blob: ecdfa3fc3336442fbd69c96c9a49ec4ab47d16a7 [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
Aurimas Liutikas67e2ae82016-10-11 18:17:42 -070019import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
20
Chet Haase21cd1382010-09-01 17:42:29 -070021import android.animation.LayoutTransition;
Chris Craik9de95db2017-01-18 17:59:23 -080022import android.annotation.CallSuper;
Tor Norbye7b9c9122013-05-30 16:48:33 -070023import android.annotation.IdRes;
Alan Viverette922e1c62015-05-05 17:18:27 -070024import android.annotation.NonNull;
Evan Rosky3ac64632017-02-13 18:04:43 -080025import android.annotation.TestApi;
Tor Norbye83c68962015-03-10 20:55:31 -070026import android.annotation.UiThread;
Vadim Trysheva61efa42016-09-28 15:15:52 -070027import android.content.ClipData;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028import android.content.Context;
Clara Bayarrid5bf3ed2015-03-27 17:32:45 +000029import android.content.Intent;
Adam Powellff0d2982014-07-10 20:34:14 -070030import android.content.pm.PackageManager;
Dianne Hackborne36d6e22010-02-17 19:46:25 -080031import android.content.res.Configuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032import android.content.res.TypedArray;
33import android.graphics.Bitmap;
34import android.graphics.Canvas;
Philip Milne10ca24a2012-04-23 15:38:27 -070035import android.graphics.Color;
36import android.graphics.Insets;
Adam Powell6e346362010-07-23 10:18:23 -070037import android.graphics.Matrix;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038import android.graphics.Paint;
Christopher Tatea53146c2010-09-07 11:57:52 -070039import android.graphics.PointF;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040import android.graphics.Rect;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041import android.graphics.RectF;
svetoslavganov75986cf2009-05-14 22:28:01 -070042import android.graphics.Region;
Jeff Brown995e7742010-12-22 16:59:36 -080043import android.os.Build;
Adam Powellb6ab0982015-01-07 17:00:12 -080044import android.os.Bundle;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045import android.os.Parcelable;
46import android.os.SystemClock;
47import android.util.AttributeSet;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048import android.util.Log;
Svet Ganov2f8fb1f2017-03-13 00:21:04 -070049import android.util.Pools;
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -080050import android.util.Pools.SynchronizedPool;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051import android.util.SparseArray;
Dianne Hackborn6ff55fc2015-08-05 18:07:31 -070052import android.util.SparseBooleanArray;
svetoslavganov75986cf2009-05-14 22:28:01 -070053import android.view.accessibility.AccessibilityEvent;
Phil Weaver4d3eec412016-09-01 16:28:34 -070054import android.view.accessibility.AccessibilityManager;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070055import android.view.accessibility.AccessibilityNodeInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056import android.view.animation.Animation;
57import android.view.animation.AnimationUtils;
58import android.view.animation.LayoutAnimationController;
59import android.view.animation.Transformation;
Chet Haasecb3d0232017-05-24 18:27:14 -070060
Romain Guy0211a0a2011-02-14 16:34:59 -080061import com.android.internal.R;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062
63import java.util.ArrayList;
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -080064import java.util.Collection;
Svetoslav Ganov42138042012-03-20 11:51:39 -070065import java.util.Collections;
Christopher Tate86cab1b2011-01-13 20:28:55 -080066import java.util.HashSet;
George Mounte1803372014-02-26 19:00:52 +000067import java.util.List;
68import java.util.Map;
Paul Duffinca4964c2017-02-07 15:04:10 +000069import java.util.function.Predicate;
Keisuke Kuroyanagid85bc502016-01-21 14:50:38 +090070
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080071/**
72 * <p>
73 * A <code>ViewGroup</code> is a special view that can contain other views
74 * (called children.) The view group is the base class for layouts and views
75 * containers. This class also defines the
76 * {@link android.view.ViewGroup.LayoutParams} class which serves as the base
77 * class for layouts parameters.
78 * </p>
79 *
80 * <p>
81 * Also see {@link LayoutParams} for layout attributes.
82 * </p>
Romain Guyd6a463a2009-05-21 23:10:10 -070083 *
Joe Fernandez558459f2011-10-13 16:47:36 -070084 * <div class="special reference">
85 * <h3>Developer Guides</h3>
86 * <p>For more information about creating user interface layouts, read the
87 * <a href="{@docRoot}guide/topics/ui/declaring-layout.html">XML Layouts</a> developer
88 * guide.</p></div>
89 *
Dianne Hackborn7caab0f2013-03-06 13:47:04 -080090 * <p>Here is a complete implementation of a custom ViewGroup that implements
91 * a simple {@link android.widget.FrameLayout} along with the ability to stack
92 * children in left and right gutters.</p>
93 *
94 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/CustomLayout.java
95 * Complete}
96 *
97 * <p>If you are implementing XML layout attributes as shown in the example, this is the
98 * corresponding definition for them that would go in <code>res/values/attrs.xml</code>:</p>
99 *
100 * {@sample development/samples/ApiDemos/res/values/attrs.xml CustomLayout}
101 *
102 * <p>Finally the layout manager can be used in an XML layout like so:</p>
103 *
104 * {@sample development/samples/ApiDemos/res/layout/custom_layout.xml Complete}
105 *
Romain Guyd6a463a2009-05-21 23:10:10 -0700106 * @attr ref android.R.styleable#ViewGroup_clipChildren
107 * @attr ref android.R.styleable#ViewGroup_clipToPadding
108 * @attr ref android.R.styleable#ViewGroup_layoutAnimation
109 * @attr ref android.R.styleable#ViewGroup_animationCache
110 * @attr ref android.R.styleable#ViewGroup_persistentDrawingCache
111 * @attr ref android.R.styleable#ViewGroup_alwaysDrawnWithCache
112 * @attr ref android.R.styleable#ViewGroup_addStatesFromChildren
113 * @attr ref android.R.styleable#ViewGroup_descendantFocusability
Chet Haase13cc1202010-09-03 15:39:20 -0700114 * @attr ref android.R.styleable#ViewGroup_animateLayoutChanges
Scott Main27a85082013-06-10 10:39:48 -0700115 * @attr ref android.R.styleable#ViewGroup_splitMotionEvents
116 * @attr ref android.R.styleable#ViewGroup_layoutMode
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800117 */
Tor Norbye83c68962015-03-10 20:55:31 -0700118@UiThread
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800119public abstract class ViewGroup extends View implements ViewParent, ViewManager {
Adam Powell539ee872012-02-03 19:00:49 -0800120 private static final String TAG = "ViewGroup";
Chet Haase21cd1382010-09-01 17:42:29 -0700121
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800122 private static final boolean DBG = false;
Gilles Debunnecea45132011-11-24 02:19:27 +0100123
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800124 /**
125 * Views which have been hidden or removed which need to be animated on
126 * their way out.
127 * This field should be made private, so it is hidden from the SDK.
128 * {@hide}
129 */
130 protected ArrayList<View> mDisappearingChildren;
131
132 /**
133 * Listener used to propagate events indicating when children are added
134 * and/or removed from a view group.
135 * This field should be made private, so it is hidden from the SDK.
136 * {@hide}
137 */
138 protected OnHierarchyChangeListener mOnHierarchyChangeListener;
139
140 // The view contained within this ViewGroup that has or contains focus.
141 private View mFocused;
Vadim Tryshev5ca73982017-01-04 17:24:43 -0800142 // The view contained within this ViewGroup (excluding nested keyboard navigation clusters)
143 // that is or contains a default-focus view.
144 private View mDefaultFocus;
Evan Rosky53fcf112017-01-26 14:37:55 -0800145 // The last child of this ViewGroup which held focus within the current cluster
Evan Rosky6c286be2017-04-19 17:23:32 -0700146 View mFocusedInCluster;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800147
Chet Haase48460322010-06-11 14:22:25 -0700148 /**
149 * A Transformation used when drawing children, to
150 * apply on the child being drawn.
151 */
Romain Guyf6991302013-06-05 17:19:01 -0700152 private Transformation mChildTransformation;
Chet Haase48460322010-06-11 14:22:25 -0700153
154 /**
155 * Used to track the current invalidation region.
156 */
Chet Haase64a48c12012-02-13 16:33:29 -0800157 RectF mInvalidateRegion;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800158
Chet Haase48460322010-06-11 14:22:25 -0700159 /**
160 * A Transformation used to calculate a correct
161 * invalidation area when the application is autoscaled.
162 */
Chet Haase64a48c12012-02-13 16:33:29 -0800163 Transformation mInvalidationTransformation;
Chet Haase48460322010-06-11 14:22:25 -0700164
Vadim Tryshevef128112016-09-16 14:05:53 -0700165 // Current frontmost child that can accept drag and lies under the drag location.
166 // Used only to generate ENTER/EXIT events for pre-Nougat aps.
167 private View mCurrentDragChild;
168
Christopher Tate86cab1b2011-01-13 20:28:55 -0800169 // Metadata about the ongoing drag
Vadim Tryshev1a68dc92015-07-20 17:01:50 -0700170 private DragEvent mCurrentDragStartEvent;
171 private boolean mIsInterestedInDrag;
172 private HashSet<View> mChildrenInterestedInDrag;
Christopher Tatea53146c2010-09-07 11:57:52 -0700173
174 // Used during drag dispatch
Romain Guy6410c0a2013-06-17 11:21:58 -0700175 private PointF mLocalPoint;
Christopher Tatea53146c2010-09-07 11:57:52 -0700176
Alan Viveretteb942b6f2014-12-08 10:37:39 -0800177 // Lazily-created holder for point computations.
178 private float[] mTempPoint;
179
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800180 // Layout animation
181 private LayoutAnimationController mLayoutAnimationController;
182 private Animation.AnimationListener mAnimationListener;
183
Jeff Brown20e987b2010-08-23 12:01:02 -0700184 // First touch target in the linked list of touch targets.
185 private TouchTarget mFirstTouchTarget;
186
Joe Onorato03ab0c72011-01-06 15:46:27 -0800187 // For debugging only. You can see these in hierarchyviewer.
Romain Guye95003e2011-01-09 13:53:06 -0800188 @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
Joe Onorato03ab0c72011-01-06 15:46:27 -0800189 @ViewDebug.ExportedProperty(category = "events")
190 private long mLastTouchDownTime;
191 @ViewDebug.ExportedProperty(category = "events")
192 private int mLastTouchDownIndex = -1;
Romain Guye95003e2011-01-09 13:53:06 -0800193 @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
Joe Onorato03ab0c72011-01-06 15:46:27 -0800194 @ViewDebug.ExportedProperty(category = "events")
195 private float mLastTouchDownX;
Romain Guye95003e2011-01-09 13:53:06 -0800196 @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
Joe Onorato03ab0c72011-01-06 15:46:27 -0800197 @ViewDebug.ExportedProperty(category = "events")
198 private float mLastTouchDownY;
199
Jeff Brown87b7f802011-06-21 18:35:45 -0700200 // First hover target in the linked list of hover targets.
201 // The hover targets are children which have received ACTION_HOVER_ENTER.
202 // They might not have actually handled the hover event, but we will
203 // continue sending hover events to them as long as the pointer remains over
204 // their bounds and the view group does not intercept hover.
205 private HoverTarget mFirstHoverTarget;
Jeff Browna032cc02011-03-07 16:56:21 -0800206
Jeff Brown10b62902011-06-20 16:40:37 -0700207 // True if the view group itself received a hover event.
208 // It might not have actually handled the hover event.
209 private boolean mHoveredSelf;
210
Vladislav Kaznacheevf847ee32016-11-21 14:11:00 -0800211 // The child capable of showing a tooltip and currently under the pointer.
212 private View mTooltipHoverTarget;
213
214 // True if the view group is capable of showing a tooltip and the pointer is directly
215 // over the view group but not one of its child views.
216 private boolean mTooltipHoveredSelf;
217
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800218 /**
219 * Internal flags.
Romain Guy8506ab42009-06-11 17:35:47 -0700220 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800221 * This field should be made private, so it is hidden from the SDK.
222 * {@hide}
223 */
Romain Guy2440e672012-08-07 14:43:43 -0700224 @ViewDebug.ExportedProperty(flagMapping = {
225 @ViewDebug.FlagToString(mask = FLAG_CLIP_CHILDREN, equals = FLAG_CLIP_CHILDREN,
226 name = "CLIP_CHILDREN"),
227 @ViewDebug.FlagToString(mask = FLAG_CLIP_TO_PADDING, equals = FLAG_CLIP_TO_PADDING,
228 name = "CLIP_TO_PADDING"),
229 @ViewDebug.FlagToString(mask = FLAG_PADDING_NOT_NULL, equals = FLAG_PADDING_NOT_NULL,
230 name = "PADDING_NOT_NULL")
Jon Miranda4597e982014-07-29 07:25:49 -0700231 }, formatToHexString = true)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800232 protected int mGroupFlags;
233
Philip Milne7b757812012-09-19 18:13:44 -0700234 /**
235 * Either {@link #LAYOUT_MODE_CLIP_BOUNDS} or {@link #LAYOUT_MODE_OPTICAL_BOUNDS}.
Philip Milne1557fd72012-04-04 23:41:34 -0700236 */
Philip Milnecfb631b2012-10-26 10:51:46 -0700237 private int mLayoutMode = LAYOUT_MODE_UNDEFINED;
Philip Milne1557fd72012-04-04 23:41:34 -0700238
Romain Guy33f6beb2012-02-16 19:24:51 -0800239 /**
240 * NOTE: If you change the flags below make sure to reflect the changes
241 * the DisplayList class
242 */
Filip Gruszczynskia33bdf32015-11-19 18:22:16 -0800243
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800244 // When set, ViewGroup invalidates only the child's rectangle
245 // Set by default
Chet Haase64a48c12012-02-13 16:33:29 -0800246 static final int FLAG_CLIP_CHILDREN = 0x1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800247
248 // When set, ViewGroup excludes the padding area from the invalidate rectangle
249 // Set by default
250 private static final int FLAG_CLIP_TO_PADDING = 0x2;
251
252 // When set, dispatchDraw() will invoke invalidate(); this is set by drawChild() when
253 // a child needs to be invalidated and FLAG_OPTIMIZE_INVALIDATE is set
Chet Haase64a48c12012-02-13 16:33:29 -0800254 static final int FLAG_INVALIDATE_REQUIRED = 0x4;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800255
256 // When set, dispatchDraw() will run the layout animation and unset the flag
257 private static final int FLAG_RUN_ANIMATION = 0x8;
258
259 // When set, there is either no layout animation on the ViewGroup or the layout
260 // animation is over
261 // Set by default
Chet Haase64a48c12012-02-13 16:33:29 -0800262 static final int FLAG_ANIMATION_DONE = 0x10;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800263
264 // If set, this ViewGroup has padding; if unset there is no padding and we don't need
265 // to clip it, even if FLAG_CLIP_TO_PADDING is set
266 private static final int FLAG_PADDING_NOT_NULL = 0x20;
267
Chris Craik5a6bbae2015-04-10 17:41:34 -0700268 /** @deprecated - functionality removed */
Aurimas Liutikas514c5ef2016-05-24 15:22:55 -0700269 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800270 private static final int FLAG_ANIMATION_CACHE = 0x40;
271
272 // When set, this ViewGroup converts calls to invalidate(Rect) to invalidate() during a
273 // layout animation; this avoid clobbering the hierarchy
274 // Automatically set when the layout animation starts, depending on the animation's
275 // characteristics
Chet Haase64a48c12012-02-13 16:33:29 -0800276 static final int FLAG_OPTIMIZE_INVALIDATE = 0x80;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800277
278 // When set, the next call to drawChild() will clear mChildTransformation's matrix
Chet Haase64a48c12012-02-13 16:33:29 -0800279 static final int FLAG_CLEAR_TRANSFORMATION = 0x100;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800280
281 // When set, this ViewGroup invokes mAnimationListener.onAnimationEnd() and removes
282 // the children's Bitmap caches if necessary
283 // This flag is set when the layout animation is over (after FLAG_ANIMATION_DONE is set)
284 private static final int FLAG_NOTIFY_ANIMATION_LISTENER = 0x200;
285
286 /**
287 * When set, the drawing method will call {@link #getChildDrawingOrder(int, int)}
288 * to get the index of the child to draw for that iteration.
Filip Gruszczynskia33bdf32015-11-19 18:22:16 -0800289 *
Romain Guy293451e2009-11-04 13:59:48 -0800290 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800291 */
292 protected static final int FLAG_USE_CHILD_DRAWING_ORDER = 0x400;
Romain Guy8506ab42009-06-11 17:35:47 -0700293
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800294 /**
295 * When set, this ViewGroup supports static transformations on children; this causes
296 * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} to be
297 * invoked when a child is drawn.
298 *
299 * Any subclass overriding
300 * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} should
301 * set this flags in {@link #mGroupFlags}.
Romain Guy8506ab42009-06-11 17:35:47 -0700302 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800303 * {@hide}
304 */
305 protected static final int FLAG_SUPPORT_STATIC_TRANSFORMATIONS = 0x800;
306
John Reckfb5899d2014-08-15 18:51:27 -0700307 // UNUSED FLAG VALUE: 0x1000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800308
309 /**
310 * When set, this ViewGroup's drawable states also include those
311 * of its children.
312 */
313 private static final int FLAG_ADD_STATES_FROM_CHILDREN = 0x2000;
314
Chris Craik5a6bbae2015-04-10 17:41:34 -0700315 /** @deprecated functionality removed */
Aurimas Liutikas514c5ef2016-05-24 15:22:55 -0700316 @Deprecated
Chris Craik5a6bbae2015-04-10 17:41:34 -0700317 private static final int FLAG_ALWAYS_DRAWN_WITH_CACHE = 0x4000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800318
Chris Craik5a6bbae2015-04-10 17:41:34 -0700319 /** @deprecated functionality removed */
Aurimas Liutikas514c5ef2016-05-24 15:22:55 -0700320 @Deprecated
Chris Craik5a6bbae2015-04-10 17:41:34 -0700321 private static final int FLAG_CHILDREN_DRAWN_WITH_CACHE = 0x8000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800322
323 /**
324 * When set, this group will go through its list of children to notify them of
325 * any drawable state change.
326 */
327 private static final int FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE = 0x10000;
328
329 private static final int FLAG_MASK_FOCUSABILITY = 0x60000;
330
331 /**
332 * This view will get focus before any of its descendants.
333 */
334 public static final int FOCUS_BEFORE_DESCENDANTS = 0x20000;
335
336 /**
337 * This view will get focus only if none of its descendants want it.
338 */
339 public static final int FOCUS_AFTER_DESCENDANTS = 0x40000;
340
341 /**
342 * This view will block any of its descendants from getting focus, even
343 * if they are focusable.
344 */
345 public static final int FOCUS_BLOCK_DESCENDANTS = 0x60000;
346
347 /**
348 * Used to map between enum in attrubutes and flag values.
349 */
350 private static final int[] DESCENDANT_FOCUSABILITY_FLAGS =
351 {FOCUS_BEFORE_DESCENDANTS, FOCUS_AFTER_DESCENDANTS,
352 FOCUS_BLOCK_DESCENDANTS};
353
354 /**
355 * When set, this ViewGroup should not intercept touch events.
Adam Powell110486f2010-06-22 17:14:44 -0700356 * {@hide}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800357 */
Adam Powell110486f2010-06-22 17:14:44 -0700358 protected static final int FLAG_DISALLOW_INTERCEPT = 0x80000;
Romain Guy8506ab42009-06-11 17:35:47 -0700359
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800360 /**
Adam Powell2b342f02010-08-18 18:14:13 -0700361 * When set, this ViewGroup will split MotionEvents to multiple child Views when appropriate.
362 */
Adam Powellf37df072010-09-17 16:22:49 -0700363 private static final int FLAG_SPLIT_MOTION_EVENTS = 0x200000;
Adam Powell2b342f02010-08-18 18:14:13 -0700364
365 /**
Adam Powell4b867882011-09-16 12:59:46 -0700366 * When set, this ViewGroup will not dispatch onAttachedToWindow calls
367 * to children when adding new views. This is used to prevent multiple
368 * onAttached calls when a ViewGroup adds children in its own onAttached method.
369 */
370 private static final int FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW = 0x400000;
371
372 /**
Philip Milnecfb631b2012-10-26 10:51:46 -0700373 * When true, indicates that a layoutMode has been explicitly set, either with
374 * an explicit call to {@link #setLayoutMode(int)} in code or from an XML resource.
375 * This distinguishes the situation in which a layout mode was inherited from
376 * one of the ViewGroup's ancestors and cached locally.
377 */
378 private static final int FLAG_LAYOUT_MODE_WAS_EXPLICITLY_SET = 0x800000;
379
Chris Craikb49f4462014-03-20 12:44:20 -0700380 static final int FLAG_IS_TRANSITION_GROUP = 0x1000000;
Chris Craikd863a102013-12-19 13:31:15 -0800381
Chris Craikb49f4462014-03-20 12:44:20 -0700382 static final int FLAG_IS_TRANSITION_GROUP_SET = 0x2000000;
George Mount0a778ed2013-12-13 13:35:36 -0800383
Chris Craikd863a102013-12-19 13:31:15 -0800384 /**
Adam Powellff0d2982014-07-10 20:34:14 -0700385 * When set, focus will not be permitted to enter this group if a touchscreen is present.
386 */
387 static final int FLAG_TOUCHSCREEN_BLOCKS_FOCUS = 0x4000000;
388
389 /**
Clara Bayarri4423d912015-03-02 19:42:48 +0000390 * When true, indicates that a call to startActionModeForChild was made with the type parameter
391 * and should not be ignored. This helps in backwards compatibility with the existing method
392 * without a type.
393 *
394 * @see #startActionModeForChild(View, android.view.ActionMode.Callback)
395 * @see #startActionModeForChild(View, android.view.ActionMode.Callback, int)
396 */
397 private static final int FLAG_START_ACTION_MODE_FOR_CHILD_IS_TYPED = 0x8000000;
398
399 /**
400 * When true, indicates that a call to startActionModeForChild was made without the type
401 * parameter. This helps in backwards compatibility with the existing method
402 * without a type.
403 *
404 * @see #startActionModeForChild(View, android.view.ActionMode.Callback)
405 * @see #startActionModeForChild(View, android.view.ActionMode.Callback, int)
406 */
407 private static final int FLAG_START_ACTION_MODE_FOR_CHILD_IS_NOT_TYPED = 0x10000000;
408
409 /**
Adam Powell2af189a2016-02-05 15:52:02 -0800410 * When set, indicates that a call to showContextMenuForChild was made with explicit
411 * coordinates within the initiating child view.
412 */
413 private static final int FLAG_SHOW_CONTEXT_MENU_WITH_COORDS = 0x20000000;
414
415 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800416 * Indicates which types of drawing caches are to be kept in memory.
417 * This field should be made private, so it is hidden from the SDK.
418 * {@hide}
419 */
420 protected int mPersistentDrawingCache;
421
422 /**
423 * Used to indicate that no drawing cache should be kept in memory.
424 */
425 public static final int PERSISTENT_NO_CACHE = 0x0;
426
427 /**
428 * Used to indicate that the animation drawing cache should be kept in memory.
429 */
430 public static final int PERSISTENT_ANIMATION_CACHE = 0x1;
431
432 /**
433 * Used to indicate that the scrolling drawing cache should be kept in memory.
434 */
435 public static final int PERSISTENT_SCROLLING_CACHE = 0x2;
436
437 /**
438 * Used to indicate that all drawing caches should be kept in memory.
439 */
440 public static final int PERSISTENT_ALL_CACHES = 0x3;
441
Philip Milne1557fd72012-04-04 23:41:34 -0700442 // Layout Modes
443
Philip Milnecfb631b2012-10-26 10:51:46 -0700444 private static final int LAYOUT_MODE_UNDEFINED = -1;
445
Philip Milne1557fd72012-04-04 23:41:34 -0700446 /**
447 * This constant is a {@link #setLayoutMode(int) layoutMode}.
Philip Milne7a23b492012-04-24 22:12:36 -0700448 * Clip bounds are the raw values of {@link #getLeft() left}, {@link #getTop() top},
Philip Milne1557fd72012-04-04 23:41:34 -0700449 * {@link #getRight() right} and {@link #getBottom() bottom}.
450 */
Philip Milne7b757812012-09-19 18:13:44 -0700451 public static final int LAYOUT_MODE_CLIP_BOUNDS = 0;
Philip Milne1557fd72012-04-04 23:41:34 -0700452
453 /**
454 * This constant is a {@link #setLayoutMode(int) layoutMode}.
Philip Milne7a23b492012-04-24 22:12:36 -0700455 * Optical bounds describe where a widget appears to be. They sit inside the clip
456 * bounds which need to cover a larger area to allow other effects,
457 * such as shadows and glows, to be drawn.
Philip Milne1557fd72012-04-04 23:41:34 -0700458 */
Philip Milne7b757812012-09-19 18:13:44 -0700459 public static final int LAYOUT_MODE_OPTICAL_BOUNDS = 1;
460
461 /** @hide */
Philip Milnecfb631b2012-10-26 10:51:46 -0700462 public static int LAYOUT_MODE_DEFAULT = LAYOUT_MODE_CLIP_BOUNDS;
Philip Milne1557fd72012-04-04 23:41:34 -0700463
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800464 /**
465 * We clip to padding when FLAG_CLIP_TO_PADDING and FLAG_PADDING_NOT_NULL
466 * are set at the same time.
467 */
468 protected static final int CLIP_TO_PADDING_MASK = FLAG_CLIP_TO_PADDING | FLAG_PADDING_NOT_NULL;
469
470 // Index of the child's left position in the mLocation array
471 private static final int CHILD_LEFT_INDEX = 0;
472 // Index of the child's top position in the mLocation array
473 private static final int CHILD_TOP_INDEX = 1;
474
475 // Child views of this ViewGroup
476 private View[] mChildren;
477 // Number of valid children in the mChildren array, the rest should be null or not
478 // considered as children
479 private int mChildrenCount;
480
Chet Haaseb9895022013-04-02 15:10:58 -0700481 // Whether layout calls are currently being suppressed, controlled by calls to
482 // suppressLayout()
483 boolean mSuppressLayout = false;
484
485 // Whether any layout calls have actually been suppressed while mSuppressLayout
486 // has been true. This tracks whether we need to issue a requestLayout() when
487 // layout is later re-enabled.
488 private boolean mLayoutCalledWhileSuppressed = false;
489
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800490 private static final int ARRAY_INITIAL_CAPACITY = 12;
491 private static final int ARRAY_CAPACITY_INCREMENT = 12;
492
Romain Guycbc67742012-04-27 16:12:57 -0700493 private static float[] sDebugLines;
Philip Milne604f4402012-04-24 19:27:11 -0700494
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800495 // Used to draw cached views
Chet Haase64a48c12012-02-13 16:33:29 -0800496 Paint mCachePaint;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800497
Chet Haase21cd1382010-09-01 17:42:29 -0700498 // Used to animate add/remove changes in layout
499 private LayoutTransition mTransition;
500
501 // The set of views that are currently being transitioned. This list is used to track views
502 // being removed that should not actually be removed from the parent yet because they are
503 // being animated.
504 private ArrayList<View> mTransitioningViews;
505
Chet Haase5e25c2c2010-09-16 11:15:56 -0700506 // List of children changing visibility. This is used to potentially keep rendering
507 // views during a transition when they otherwise would have become gone/invisible
508 private ArrayList<View> mVisibilityChangingChildren;
509
Chris Craikab008f02014-05-23 17:55:03 -0700510 // Temporary holder of presorted children, only used for
511 // input/software draw dispatch for correctly Z ordering.
512 private ArrayList<View> mPreSortedChildren;
513
Adam Powell539ee872012-02-03 19:00:49 -0800514 // Indicates how many of this container's child subtrees contain transient state
515 @ViewDebug.ExportedProperty(category = "layout")
516 private int mChildCountWithTransientState = 0;
517
Adam Powell10ba2772014-04-15 09:46:51 -0700518 /**
519 * Currently registered axes for nested scrolling. Flag set consisting of
520 * {@link #SCROLL_AXIS_HORIZONTAL} {@link #SCROLL_AXIS_VERTICAL} or {@link #SCROLL_AXIS_NONE}
521 * for null.
522 */
523 private int mNestedScrollAxes;
524
Chet Haasec633d2f2015-04-07 10:29:39 -0700525 // Used to manage the list of transient views, added by addTransientView()
526 private List<Integer> mTransientIndices = null;
527 private List<View> mTransientViews = null;
528
529
Clara Bayarri4423d912015-03-02 19:42:48 +0000530 /**
531 * Empty ActionMode used as a sentinel in recursive entries to startActionModeForChild.
532 *
533 * @see #startActionModeForChild(View, android.view.ActionMode.Callback)
534 * @see #startActionModeForChild(View, android.view.ActionMode.Callback, int)
535 */
536 private static final ActionMode SENTINEL_ACTION_MODE = new ActionMode() {
537 @Override
538 public void setTitle(CharSequence title) {}
539
540 @Override
541 public void setTitle(int resId) {}
542
543 @Override
544 public void setSubtitle(CharSequence subtitle) {}
545
546 @Override
547 public void setSubtitle(int resId) {}
548
549 @Override
550 public void setCustomView(View view) {}
551
552 @Override
553 public void invalidate() {}
554
555 @Override
556 public void finish() {}
557
558 @Override
559 public Menu getMenu() {
560 return null;
561 }
562
563 @Override
564 public CharSequence getTitle() {
565 return null;
566 }
567
568 @Override
569 public CharSequence getSubtitle() {
570 return null;
571 }
572
573 @Override
574 public View getCustomView() {
575 return null;
576 }
577
578 @Override
579 public MenuInflater getMenuInflater() {
580 return null;
581 }
582 };
583
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800584 public ViewGroup(Context context) {
Alan Viveretted6479ec2013-09-10 17:03:02 -0700585 this(context, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800586 }
587
588 public ViewGroup(Context context, AttributeSet attrs) {
Alan Viveretted6479ec2013-09-10 17:03:02 -0700589 this(context, attrs, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800590 }
591
Alan Viverette617feb92013-09-09 18:09:13 -0700592 public ViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {
Alan Viveretted6479ec2013-09-10 17:03:02 -0700593 this(context, attrs, defStyleAttr, 0);
Alan Viverette617feb92013-09-09 18:09:13 -0700594 }
595
596 public ViewGroup(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
597 super(context, attrs, defStyleAttr, defStyleRes);
Felipe Lemed04a6972017-03-02 12:56:18 -0800598
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800599 initViewGroup();
Alan Viveretted6479ec2013-09-10 17:03:02 -0700600 initFromAttributes(context, attrs, defStyleAttr, defStyleRes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800601 }
602
603 private void initViewGroup() {
604 // ViewGroup doesn't draw by default
Philip Milne10ca24a2012-04-23 15:38:27 -0700605 if (!debugDraw()) {
606 setFlags(WILL_NOT_DRAW, DRAW_MASK);
607 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800608 mGroupFlags |= FLAG_CLIP_CHILDREN;
609 mGroupFlags |= FLAG_CLIP_TO_PADDING;
610 mGroupFlags |= FLAG_ANIMATION_DONE;
Chris Craikf6ce8fd2015-05-11 15:33:11 -0700611 mGroupFlags |= FLAG_ANIMATION_CACHE;
612 mGroupFlags |= FLAG_ALWAYS_DRAWN_WITH_CACHE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800613
Jeff Brown995e7742010-12-22 16:59:36 -0800614 if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB) {
615 mGroupFlags |= FLAG_SPLIT_MOTION_EVENTS;
616 }
617
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800618 setDescendantFocusability(FOCUS_BEFORE_DESCENDANTS);
619
620 mChildren = new View[ARRAY_INITIAL_CAPACITY];
621 mChildrenCount = 0;
622
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800623 mPersistentDrawingCache = PERSISTENT_SCROLLING_CACHE;
624 }
625
Alan Viveretted6479ec2013-09-10 17:03:02 -0700626 private void initFromAttributes(
627 Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
Filip Gruszczyńskib50cea02014-03-05 17:54:58 -0800628 final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ViewGroup, defStyleAttr,
629 defStyleRes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800630
631 final int N = a.getIndexCount();
632 for (int i = 0; i < N; i++) {
633 int attr = a.getIndex(i);
634 switch (attr) {
635 case R.styleable.ViewGroup_clipChildren:
636 setClipChildren(a.getBoolean(attr, true));
637 break;
638 case R.styleable.ViewGroup_clipToPadding:
639 setClipToPadding(a.getBoolean(attr, true));
640 break;
641 case R.styleable.ViewGroup_animationCache:
642 setAnimationCacheEnabled(a.getBoolean(attr, true));
643 break;
644 case R.styleable.ViewGroup_persistentDrawingCache:
645 setPersistentDrawingCache(a.getInt(attr, PERSISTENT_SCROLLING_CACHE));
646 break;
647 case R.styleable.ViewGroup_addStatesFromChildren:
648 setAddStatesFromChildren(a.getBoolean(attr, false));
649 break;
650 case R.styleable.ViewGroup_alwaysDrawnWithCache:
651 setAlwaysDrawnWithCacheEnabled(a.getBoolean(attr, true));
652 break;
653 case R.styleable.ViewGroup_layoutAnimation:
654 int id = a.getResourceId(attr, -1);
655 if (id > 0) {
656 setLayoutAnimation(AnimationUtils.loadLayoutAnimation(mContext, id));
657 }
658 break;
659 case R.styleable.ViewGroup_descendantFocusability:
660 setDescendantFocusability(DESCENDANT_FOCUSABILITY_FLAGS[a.getInt(attr, 0)]);
661 break;
Adam Powell2b342f02010-08-18 18:14:13 -0700662 case R.styleable.ViewGroup_splitMotionEvents:
663 setMotionEventSplittingEnabled(a.getBoolean(attr, false));
664 break;
Chet Haase13cc1202010-09-03 15:39:20 -0700665 case R.styleable.ViewGroup_animateLayoutChanges:
666 boolean animateLayoutChanges = a.getBoolean(attr, false);
667 if (animateLayoutChanges) {
668 setLayoutTransition(new LayoutTransition());
669 }
670 break;
Philip Milne7b757812012-09-19 18:13:44 -0700671 case R.styleable.ViewGroup_layoutMode:
Philip Milnecfb631b2012-10-26 10:51:46 -0700672 setLayoutMode(a.getInt(attr, LAYOUT_MODE_UNDEFINED));
Philip Milne7b757812012-09-19 18:13:44 -0700673 break;
George Mount0a778ed2013-12-13 13:35:36 -0800674 case R.styleable.ViewGroup_transitionGroup:
675 setTransitionGroup(a.getBoolean(attr, false));
676 break;
Adam Powellff0d2982014-07-10 20:34:14 -0700677 case R.styleable.ViewGroup_touchscreenBlocksFocus:
678 setTouchscreenBlocksFocus(a.getBoolean(attr, false));
679 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800680 }
681 }
682
683 a.recycle();
684 }
685
686 /**
687 * Gets the descendant focusability of this view group. The descendant
688 * focusability defines the relationship between this view group and its
689 * descendants when looking for a view to take focus in
690 * {@link #requestFocus(int, android.graphics.Rect)}.
691 *
692 * @return one of {@link #FOCUS_BEFORE_DESCENDANTS}, {@link #FOCUS_AFTER_DESCENDANTS},
693 * {@link #FOCUS_BLOCK_DESCENDANTS}.
694 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -0700695 @ViewDebug.ExportedProperty(category = "focus", mapping = {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800696 @ViewDebug.IntToString(from = FOCUS_BEFORE_DESCENDANTS, to = "FOCUS_BEFORE_DESCENDANTS"),
697 @ViewDebug.IntToString(from = FOCUS_AFTER_DESCENDANTS, to = "FOCUS_AFTER_DESCENDANTS"),
698 @ViewDebug.IntToString(from = FOCUS_BLOCK_DESCENDANTS, to = "FOCUS_BLOCK_DESCENDANTS")
699 })
700 public int getDescendantFocusability() {
701 return mGroupFlags & FLAG_MASK_FOCUSABILITY;
702 }
703
704 /**
705 * Set the descendant focusability of this view group. This defines the relationship
706 * between this view group and its descendants when looking for a view to
707 * take focus in {@link #requestFocus(int, android.graphics.Rect)}.
708 *
709 * @param focusability one of {@link #FOCUS_BEFORE_DESCENDANTS}, {@link #FOCUS_AFTER_DESCENDANTS},
710 * {@link #FOCUS_BLOCK_DESCENDANTS}.
711 */
712 public void setDescendantFocusability(int focusability) {
713 switch (focusability) {
714 case FOCUS_BEFORE_DESCENDANTS:
715 case FOCUS_AFTER_DESCENDANTS:
716 case FOCUS_BLOCK_DESCENDANTS:
717 break;
718 default:
719 throw new IllegalArgumentException("must be one of FOCUS_BEFORE_DESCENDANTS, "
720 + "FOCUS_AFTER_DESCENDANTS, FOCUS_BLOCK_DESCENDANTS");
721 }
722 mGroupFlags &= ~FLAG_MASK_FOCUSABILITY;
723 mGroupFlags |= (focusability & FLAG_MASK_FOCUSABILITY);
724 }
725
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800726 @Override
727 void handleFocusGainInternal(int direction, Rect previouslyFocusedRect) {
728 if (mFocused != null) {
Alan Viverette223622a2013-12-17 13:29:02 -0800729 mFocused.unFocus(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800730 mFocused = null;
Evan Rosky53fcf112017-01-26 14:37:55 -0800731 mFocusedInCluster = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800732 }
733 super.handleFocusGainInternal(direction, previouslyFocusedRect);
734 }
735
Alan Viverettebe463f22016-01-21 10:50:10 -0500736 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800737 public void requestChildFocus(View child, View focused) {
738 if (DBG) {
739 System.out.println(this + " requestChildFocus()");
740 }
741 if (getDescendantFocusability() == FOCUS_BLOCK_DESCENDANTS) {
742 return;
743 }
744
745 // Unfocus us, if necessary
Alan Viverette223622a2013-12-17 13:29:02 -0800746 super.unFocus(focused);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800747
748 // We had a previous notion of who had focus. Clear it.
749 if (mFocused != child) {
750 if (mFocused != null) {
Alan Viverette223622a2013-12-17 13:29:02 -0800751 mFocused.unFocus(focused);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800752 }
753
754 mFocused = child;
755 }
756 if (mParent != null) {
757 mParent.requestChildFocus(this, focused);
758 }
759 }
760
Vadim Tryshev5ca73982017-01-04 17:24:43 -0800761 void setDefaultFocus(View child) {
Evan Rosky53fcf112017-01-26 14:37:55 -0800762 // Stop at any higher view which is explicitly focused-by-default
763 if (mDefaultFocus != null && mDefaultFocus.isFocusedByDefault()) {
Vadim Tryshev5ca73982017-01-04 17:24:43 -0800764 return;
Vadim Tryshev01d8c492016-12-15 11:33:15 -0800765 }
Vadim Tryshev5ca73982017-01-04 17:24:43 -0800766
767 mDefaultFocus = child;
768
769 if (mParent instanceof ViewGroup) {
770 ((ViewGroup) mParent).setDefaultFocus(this);
771 }
772 }
773
774 /**
Evan Rosky53fcf112017-01-26 14:37:55 -0800775 * Clears the default-focus chain from {@param child} up to the first parent which has another
776 * default-focusable branch below it or until there is no default-focus chain.
777 *
778 * @param child
Vadim Tryshev5ca73982017-01-04 17:24:43 -0800779 */
Evan Rosky53fcf112017-01-26 14:37:55 -0800780 void clearDefaultFocus(View child) {
781 // Stop at any higher view which is explicitly focused-by-default
782 if (mDefaultFocus != child && mDefaultFocus != null
783 && mDefaultFocus.isFocusedByDefault()) {
784 return;
785 }
786
787 mDefaultFocus = null;
788
789 // Search child siblings for default focusables.
790 for (int i = 0; i < mChildrenCount; ++i) {
791 View sibling = mChildren[i];
792 if (sibling.isFocusedByDefault()) {
793 mDefaultFocus = sibling;
794 return;
795 } else if (mDefaultFocus == null && sibling.hasDefaultFocus()) {
796 mDefaultFocus = sibling;
797 }
798 }
799
800 if (mParent instanceof ViewGroup) {
801 ((ViewGroup) mParent).clearDefaultFocus(this);
802 }
803 }
804
805 @Override
806 boolean hasDefaultFocus() {
807 return mDefaultFocus != null || super.hasDefaultFocus();
808 }
809
Evan Rosky0e8a6832017-04-10 12:35:15 -0700810 /**
811 * Removes {@code child} (and associated focusedInCluster chain) from the cluster containing
812 * it.
813 * <br>
814 * This is intended to be run on {@code child}'s immediate parent. This is necessary because
815 * the chain is sometimes cleared after {@code child} has been detached.
816 */
817 void clearFocusedInCluster(View child) {
Evan Rosky53fcf112017-01-26 14:37:55 -0800818 if (mFocusedInCluster != child) {
Vadim Tryshev5ca73982017-01-04 17:24:43 -0800819 return;
820 }
Evan Rosky0e8a6832017-04-10 12:35:15 -0700821 View top = findKeyboardNavigationCluster();
822 ViewParent parent = this;
823 do {
824 ((ViewGroup) parent).mFocusedInCluster = null;
Evan Rosky6c286be2017-04-19 17:23:32 -0700825 if (parent == top) {
826 break;
827 }
Evan Rosky0e8a6832017-04-10 12:35:15 -0700828 parent = parent.getParent();
Evan Rosky6c286be2017-04-19 17:23:32 -0700829 } while (parent instanceof ViewGroup);
Vadim Tryshev5ca73982017-01-04 17:24:43 -0800830 }
831
832 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800833 public void focusableViewAvailable(View v) {
834 if (mParent != null
835 // shortcut: don't report a new focusable view if we block our descendants from
Evan Rosky2ae1bf52017-05-11 11:18:45 -0700836 // getting focus or if we're not visible
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800837 && (getDescendantFocusability() != FOCUS_BLOCK_DESCENDANTS)
Evan Rosky2ae1bf52017-05-11 11:18:45 -0700838 && ((mViewFlags & VISIBILITY_MASK) == VISIBLE)
Adam Powell88c11752014-07-21 17:19:16 -0700839 && (isFocusableInTouchMode() || !shouldBlockFocusForTouchscreen())
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800840 // shortcut: don't report a new focusable view if we already are focused
841 // (and we don't prefer our descendants)
842 //
843 // note: knowing that mFocused is non-null is not a good enough reason
844 // to break the traversal since in that case we'd actually have to find
845 // the focused view and make sure it wasn't FOCUS_AFTER_DESCENDANTS and
Joe Onoratoc6cc0f82011-04-12 11:53:13 -0700846 // an ancestor of v; this will get checked for at ViewAncestor
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800847 && !(isFocused() && getDescendantFocusability() != FOCUS_AFTER_DESCENDANTS)) {
848 mParent.focusableViewAvailable(v);
849 }
850 }
851
Alan Viverettebe463f22016-01-21 10:50:10 -0500852 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800853 public boolean showContextMenuForChild(View originalView) {
Adam Powell2af189a2016-02-05 15:52:02 -0800854 if (isShowingContextMenuWithCoords()) {
855 // We're being called for compatibility. Return false and let the version
856 // with coordinates recurse up.
857 return false;
858 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800859 return mParent != null && mParent.showContextMenuForChild(originalView);
860 }
861
Adam Powell2af189a2016-02-05 15:52:02 -0800862 /**
863 * @hide used internally for compatibility with existing app code only
864 */
865 public final boolean isShowingContextMenuWithCoords() {
866 return (mGroupFlags & FLAG_SHOW_CONTEXT_MENU_WITH_COORDS) != 0;
867 }
868
Oren Blasberged391262015-09-01 12:12:51 -0700869 @Override
870 public boolean showContextMenuForChild(View originalView, float x, float y) {
Adam Powell2af189a2016-02-05 15:52:02 -0800871 try {
872 mGroupFlags |= FLAG_SHOW_CONTEXT_MENU_WITH_COORDS;
873 if (showContextMenuForChild(originalView)) {
874 return true;
875 }
876 } finally {
877 mGroupFlags &= ~FLAG_SHOW_CONTEXT_MENU_WITH_COORDS;
878 }
Oren Blasberged391262015-09-01 12:12:51 -0700879 return mParent != null && mParent.showContextMenuForChild(originalView, x, y);
880 }
881
Clara Bayarri4423d912015-03-02 19:42:48 +0000882 @Override
Adam Powell6e346362010-07-23 10:18:23 -0700883 public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback) {
Clara Bayarri4423d912015-03-02 19:42:48 +0000884 if ((mGroupFlags & FLAG_START_ACTION_MODE_FOR_CHILD_IS_TYPED) == 0) {
885 // This is the original call.
886 try {
887 mGroupFlags |= FLAG_START_ACTION_MODE_FOR_CHILD_IS_NOT_TYPED;
888 return startActionModeForChild(originalView, callback, ActionMode.TYPE_PRIMARY);
889 } finally {
890 mGroupFlags &= ~FLAG_START_ACTION_MODE_FOR_CHILD_IS_NOT_TYPED;
891 }
892 } else {
893 // We are being called from the new method with type.
894 return SENTINEL_ACTION_MODE;
895 }
896 }
897
Clara Bayarri4423d912015-03-02 19:42:48 +0000898 @Override
899 public ActionMode startActionModeForChild(
900 View originalView, ActionMode.Callback callback, int type) {
Adam Powelle9fd6d22015-06-01 11:26:32 -0700901 if ((mGroupFlags & FLAG_START_ACTION_MODE_FOR_CHILD_IS_NOT_TYPED) == 0
902 && type == ActionMode.TYPE_PRIMARY) {
Clara Bayarri4423d912015-03-02 19:42:48 +0000903 ActionMode mode;
904 try {
905 mGroupFlags |= FLAG_START_ACTION_MODE_FOR_CHILD_IS_TYPED;
906 mode = startActionModeForChild(originalView, callback);
907 } finally {
908 mGroupFlags &= ~FLAG_START_ACTION_MODE_FOR_CHILD_IS_TYPED;
909 }
910 if (mode != SENTINEL_ACTION_MODE) {
911 return mode;
912 }
913 }
914 if (mParent != null) {
915 try {
916 return mParent.startActionModeForChild(originalView, callback, type);
917 } catch (AbstractMethodError ame) {
918 // Custom view parents might not implement this method.
919 return mParent.startActionModeForChild(originalView, callback);
920 }
921 }
922 return null;
Adam Powell6e346362010-07-23 10:18:23 -0700923 }
924
925 /**
Clara Bayarrid5bf3ed2015-03-27 17:32:45 +0000926 * @hide
927 */
928 @Override
929 public boolean dispatchActivityResult(
930 String who, int requestCode, int resultCode, Intent data) {
931 if (super.dispatchActivityResult(who, requestCode, resultCode, data)) {
932 return true;
933 }
934 int childCount = getChildCount();
935 for (int i = 0; i < childCount; i++) {
936 View child = getChildAt(i);
937 if (child.dispatchActivityResult(who, requestCode, resultCode, data)) {
938 return true;
939 }
940 }
941 return false;
942 }
943
944 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800945 * Find the nearest view in the specified direction that wants to take
946 * focus.
947 *
948 * @param focused The view that currently has focus
949 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and
950 * FOCUS_RIGHT, or 0 for not applicable.
951 */
Alan Viverettebe463f22016-01-21 10:50:10 -0500952 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800953 public View focusSearch(View focused, int direction) {
Vadim Tryshevb5ced222017-01-17 19:31:35 -0800954 if (isRootNamespace()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800955 // root namespace means we should consider ourselves the top of the
956 // tree for focus searching; otherwise we could be focus searching
Vadim Tryshev418b1fc2016-11-28 18:26:24 -0800957 // into other tabs. see LocalActivityManager and TabHost for more info.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800958 return FocusFinder.getInstance().findNextFocus(this, focused, direction);
959 } else if (mParent != null) {
960 return mParent.focusSearch(focused, direction);
961 }
962 return null;
963 }
964
Alan Viverettebe463f22016-01-21 10:50:10 -0500965 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800966 public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
967 return false;
968 }
969
Svetoslav Ganov42138042012-03-20 11:51:39 -0700970 @Override
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700971 public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event) {
Svetoslav Ganov42138042012-03-20 11:51:39 -0700972 ViewParent parent = mParent;
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700973 if (parent == null) {
974 return false;
975 }
976 final boolean propagate = onRequestSendAccessibilityEvent(child, event);
977 if (!propagate) {
978 return false;
979 }
980 return parent.requestSendAccessibilityEvent(this, event);
981 }
982
983 /**
984 * Called when a child has requested sending an {@link AccessibilityEvent} and
985 * gives an opportunity to its parent to augment the event.
Svetoslav Ganov031d9c12011-09-09 16:41:13 -0700986 * <p>
Adam Powell2fcbbd02011-09-28 18:56:43 -0700987 * If an {@link android.view.View.AccessibilityDelegate} has been specified via calling
988 * {@link android.view.View#setAccessibilityDelegate(android.view.View.AccessibilityDelegate)} its
989 * {@link android.view.View.AccessibilityDelegate#onRequestSendAccessibilityEvent(ViewGroup, View, AccessibilityEvent)}
Svetoslav Ganov031d9c12011-09-09 16:41:13 -0700990 * is responsible for handling this call.
991 * </p>
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700992 *
993 * @param child The child which requests sending the event.
994 * @param event The event to be sent.
995 * @return True if the event should be sent.
996 *
997 * @see #requestSendAccessibilityEvent(View, AccessibilityEvent)
998 */
999 public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
Svetoslav Ganov031d9c12011-09-09 16:41:13 -07001000 if (mAccessibilityDelegate != null) {
1001 return mAccessibilityDelegate.onRequestSendAccessibilityEvent(this, child, event);
1002 } else {
1003 return onRequestSendAccessibilityEventInternal(child, event);
1004 }
1005 }
1006
1007 /**
1008 * @see #onRequestSendAccessibilityEvent(View, AccessibilityEvent)
1009 *
1010 * Note: Called from the default {@link View.AccessibilityDelegate}.
Alan Viverettea54956a2015-01-07 16:05:02 -08001011 *
1012 * @hide
Svetoslav Ganov031d9c12011-09-09 16:41:13 -07001013 */
Alan Viverettea54956a2015-01-07 16:05:02 -08001014 public boolean onRequestSendAccessibilityEventInternal(View child, AccessibilityEvent event) {
Svetoslav Ganov736c2752011-04-22 18:30:36 -07001015 return true;
1016 }
1017
1018 /**
Adam Powell539ee872012-02-03 19:00:49 -08001019 * Called when a child view has changed whether or not it is tracking transient state.
Adam Powell539ee872012-02-03 19:00:49 -08001020 */
Alan Viverettebe463f22016-01-21 10:50:10 -05001021 @Override
Adam Powell539ee872012-02-03 19:00:49 -08001022 public void childHasTransientStateChanged(View child, boolean childHasTransientState) {
1023 final boolean oldHasTransientState = hasTransientState();
1024 if (childHasTransientState) {
1025 mChildCountWithTransientState++;
1026 } else {
1027 mChildCountWithTransientState--;
1028 }
1029
1030 final boolean newHasTransientState = hasTransientState();
1031 if (mParent != null && oldHasTransientState != newHasTransientState) {
1032 try {
1033 mParent.childHasTransientStateChanged(this, newHasTransientState);
1034 } catch (AbstractMethodError e) {
1035 Log.e(TAG, mParent.getClass().getSimpleName() +
1036 " does not fully implement ViewParent", e);
1037 }
1038 }
1039 }
1040
Adam Powell539ee872012-02-03 19:00:49 -08001041 @Override
1042 public boolean hasTransientState() {
1043 return mChildCountWithTransientState > 0 || super.hasTransientState();
1044 }
1045
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001046 @Override
1047 public boolean dispatchUnhandledMove(View focused, int direction) {
1048 return mFocused != null &&
1049 mFocused.dispatchUnhandledMove(focused, direction);
1050 }
1051
Alan Viverettebe463f22016-01-21 10:50:10 -05001052 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001053 public void clearChildFocus(View child) {
1054 if (DBG) {
1055 System.out.println(this + " clearChildFocus()");
1056 }
1057
1058 mFocused = null;
1059 if (mParent != null) {
1060 mParent.clearChildFocus(this);
1061 }
1062 }
1063
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001064 @Override
1065 public void clearFocus() {
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08001066 if (DBG) {
1067 System.out.println(this + " clearFocus()");
1068 }
1069 if (mFocused == null) {
1070 super.clearFocus();
1071 } else {
Svetoslav Ganovb552d892012-06-02 14:35:02 -07001072 View focused = mFocused;
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08001073 mFocused = null;
Svetoslav Ganovb552d892012-06-02 14:35:02 -07001074 focused.clearFocus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001075 }
1076 }
1077
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001078 @Override
Alan Viverette223622a2013-12-17 13:29:02 -08001079 void unFocus(View focused) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001080 if (DBG) {
1081 System.out.println(this + " unFocus()");
1082 }
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08001083 if (mFocused == null) {
Alan Viverette223622a2013-12-17 13:29:02 -08001084 super.unFocus(focused);
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08001085 } else {
Alan Viverette223622a2013-12-17 13:29:02 -08001086 mFocused.unFocus(focused);
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08001087 mFocused = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001088 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001089 }
1090
1091 /**
1092 * Returns the focused child of this view, if any. The child may have focus
1093 * or contain focus.
1094 *
1095 * @return the focused child or null.
1096 */
1097 public View getFocusedChild() {
1098 return mFocused;
1099 }
1100
Adam Powell88c11752014-07-21 17:19:16 -07001101 View getDeepestFocusedChild() {
1102 View v = this;
1103 while (v != null) {
1104 if (v.isFocused()) {
1105 return v;
1106 }
1107 v = v instanceof ViewGroup ? ((ViewGroup) v).getFocusedChild() : null;
1108 }
1109 return null;
1110 }
1111
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001112 /**
1113 * Returns true if this view has or contains focus
1114 *
1115 * @return true if this view has or contains focus
1116 */
1117 @Override
1118 public boolean hasFocus() {
Dianne Hackborn4702a852012-08-17 15:18:29 -07001119 return (mPrivateFlags & PFLAG_FOCUSED) != 0 || mFocused != null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001120 }
1121
1122 /*
1123 * (non-Javadoc)
1124 *
1125 * @see android.view.View#findFocus()
1126 */
1127 @Override
1128 public View findFocus() {
1129 if (DBG) {
1130 System.out.println("Find focus in " + this + ": flags="
1131 + isFocused() + ", child=" + mFocused);
1132 }
1133
1134 if (isFocused()) {
1135 return this;
1136 }
1137
1138 if (mFocused != null) {
1139 return mFocused.findFocus();
1140 }
1141 return null;
1142 }
1143
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001144 @Override
Adam Powell0f552f42017-02-03 11:50:42 -08001145 boolean hasFocusable(boolean allowAutoFocus, boolean dispatchExplicit) {
Alan Viverette7485a9b2017-02-27 11:55:53 -05001146 // This should probably be super.hasFocusable, but that would change
1147 // behavior. Historically, we have not checked the ancestor views for
1148 // shouldBlockFocusForTouchscreen() in ViewGroup.hasFocusable.
1149
1150 // Invisible and gone views are never focusable.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001151 if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) {
1152 return false;
1153 }
1154
Alan Viverette7485a9b2017-02-27 11:55:53 -05001155 // Only use effective focusable value when allowed.
1156 if ((allowAutoFocus || getFocusable() != FOCUSABLE_AUTO) && isFocusable()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001157 return true;
1158 }
1159
Alan Viverette7485a9b2017-02-27 11:55:53 -05001160 // Determine whether we have a focused descendant.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001161 final int descendantFocusability = getDescendantFocusability();
Adam Powell88c11752014-07-21 17:19:16 -07001162 if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) {
Evan Rosky2ae1bf52017-05-11 11:18:45 -07001163 return hasFocusableChild(dispatchExplicit);
1164 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001165
Evan Rosky2ae1bf52017-05-11 11:18:45 -07001166 return false;
1167 }
Adam Powell0f552f42017-02-03 11:50:42 -08001168
Evan Rosky2ae1bf52017-05-11 11:18:45 -07001169 boolean hasFocusableChild(boolean dispatchExplicit) {
1170 // Determine whether we have a focusable descendant.
1171 final int count = mChildrenCount;
1172 final View[] children = mChildren;
1173
1174 for (int i = 0; i < count; i++) {
1175 final View child = children[i];
1176
1177 // In case the subclass has overridden has[Explicit]Focusable, dispatch
1178 // to the expected one for each child even though we share logic here.
1179 if ((dispatchExplicit && child.hasExplicitFocusable())
1180 || (!dispatchExplicit && child.hasFocusable())) {
1181 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001182 }
1183 }
1184
1185 return false;
1186 }
1187
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001188 @Override
svetoslavganov75986cf2009-05-14 22:28:01 -07001189 public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001190 final int focusableCount = views.size();
1191
1192 final int descendantFocusability = getDescendantFocusability();
Evan Rosky18b886e2017-02-15 13:26:51 -08001193 final boolean blockFocusForTouchscreen = shouldBlockFocusForTouchscreen();
1194 final boolean focusSelf = (isFocusableInTouchMode() || !blockFocusForTouchscreen);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001195
Evan Rosky3b94bf52017-01-10 17:05:28 -08001196 if (descendantFocusability == FOCUS_BLOCK_DESCENDANTS) {
1197 if (focusSelf) {
1198 super.addFocusables(views, direction, focusableMode);
Adam Powell88c11752014-07-21 17:19:16 -07001199 }
Evan Rosky3b94bf52017-01-10 17:05:28 -08001200 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001201 }
1202
Evan Rosky18b886e2017-02-15 13:26:51 -08001203 if (blockFocusForTouchscreen) {
Evan Rosky3b94bf52017-01-10 17:05:28 -08001204 focusableMode |= FOCUSABLES_TOUCH_MODE;
1205 }
1206
1207 if ((descendantFocusability == FOCUS_BEFORE_DESCENDANTS) && focusSelf) {
1208 super.addFocusables(views, direction, focusableMode);
1209 }
1210
1211 int count = 0;
1212 final View[] children = new View[mChildrenCount];
1213 for (int i = 0; i < mChildrenCount; ++i) {
1214 View child = mChildren[i];
1215 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
1216 children[count++] = child;
1217 }
1218 }
Evan Roskyd114e0f2017-03-23 11:20:04 -07001219 FocusFinder.sort(children, 0, count, this, isLayoutRtl());
Evan Rosky3b94bf52017-01-10 17:05:28 -08001220 for (int i = 0; i < count; ++i) {
1221 children[i].addFocusables(views, direction, focusableMode);
1222 }
1223
1224 // When set to FOCUS_AFTER_DESCENDANTS, we only add ourselves if
1225 // there aren't any focusable descendants. this is
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001226 // to avoid the focus search finding layouts when a more precise search
1227 // among the focusable children would be more interesting.
Evan Rosky3b94bf52017-01-10 17:05:28 -08001228 if ((descendantFocusability == FOCUS_AFTER_DESCENDANTS) && focusSelf
1229 && focusableCount == views.size()) {
svetoslavganov75986cf2009-05-14 22:28:01 -07001230 super.addFocusables(views, direction, focusableMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001231 }
1232 }
1233
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08001234 @Override
Vadim Tryshevb5ced222017-01-17 19:31:35 -08001235 public void addKeyboardNavigationClusters(Collection<View> views, int direction) {
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08001236 final int focusableCount = views.size();
1237
Evan Rosky18b886e2017-02-15 13:26:51 -08001238 if (isKeyboardNavigationCluster()) {
1239 // Cluster-navigation can enter a touchscreenBlocksFocus cluster, so temporarily
1240 // disable touchscreenBlocksFocus to evaluate whether it contains focusables.
1241 final boolean blockedFocus = getTouchscreenBlocksFocus();
1242 try {
1243 setTouchscreenBlocksFocusNoRefocus(false);
1244 super.addKeyboardNavigationClusters(views, direction);
1245 } finally {
1246 setTouchscreenBlocksFocusNoRefocus(blockedFocus);
1247 }
1248 } else {
1249 super.addKeyboardNavigationClusters(views, direction);
1250 }
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08001251
1252 if (focusableCount != views.size()) {
Vadim Tryshev311a5b52017-01-05 18:54:11 -08001253 // No need to look for groups inside a group.
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08001254 return;
1255 }
1256
1257 if (getDescendantFocusability() == FOCUS_BLOCK_DESCENDANTS) {
1258 return;
1259 }
1260
Evan Roskybd10c522017-03-27 15:50:38 -07001261 int count = 0;
1262 final View[] visibleChildren = new View[mChildrenCount];
1263 for (int i = 0; i < mChildrenCount; ++i) {
1264 final View child = mChildren[i];
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08001265 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
Evan Roskybd10c522017-03-27 15:50:38 -07001266 visibleChildren[count++] = child;
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08001267 }
1268 }
Evan Roskyd114e0f2017-03-23 11:20:04 -07001269 FocusFinder.sort(visibleChildren, 0, count, this, isLayoutRtl());
Evan Roskybd10c522017-03-27 15:50:38 -07001270 for (int i = 0; i < count; ++i) {
1271 visibleChildren[i].addKeyboardNavigationClusters(views, direction);
1272 }
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08001273 }
1274
Adam Powellff0d2982014-07-10 20:34:14 -07001275 /**
1276 * Set whether this ViewGroup should ignore focus requests for itself and its children.
1277 * If this option is enabled and the ViewGroup or a descendant currently has focus, focus
1278 * will proceed forward.
1279 *
1280 * @param touchscreenBlocksFocus true to enable blocking focus in the presence of a touchscreen
1281 */
1282 public void setTouchscreenBlocksFocus(boolean touchscreenBlocksFocus) {
1283 if (touchscreenBlocksFocus) {
1284 mGroupFlags |= FLAG_TOUCHSCREEN_BLOCKS_FOCUS;
Evan Rosky0e8a6832017-04-10 12:35:15 -07001285 if (hasFocus() && !isKeyboardNavigationCluster()) {
Adam Powell88c11752014-07-21 17:19:16 -07001286 final View focusedChild = getDeepestFocusedChild();
1287 if (!focusedChild.isFocusableInTouchMode()) {
1288 final View newFocus = focusSearch(FOCUS_FORWARD);
1289 if (newFocus != null) {
1290 newFocus.requestFocus();
1291 }
Adam Powellff0d2982014-07-10 20:34:14 -07001292 }
1293 }
1294 } else {
1295 mGroupFlags &= ~FLAG_TOUCHSCREEN_BLOCKS_FOCUS;
1296 }
1297 }
1298
Evan Rosky18b886e2017-02-15 13:26:51 -08001299 private void setTouchscreenBlocksFocusNoRefocus(boolean touchscreenBlocksFocus) {
1300 if (touchscreenBlocksFocus) {
1301 mGroupFlags |= FLAG_TOUCHSCREEN_BLOCKS_FOCUS;
1302 } else {
1303 mGroupFlags &= ~FLAG_TOUCHSCREEN_BLOCKS_FOCUS;
1304 }
1305 }
1306
Adam Powellff0d2982014-07-10 20:34:14 -07001307 /**
1308 * Check whether this ViewGroup should ignore focus requests for itself and its children.
1309 */
Evan Roskyecb63fc2017-04-13 16:57:18 -07001310 @ViewDebug.ExportedProperty(category = "focus")
Adam Powellff0d2982014-07-10 20:34:14 -07001311 public boolean getTouchscreenBlocksFocus() {
1312 return (mGroupFlags & FLAG_TOUCHSCREEN_BLOCKS_FOCUS) != 0;
1313 }
1314
1315 boolean shouldBlockFocusForTouchscreen() {
Evan Rosky18b886e2017-02-15 13:26:51 -08001316 // There is a special case for keyboard-navigation clusters. We allow cluster navigation
1317 // to jump into blockFocusForTouchscreen ViewGroups which are clusters. Once in the
1318 // cluster, focus is free to move around within it.
Adam Powellff0d2982014-07-10 20:34:14 -07001319 return getTouchscreenBlocksFocus() &&
Evan Rosky18b886e2017-02-15 13:26:51 -08001320 mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN)
Evan Rosky0e8a6832017-04-10 12:35:15 -07001321 && !(isKeyboardNavigationCluster()
1322 && (hasFocus() || (findKeyboardNavigationCluster() != this)));
Adam Powellff0d2982014-07-10 20:34:14 -07001323 }
1324
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001325 @Override
Svetoslav Ganovea515ae2011-09-14 18:15:32 -07001326 public void findViewsWithText(ArrayList<View> outViews, CharSequence text, int flags) {
1327 super.findViewsWithText(outViews, text, flags);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001328 final int childrenCount = mChildrenCount;
1329 final View[] children = mChildren;
1330 for (int i = 0; i < childrenCount; i++) {
1331 View child = children[i];
Svetoslav Ganovea515ae2011-09-14 18:15:32 -07001332 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE
Dianne Hackborn4702a852012-08-17 15:18:29 -07001333 && (child.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
Svetoslav Ganovea515ae2011-09-14 18:15:32 -07001334 child.findViewsWithText(outViews, text, flags);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001335 }
1336 }
1337 }
1338
Svetoslav5b578da2013-05-08 14:23:32 -07001339 /** @hide */
Svetoslav Ganov2cdedff2011-10-03 14:18:42 -07001340 @Override
Svetoslav5b578da2013-05-08 14:23:32 -07001341 public View findViewByAccessibilityIdTraversal(int accessibilityId) {
Svetoslav Ganov2cdedff2011-10-03 14:18:42 -07001342 View foundView = super.findViewByAccessibilityIdTraversal(accessibilityId);
1343 if (foundView != null) {
1344 return foundView;
1345 }
Svetoslav6cc46272015-06-03 11:38:30 -07001346
1347 if (getAccessibilityNodeProvider() != null) {
1348 return null;
1349 }
1350
Svetoslav Ganov2cdedff2011-10-03 14:18:42 -07001351 final int childrenCount = mChildrenCount;
1352 final View[] children = mChildren;
1353 for (int i = 0; i < childrenCount; i++) {
1354 View child = children[i];
1355 foundView = child.findViewByAccessibilityIdTraversal(accessibilityId);
1356 if (foundView != null) {
1357 return foundView;
1358 }
1359 }
Svetoslav6cc46272015-06-03 11:38:30 -07001360
Svetoslav Ganov2cdedff2011-10-03 14:18:42 -07001361 return null;
1362 }
1363
Phil Weaver846cda932017-06-15 10:10:06 -07001364 /** @hide */
1365 @Override
1366 public View findViewByAutofillIdTraversal(int autofillId) {
1367 View foundView = super.findViewByAutofillIdTraversal(autofillId);
1368 if (foundView != null) {
1369 return foundView;
1370 }
1371
1372 final int childrenCount = mChildrenCount;
1373 final View[] children = mChildren;
1374 for (int i = 0; i < childrenCount; i++) {
1375 View child = children[i];
1376 foundView = child.findViewByAutofillIdTraversal(autofillId);
1377 if (foundView != null) {
1378 return foundView;
1379 }
1380 }
1381
1382 return null;
1383 }
1384
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001385 @Override
1386 public void dispatchWindowFocusChanged(boolean hasFocus) {
1387 super.dispatchWindowFocusChanged(hasFocus);
1388 final int count = mChildrenCount;
1389 final View[] children = mChildren;
1390 for (int i = 0; i < count; i++) {
1391 children[i].dispatchWindowFocusChanged(hasFocus);
1392 }
1393 }
1394
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001395 @Override
1396 public void addTouchables(ArrayList<View> views) {
1397 super.addTouchables(views);
1398
1399 final int count = mChildrenCount;
1400 final View[] children = mChildren;
1401
1402 for (int i = 0; i < count; i++) {
1403 final View child = children[i];
1404 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
1405 child.addTouchables(views);
1406 }
1407 }
1408 }
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001409
1410 /**
1411 * @hide
1412 */
1413 @Override
1414 public void makeOptionalFitsSystemWindows() {
1415 super.makeOptionalFitsSystemWindows();
1416 final int count = mChildrenCount;
1417 final View[] children = mChildren;
1418 for (int i = 0; i < count; i++) {
1419 children[i].makeOptionalFitsSystemWindows();
1420 }
1421 }
1422
Romain Guy43c9cdf2010-01-27 13:53:55 -08001423 @Override
1424 public void dispatchDisplayHint(int hint) {
1425 super.dispatchDisplayHint(hint);
1426 final int count = mChildrenCount;
1427 final View[] children = mChildren;
1428 for (int i = 0; i < count; i++) {
1429 children[i].dispatchDisplayHint(hint);
1430 }
1431 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001432
1433 /**
Chet Haase0d299362012-01-26 10:51:48 -08001434 * Called when a view's visibility has changed. Notify the parent to take any appropriate
1435 * action.
1436 *
1437 * @param child The view whose visibility has changed
1438 * @param oldVisibility The previous visibility value (GONE, INVISIBLE, or VISIBLE).
1439 * @param newVisibility The new visibility value (GONE, INVISIBLE, or VISIBLE).
Chet Haase5e25c2c2010-09-16 11:15:56 -07001440 * @hide
Chet Haase5e25c2c2010-09-16 11:15:56 -07001441 */
Chet Haase0d299362012-01-26 10:51:48 -08001442 protected void onChildVisibilityChanged(View child, int oldVisibility, int newVisibility) {
Chet Haase5e25c2c2010-09-16 11:15:56 -07001443 if (mTransition != null) {
Chet Haase0d299362012-01-26 10:51:48 -08001444 if (newVisibility == VISIBLE) {
1445 mTransition.showChild(this, child, oldVisibility);
Chet Haase5e25c2c2010-09-16 11:15:56 -07001446 } else {
Chet Haase0d299362012-01-26 10:51:48 -08001447 mTransition.hideChild(this, child, newVisibility);
Chet Haase5e25c2c2010-09-16 11:15:56 -07001448 if (mTransitioningViews != null && mTransitioningViews.contains(child)) {
Chet Haaseddbb3462012-06-19 13:54:29 -07001449 // Only track this on disappearing views - appearing views are already visible
1450 // and don't need special handling during drawChild()
1451 if (mVisibilityChangingChildren == null) {
1452 mVisibilityChangingChildren = new ArrayList<View>();
1453 }
1454 mVisibilityChangingChildren.add(child);
Chet Haase5e25c2c2010-09-16 11:15:56 -07001455 addDisappearingView(child);
1456 }
1457 }
1458 }
Christopher Tate86cab1b2011-01-13 20:28:55 -08001459
1460 // in all cases, for drags
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001461 if (newVisibility == VISIBLE && mCurrentDragStartEvent != null) {
1462 if (!mChildrenInterestedInDrag.contains(child)) {
1463 notifyChildOfDragStart(child);
Christopher Tate86cab1b2011-01-13 20:28:55 -08001464 }
1465 }
Chet Haase5e25c2c2010-09-16 11:15:56 -07001466 }
1467
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001468 @Override
Adam Powell326d8082009-12-09 15:10:07 -08001469 protected void dispatchVisibilityChanged(View changedView, int visibility) {
1470 super.dispatchVisibilityChanged(changedView, visibility);
1471 final int count = mChildrenCount;
1472 final View[] children = mChildren;
1473 for (int i = 0; i < count; i++) {
1474 children[i].dispatchVisibilityChanged(changedView, visibility);
1475 }
1476 }
1477
Adam Powell326d8082009-12-09 15:10:07 -08001478 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001479 public void dispatchWindowVisibilityChanged(int visibility) {
1480 super.dispatchWindowVisibilityChanged(visibility);
1481 final int count = mChildrenCount;
1482 final View[] children = mChildren;
1483 for (int i = 0; i < count; i++) {
1484 children[i].dispatchWindowVisibilityChanged(visibility);
1485 }
1486 }
1487
Dianne Hackborne36d6e22010-02-17 19:46:25 -08001488 @Override
Adam Powell9c146bf2016-03-15 17:35:00 -07001489 boolean dispatchVisibilityAggregated(boolean isVisible) {
1490 isVisible = super.dispatchVisibilityAggregated(isVisible);
Adam Powell41d96902016-03-15 14:43:19 -07001491 final int count = mChildrenCount;
1492 final View[] children = mChildren;
1493 for (int i = 0; i < count; i++) {
Adam Powell9c146bf2016-03-15 17:35:00 -07001494 // Only dispatch to visible children. Not visible children and their subtrees already
1495 // know that they aren't visible and that's not going to change as a result of
1496 // whatever triggered this dispatch.
1497 if (children[i].getVisibility() == VISIBLE) {
1498 children[i].dispatchVisibilityAggregated(isVisible);
Adam Powell41d96902016-03-15 14:43:19 -07001499 }
1500 }
Adam Powell9c146bf2016-03-15 17:35:00 -07001501 return isVisible;
Adam Powell41d96902016-03-15 14:43:19 -07001502 }
1503
1504 @Override
Dianne Hackborne36d6e22010-02-17 19:46:25 -08001505 public void dispatchConfigurationChanged(Configuration newConfig) {
1506 super.dispatchConfigurationChanged(newConfig);
1507 final int count = mChildrenCount;
1508 final View[] children = mChildren;
1509 for (int i = 0; i < count; i++) {
1510 children[i].dispatchConfigurationChanged(newConfig);
1511 }
1512 }
Filip Gruszczynskia33bdf32015-11-19 18:22:16 -08001513
Alan Viverettebe463f22016-01-21 10:50:10 -05001514 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001515 public void recomputeViewAttributes(View child) {
Joe Onorato664644d2011-01-23 17:53:23 -08001516 if (mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) {
1517 ViewParent parent = mParent;
1518 if (parent != null) parent.recomputeViewAttributes(this);
1519 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001520 }
Romain Guy8506ab42009-06-11 17:35:47 -07001521
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001522 @Override
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001523 void dispatchCollectViewAttributes(AttachInfo attachInfo, int visibility) {
1524 if ((visibility & VISIBILITY_MASK) == VISIBLE) {
1525 super.dispatchCollectViewAttributes(attachInfo, visibility);
1526 final int count = mChildrenCount;
1527 final View[] children = mChildren;
1528 for (int i = 0; i < count; i++) {
1529 final View child = children[i];
1530 child.dispatchCollectViewAttributes(attachInfo,
1531 visibility | (child.mViewFlags&VISIBILITY_MASK));
1532 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001533 }
1534 }
1535
Alan Viverettebe463f22016-01-21 10:50:10 -05001536 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001537 public void bringChildToFront(View child) {
Alan Viverette77bb6f12015-02-11 17:24:33 -08001538 final int index = indexOfChild(child);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001539 if (index >= 0) {
1540 removeFromArray(index);
1541 addInArray(child, mChildrenCount);
1542 child.mParent = this;
Chet Haasecb96db82013-09-04 10:21:46 -07001543 requestLayout();
1544 invalidate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001545 }
1546 }
1547
Romain Guy6410c0a2013-06-17 11:21:58 -07001548 private PointF getLocalPoint() {
1549 if (mLocalPoint == null) mLocalPoint = new PointF();
1550 return mLocalPoint;
1551 }
1552
Vadim Tryshevef128112016-09-16 14:05:53 -07001553 @Override
1554 boolean dispatchDragEnterExitInPreN(DragEvent event) {
1555 if (event.mAction == DragEvent.ACTION_DRAG_EXITED && mCurrentDragChild != null) {
1556 // The drag exited a sub-tree of views; notify of the exit all descendants that are in
1557 // entered state.
1558 // We don't need this recursive delivery for ENTERED events because they get generated
1559 // from the recursive delivery of LOCATION/DROP events, and hence, don't need their own
1560 // recursion.
1561 mCurrentDragChild.dispatchDragEnterExitInPreN(event);
1562 mCurrentDragChild = null;
1563 }
1564 return mIsInterestedInDrag && super.dispatchDragEnterExitInPreN(event);
1565 }
1566
Steve Block8a7259b2012-03-01 11:24:41 +00001567 // TODO: Write real docs
Christopher Tatea53146c2010-09-07 11:57:52 -07001568 @Override
1569 public boolean dispatchDragEvent(DragEvent event) {
1570 boolean retval = false;
1571 final float tx = event.mX;
1572 final float ty = event.mY;
Vadim Trysheva61efa42016-09-28 15:15:52 -07001573 final ClipData td = event.mClipData;
Christopher Tatea53146c2010-09-07 11:57:52 -07001574
Christopher Tatea53146c2010-09-07 11:57:52 -07001575 // Dispatch down the view hierarchy
Romain Guy6410c0a2013-06-17 11:21:58 -07001576 final PointF localPoint = getLocalPoint();
1577
Christopher Tatea53146c2010-09-07 11:57:52 -07001578 switch (event.mAction) {
1579 case DragEvent.ACTION_DRAG_STARTED: {
Vadim Tryshevef128112016-09-16 14:05:53 -07001580 // Clear the state to recalculate which views we drag over.
1581 mCurrentDragChild = null;
1582
Christopher Tate86cab1b2011-01-13 20:28:55 -08001583 // Set up our tracking of drag-started notifications
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001584 mCurrentDragStartEvent = DragEvent.obtain(event);
1585 if (mChildrenInterestedInDrag == null) {
1586 mChildrenInterestedInDrag = new HashSet<View>();
Christopher Tate86cab1b2011-01-13 20:28:55 -08001587 } else {
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001588 mChildrenInterestedInDrag.clear();
Christopher Tate86cab1b2011-01-13 20:28:55 -08001589 }
1590
Christopher Tatea53146c2010-09-07 11:57:52 -07001591 // Now dispatch down to our children, caching the responses
Christopher Tatea53146c2010-09-07 11:57:52 -07001592 final int count = mChildrenCount;
1593 final View[] children = mChildren;
1594 for (int i = 0; i < count; i++) {
Christopher Tate2c095f32010-10-04 14:13:40 -07001595 final View child = children[i];
Christopher Tate3d4bf172011-03-28 16:16:46 -07001596 child.mPrivateFlags2 &= ~View.DRAG_MASK;
Christopher Tate2c095f32010-10-04 14:13:40 -07001597 if (child.getVisibility() == VISIBLE) {
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001598 if (notifyChildOfDragStart(children[i])) {
1599 retval = true;
Christopher Tate2c095f32010-10-04 14:13:40 -07001600 }
Christopher Tatea53146c2010-09-07 11:57:52 -07001601 }
1602 }
1603
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001604 // Notify itself of the drag start.
1605 mIsInterestedInDrag = super.dispatchDragEvent(event);
1606 if (mIsInterestedInDrag) {
Christopher Tatea53146c2010-09-07 11:57:52 -07001607 retval = true;
1608 }
Yorke Lee0394b212016-03-10 18:20:04 -08001609
1610 if (!retval) {
1611 // Neither us nor any of our children are interested in this drag, so stop tracking
1612 // the current drag event.
1613 mCurrentDragStartEvent.recycle();
1614 mCurrentDragStartEvent = null;
1615 }
Christopher Tatea53146c2010-09-07 11:57:52 -07001616 } break;
1617
1618 case DragEvent.ACTION_DRAG_ENDED: {
Christopher Tate86cab1b2011-01-13 20:28:55 -08001619 // Release the bookkeeping now that the drag lifecycle has ended
Vadim Tryshev15177892015-12-18 08:01:00 -08001620 final HashSet<View> childrenInterestedInDrag = mChildrenInterestedInDrag;
1621 if (childrenInterestedInDrag != null) {
1622 for (View child : childrenInterestedInDrag) {
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001623 // If a child was interested in the ongoing drag, it's told that it's over
1624 if (child.dispatchDragEvent(event)) {
1625 retval = true;
1626 }
Christopher Tate1fc014f2011-01-19 12:56:26 -08001627 }
Vadim Tryshev15177892015-12-18 08:01:00 -08001628 childrenInterestedInDrag.clear();
1629 }
1630 if (mCurrentDragStartEvent != null) {
1631 mCurrentDragStartEvent.recycle();
1632 mCurrentDragStartEvent = null;
Christopher Tate1fc014f2011-01-19 12:56:26 -08001633 }
Christopher Tate86cab1b2011-01-13 20:28:55 -08001634
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001635 if (mIsInterestedInDrag) {
1636 if (super.dispatchDragEvent(event)) {
1637 retval = true;
1638 }
1639 mIsInterestedInDrag = false;
Christopher Tatea53146c2010-09-07 11:57:52 -07001640 }
1641 } break;
1642
Vadim Tryshev1edc6daf2016-09-15 16:19:15 -07001643 case DragEvent.ACTION_DRAG_LOCATION:
1644 case DragEvent.ACTION_DROP: {
Christopher Tatea53146c2010-09-07 11:57:52 -07001645 // Find the [possibly new] drag target
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001646 View target = findFrontmostDroppableChildAt(event.mX, event.mY, localPoint);
Vadim Tryshevef128112016-09-16 14:05:53 -07001647
1648 if (target != mCurrentDragChild) {
Vadim Tryshev45bee6b2016-09-19 11:00:37 -07001649 if (sCascadedDragDrop) {
Vadim Tryshevef128112016-09-16 14:05:53 -07001650 // For pre-Nougat apps, make sure that the whole hierarchy of views that contain
1651 // the drag location is kept in the state between ENTERED and EXITED events.
1652 // (Starting with N, only the innermost view will be in that state).
1653
1654 final int action = event.mAction;
1655 // Position should not be available for ACTION_DRAG_ENTERED and
1656 // ACTION_DRAG_EXITED.
1657 event.mX = 0;
1658 event.mY = 0;
Vadim Trysheva61efa42016-09-28 15:15:52 -07001659 event.mClipData = null;
Vadim Tryshevef128112016-09-16 14:05:53 -07001660
1661 if (mCurrentDragChild != null) {
1662 event.mAction = DragEvent.ACTION_DRAG_EXITED;
1663 mCurrentDragChild.dispatchDragEnterExitInPreN(event);
1664 }
1665
1666 if (target != null) {
1667 event.mAction = DragEvent.ACTION_DRAG_ENTERED;
1668 target.dispatchDragEnterExitInPreN(event);
1669 }
1670
1671 event.mAction = action;
1672 event.mX = tx;
1673 event.mY = ty;
Vadim Trysheva61efa42016-09-28 15:15:52 -07001674 event.mClipData = td;
Vadim Tryshevef128112016-09-16 14:05:53 -07001675 }
1676 mCurrentDragChild = target;
1677 }
1678
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001679 if (target == null && mIsInterestedInDrag) {
1680 target = this;
1681 }
Christopher Tatea53146c2010-09-07 11:57:52 -07001682
Vadim Tryshev1edc6daf2016-09-15 16:19:15 -07001683 // Dispatch the actual drag notice, localized into the target coordinates.
Christopher Tatea53146c2010-09-07 11:57:52 -07001684 if (target != null) {
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001685 if (target != this) {
1686 event.mX = localPoint.x;
1687 event.mY = localPoint.y;
Christopher Tatea53146c2010-09-07 11:57:52 -07001688
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001689 retval = target.dispatchDragEvent(event);
Christopher Tatea53146c2010-09-07 11:57:52 -07001690
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001691 event.mX = tx;
1692 event.mY = ty;
Vadim Tryshev1edc6daf2016-09-15 16:19:15 -07001693
Vadim Tryshev45bee6b2016-09-19 11:00:37 -07001694 if (mIsInterestedInDrag) {
1695 final boolean eventWasConsumed;
1696 if (sCascadedDragDrop) {
1697 eventWasConsumed = retval;
1698 } else {
1699 eventWasConsumed = event.mEventHandlerWasCalled;
1700 }
1701
1702 if (!eventWasConsumed) {
1703 retval = super.dispatchDragEvent(event);
1704 }
Vadim Tryshev1edc6daf2016-09-15 16:19:15 -07001705 }
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001706 } else {
1707 retval = super.dispatchDragEvent(event);
1708 }
Christopher Tatea53146c2010-09-07 11:57:52 -07001709 }
1710 } break;
Christopher Tatea53146c2010-09-07 11:57:52 -07001711 }
1712
Christopher Tatea53146c2010-09-07 11:57:52 -07001713 return retval;
1714 }
1715
1716 // Find the frontmost child view that lies under the given point, and calculate
1717 // the position within its own local coordinate system.
1718 View findFrontmostDroppableChildAt(float x, float y, PointF outLocalPoint) {
Christopher Tatea53146c2010-09-07 11:57:52 -07001719 final int count = mChildrenCount;
1720 final View[] children = mChildren;
1721 for (int i = count - 1; i >= 0; i--) {
1722 final View child = children[i];
Christopher Tate3d4bf172011-03-28 16:16:46 -07001723 if (!child.canAcceptDrag()) {
Christopher Tatea53146c2010-09-07 11:57:52 -07001724 continue;
1725 }
1726
Christopher Tate2c095f32010-10-04 14:13:40 -07001727 if (isTransformedTouchPointInView(x, y, child, outLocalPoint)) {
Christopher Tatea53146c2010-09-07 11:57:52 -07001728 return child;
1729 }
1730 }
1731 return null;
1732 }
1733
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001734 boolean notifyChildOfDragStart(View child) {
1735 // The caller guarantees that the child is not in mChildrenInterestedInDrag yet.
1736
Christopher Tate86cab1b2011-01-13 20:28:55 -08001737 if (ViewDebug.DEBUG_DRAG) {
1738 Log.d(View.VIEW_LOG_TAG, "Sending drag-started to view: " + child);
1739 }
1740
Vladislav Kaznacheevc2449702016-05-16 12:57:15 -07001741 final float tx = mCurrentDragStartEvent.mX;
1742 final float ty = mCurrentDragStartEvent.mY;
1743
1744 final float[] point = getTempPoint();
1745 point[0] = tx;
1746 point[1] = ty;
1747 transformPointToViewLocal(point, child);
1748
1749 mCurrentDragStartEvent.mX = point[0];
1750 mCurrentDragStartEvent.mY = point[1];
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001751 final boolean canAccept = child.dispatchDragEvent(mCurrentDragStartEvent);
Vladislav Kaznacheevc2449702016-05-16 12:57:15 -07001752 mCurrentDragStartEvent.mX = tx;
1753 mCurrentDragStartEvent.mY = ty;
Vadim Tryshev1edc6daf2016-09-15 16:19:15 -07001754 mCurrentDragStartEvent.mEventHandlerWasCalled = false;
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001755 if (canAccept) {
1756 mChildrenInterestedInDrag.add(child);
1757 if (!child.canAcceptDrag()) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07001758 child.mPrivateFlags2 |= View.PFLAG2_DRAG_CAN_ACCEPT;
Christopher Tate3d4bf172011-03-28 16:16:46 -07001759 child.refreshDrawableState();
1760 }
Christopher Tate86cab1b2011-01-13 20:28:55 -08001761 }
Christopher Tate3d4bf172011-03-28 16:16:46 -07001762 return canAccept;
Christopher Tate86cab1b2011-01-13 20:28:55 -08001763 }
1764
Joe Onorato664644d2011-01-23 17:53:23 -08001765 @Override
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001766 public void dispatchWindowSystemUiVisiblityChanged(int visible) {
1767 super.dispatchWindowSystemUiVisiblityChanged(visible);
1768
1769 final int count = mChildrenCount;
1770 final View[] children = mChildren;
1771 for (int i=0; i <count; i++) {
1772 final View child = children[i];
1773 child.dispatchWindowSystemUiVisiblityChanged(visible);
1774 }
1775 }
1776
1777 @Override
Joe Onorato664644d2011-01-23 17:53:23 -08001778 public void dispatchSystemUiVisibilityChanged(int visible) {
1779 super.dispatchSystemUiVisibilityChanged(visible);
1780
1781 final int count = mChildrenCount;
1782 final View[] children = mChildren;
1783 for (int i=0; i <count; i++) {
1784 final View child = children[i];
1785 child.dispatchSystemUiVisibilityChanged(visible);
1786 }
1787 }
1788
Dianne Hackborn9a230e02011-10-06 11:51:27 -07001789 @Override
Dianne Hackborncf675782012-05-10 15:07:24 -07001790 boolean updateLocalSystemUiVisibility(int localValue, int localChanges) {
1791 boolean changed = super.updateLocalSystemUiVisibility(localValue, localChanges);
Dianne Hackborn9a230e02011-10-06 11:51:27 -07001792
1793 final int count = mChildrenCount;
1794 final View[] children = mChildren;
1795 for (int i=0; i <count; i++) {
1796 final View child = children[i];
Dianne Hackborncf675782012-05-10 15:07:24 -07001797 changed |= child.updateLocalSystemUiVisibility(localValue, localChanges);
Dianne Hackborn9a230e02011-10-06 11:51:27 -07001798 }
Dianne Hackborncf675782012-05-10 15:07:24 -07001799 return changed;
Dianne Hackborn9a230e02011-10-06 11:51:27 -07001800 }
1801
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001802 @Override
1803 public boolean dispatchKeyEventPreIme(KeyEvent event) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07001804 if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
1805 == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001806 return super.dispatchKeyEventPreIme(event);
Dianne Hackborn4702a852012-08-17 15:18:29 -07001807 } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
1808 == PFLAG_HAS_BOUNDS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001809 return mFocused.dispatchKeyEventPreIme(event);
1810 }
1811 return false;
1812 }
1813
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001814 @Override
1815 public boolean dispatchKeyEvent(KeyEvent event) {
Jeff Brown21bc5c92011-02-28 18:27:14 -08001816 if (mInputEventConsistencyVerifier != null) {
1817 mInputEventConsistencyVerifier.onKeyEvent(event, 1);
1818 }
1819
Dianne Hackborn4702a852012-08-17 15:18:29 -07001820 if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
1821 == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001822 if (super.dispatchKeyEvent(event)) {
1823 return true;
1824 }
Dianne Hackborn4702a852012-08-17 15:18:29 -07001825 } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
1826 == PFLAG_HAS_BOUNDS) {
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001827 if (mFocused.dispatchKeyEvent(event)) {
1828 return true;
1829 }
1830 }
1831
1832 if (mInputEventConsistencyVerifier != null) {
1833 mInputEventConsistencyVerifier.onUnhandledEvent(event, 1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001834 }
1835 return false;
1836 }
1837
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001838 @Override
1839 public boolean dispatchKeyShortcutEvent(KeyEvent event) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07001840 if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
1841 == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001842 return super.dispatchKeyShortcutEvent(event);
Dianne Hackborn4702a852012-08-17 15:18:29 -07001843 } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
1844 == PFLAG_HAS_BOUNDS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001845 return mFocused.dispatchKeyShortcutEvent(event);
1846 }
1847 return false;
1848 }
1849
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001850 @Override
1851 public boolean dispatchTrackballEvent(MotionEvent event) {
Jeff Brown21bc5c92011-02-28 18:27:14 -08001852 if (mInputEventConsistencyVerifier != null) {
1853 mInputEventConsistencyVerifier.onTrackballEvent(event, 1);
1854 }
1855
Dianne Hackborn4702a852012-08-17 15:18:29 -07001856 if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
1857 == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001858 if (super.dispatchTrackballEvent(event)) {
1859 return true;
1860 }
Dianne Hackborn4702a852012-08-17 15:18:29 -07001861 } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
1862 == PFLAG_HAS_BOUNDS) {
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001863 if (mFocused.dispatchTrackballEvent(event)) {
1864 return true;
1865 }
1866 }
1867
1868 if (mInputEventConsistencyVerifier != null) {
1869 mInputEventConsistencyVerifier.onUnhandledEvent(event, 1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001870 }
1871 return false;
1872 }
1873
Jun Mukai1db53972015-09-11 18:08:31 -07001874 @Override
Vladislav Kaznacheev3787de12016-12-21 10:36:35 -08001875 public boolean dispatchCapturedPointerEvent(MotionEvent event) {
1876 if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
1877 == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
1878 if (super.dispatchCapturedPointerEvent(event)) {
1879 return true;
1880 }
1881 } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
1882 == PFLAG_HAS_BOUNDS) {
1883 if (mFocused.dispatchCapturedPointerEvent(event)) {
1884 return true;
1885 }
1886 }
1887 return false;
1888 }
1889
1890 @Override
1891 public void dispatchPointerCaptureChanged(boolean hasCapture) {
1892 exitHoverTargets();
1893
1894 super.dispatchPointerCaptureChanged(hasCapture);
1895 final int count = mChildrenCount;
1896 final View[] children = mChildren;
1897 for (int i = 0; i < count; i++) {
1898 children[i].dispatchPointerCaptureChanged(hasCapture);
1899 }
1900 }
1901
1902 @Override
Michael Wrighte051f6f2016-05-13 17:44:16 +01001903 public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) {
1904 final float x = event.getX(pointerIndex);
1905 final float y = event.getY(pointerIndex);
Keisuke Kuroyanagid85bc502016-01-21 14:50:38 +09001906 if (isOnScrollbarThumb(x, y) || isDraggingScrollBar()) {
Michael Wrighte051f6f2016-05-13 17:44:16 +01001907 return PointerIcon.getSystemIcon(mContext, PointerIcon.TYPE_ARROW);
Keisuke Kuroyanagid85bc502016-01-21 14:50:38 +09001908 }
Jun Mukai1db53972015-09-11 18:08:31 -07001909 // Check what the child under the pointer says about the pointer.
1910 final int childrenCount = mChildrenCount;
1911 if (childrenCount != 0) {
1912 final ArrayList<View> preorderedList = buildOrderedChildList();
1913 final boolean customOrder = preorderedList == null
1914 && isChildrenDrawingOrderEnabled();
1915 final View[] children = mChildren;
1916 for (int i = childrenCount - 1; i >= 0; i--) {
Alan Viverettea7b85e62016-01-22 10:14:02 -05001917 final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
1918 final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);
Vladislav Kaznacheev3d5cfc02017-01-05 17:50:38 -08001919 if (!canViewReceivePointerEvents(child)
1920 || !isTransformedTouchPointInView(x, y, child, null)) {
1921 continue;
1922 }
1923 final PointerIcon pointerIcon =
1924 dispatchResolvePointerIcon(event, pointerIndex, child);
1925 if (pointerIcon != null) {
1926 if (preorderedList != null) preorderedList.clear();
1927 return pointerIcon;
Jun Mukai1db53972015-09-11 18:08:31 -07001928 }
1929 }
Chris Craikfc563772016-05-04 13:34:30 -07001930 if (preorderedList != null) preorderedList.clear();
Jun Mukai1db53972015-09-11 18:08:31 -07001931 }
1932
1933 // The pointer is not a child or the child has no preferences, returning the default
1934 // implementation.
Michael Wrighte051f6f2016-05-13 17:44:16 +01001935 return super.onResolvePointerIcon(event, pointerIndex);
1936 }
1937
1938 private PointerIcon dispatchResolvePointerIcon(MotionEvent event, int pointerIndex,
1939 View child) {
1940 final PointerIcon pointerIcon;
1941 if (!child.hasIdentityMatrix()) {
1942 MotionEvent transformedEvent = getTransformedMotionEvent(event, child);
1943 pointerIcon = child.onResolvePointerIcon(transformedEvent, pointerIndex);
1944 transformedEvent.recycle();
1945 } else {
1946 final float offsetX = mScrollX - child.mLeft;
1947 final float offsetY = mScrollY - child.mTop;
1948 event.offsetLocation(offsetX, offsetY);
1949 pointerIcon = child.onResolvePointerIcon(event, pointerIndex);
1950 event.offsetLocation(-offsetX, -offsetY);
1951 }
1952 return pointerIcon;
Jun Mukai1db53972015-09-11 18:08:31 -07001953 }
1954
Alan Viverettea7b85e62016-01-22 10:14:02 -05001955 private int getAndVerifyPreorderedIndex(int childrenCount, int i, boolean customOrder) {
1956 final int childIndex;
1957 if (customOrder) {
1958 final int childIndex1 = getChildDrawingOrder(childrenCount, i);
1959 if (childIndex1 >= childrenCount) {
1960 throw new IndexOutOfBoundsException("getChildDrawingOrder() "
1961 + "returned invalid index " + childIndex1
1962 + " (child count is " + childrenCount + ")");
1963 }
1964 childIndex = childIndex1;
1965 } else {
1966 childIndex = i;
1967 }
1968 return childIndex;
1969 }
1970
Romain Guya9489272011-06-22 20:58:11 -07001971 @SuppressWarnings({"ConstantConditions"})
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001972 @Override
Jeff Browna032cc02011-03-07 16:56:21 -08001973 protected boolean dispatchHoverEvent(MotionEvent event) {
Jeff Browna032cc02011-03-07 16:56:21 -08001974 final int action = event.getAction();
Jeff Browna032cc02011-03-07 16:56:21 -08001975
Jeff Brown10b62902011-06-20 16:40:37 -07001976 // First check whether the view group wants to intercept the hover event.
1977 final boolean interceptHover = onInterceptHoverEvent(event);
1978 event.setAction(action); // restore action in case it was changed
1979
Jeff Brown87b7f802011-06-21 18:35:45 -07001980 MotionEvent eventNoHistory = event;
1981 boolean handled = false;
1982
1983 // Send events to the hovered children and build a new list of hover targets until
1984 // one is found that handles the event.
1985 HoverTarget firstOldHoverTarget = mFirstHoverTarget;
1986 mFirstHoverTarget = null;
Jeff Brown10b62902011-06-20 16:40:37 -07001987 if (!interceptHover && action != MotionEvent.ACTION_HOVER_EXIT) {
Jeff Browna032cc02011-03-07 16:56:21 -08001988 final float x = event.getX();
1989 final float y = event.getY();
Jeff Brown33bbfd22011-02-24 20:55:35 -08001990 final int childrenCount = mChildrenCount;
1991 if (childrenCount != 0) {
Chris Craikab008f02014-05-23 17:55:03 -07001992 final ArrayList<View> preorderedList = buildOrderedChildList();
1993 final boolean customOrder = preorderedList == null
1994 && isChildrenDrawingOrderEnabled();
Jeff Brown33bbfd22011-02-24 20:55:35 -08001995 final View[] children = mChildren;
Jeff Brown87b7f802011-06-21 18:35:45 -07001996 HoverTarget lastHoverTarget = null;
Jeff Brown33bbfd22011-02-24 20:55:35 -08001997 for (int i = childrenCount - 1; i >= 0; i--) {
Alan Viverettea7b85e62016-01-22 10:14:02 -05001998 final int childIndex = getAndVerifyPreorderedIndex(
1999 childrenCount, i, customOrder);
2000 final View child = getAndVerifyPreorderedView(
2001 preorderedList, children, childIndex);
Jeff Brown87b7f802011-06-21 18:35:45 -07002002 if (!canViewReceivePointerEvents(child)
2003 || !isTransformedTouchPointInView(x, y, child, null)) {
2004 continue;
2005 }
2006
2007 // Obtain a hover target for this child. Dequeue it from the
2008 // old hover target list if the child was previously hovered.
2009 HoverTarget hoverTarget = firstOldHoverTarget;
2010 final boolean wasHovered;
2011 for (HoverTarget predecessor = null; ;) {
2012 if (hoverTarget == null) {
2013 hoverTarget = HoverTarget.obtain(child);
2014 wasHovered = false;
2015 break;
2016 }
2017
2018 if (hoverTarget.child == child) {
2019 if (predecessor != null) {
2020 predecessor.next = hoverTarget.next;
2021 } else {
2022 firstOldHoverTarget = hoverTarget.next;
2023 }
2024 hoverTarget.next = null;
2025 wasHovered = true;
2026 break;
2027 }
2028
2029 predecessor = hoverTarget;
2030 hoverTarget = hoverTarget.next;
2031 }
2032
2033 // Enqueue the hover target onto the new hover target list.
2034 if (lastHoverTarget != null) {
2035 lastHoverTarget.next = hoverTarget;
2036 } else {
Jeff Brown87b7f802011-06-21 18:35:45 -07002037 mFirstHoverTarget = hoverTarget;
2038 }
Sangkyu Lee8725f362013-03-13 09:38:45 +09002039 lastHoverTarget = hoverTarget;
Jeff Brown87b7f802011-06-21 18:35:45 -07002040
2041 // Dispatch the event to the child.
2042 if (action == MotionEvent.ACTION_HOVER_ENTER) {
2043 if (!wasHovered) {
2044 // Send the enter as is.
2045 handled |= dispatchTransformedGenericPointerEvent(
2046 event, child); // enter
2047 }
2048 } else if (action == MotionEvent.ACTION_HOVER_MOVE) {
2049 if (!wasHovered) {
2050 // Synthesize an enter from a move.
2051 eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory);
2052 eventNoHistory.setAction(MotionEvent.ACTION_HOVER_ENTER);
2053 handled |= dispatchTransformedGenericPointerEvent(
2054 eventNoHistory, child); // enter
2055 eventNoHistory.setAction(action);
2056
2057 handled |= dispatchTransformedGenericPointerEvent(
2058 eventNoHistory, child); // move
2059 } else {
2060 // Send the move as is.
2061 handled |= dispatchTransformedGenericPointerEvent(event, child);
2062 }
2063 }
2064 if (handled) {
Jeff Brown10b62902011-06-20 16:40:37 -07002065 break;
Jeff Brown33bbfd22011-02-24 20:55:35 -08002066 }
Jeff Brown10b62902011-06-20 16:40:37 -07002067 }
Chris Craikab008f02014-05-23 17:55:03 -07002068 if (preorderedList != null) preorderedList.clear();
Jeff Brown10b62902011-06-20 16:40:37 -07002069 }
2070 }
Jeff Brown33bbfd22011-02-24 20:55:35 -08002071
Jeff Brown87b7f802011-06-21 18:35:45 -07002072 // Send exit events to all previously hovered children that are no longer hovered.
2073 while (firstOldHoverTarget != null) {
2074 final View child = firstOldHoverTarget.child;
Jeff Brown10b62902011-06-20 16:40:37 -07002075
Jeff Brown87b7f802011-06-21 18:35:45 -07002076 // Exit the old hovered child.
2077 if (action == MotionEvent.ACTION_HOVER_EXIT) {
2078 // Send the exit as is.
2079 handled |= dispatchTransformedGenericPointerEvent(
2080 event, child); // exit
2081 } else {
2082 // Synthesize an exit from a move or enter.
2083 // Ignore the result because hover focus has moved to a different view.
2084 if (action == MotionEvent.ACTION_HOVER_MOVE) {
Vladislav Kaznacheev5a77c372016-10-10 16:11:15 -07002085 final boolean hoverExitPending = event.isHoverExitPending();
2086 event.setHoverExitPending(true);
Jeff Brown10b62902011-06-20 16:40:37 -07002087 dispatchTransformedGenericPointerEvent(
Jeff Brown87b7f802011-06-21 18:35:45 -07002088 event, child); // move
Vladislav Kaznacheev5a77c372016-10-10 16:11:15 -07002089 event.setHoverExitPending(hoverExitPending);
Jeff Brown10b62902011-06-20 16:40:37 -07002090 }
Jeff Brown87b7f802011-06-21 18:35:45 -07002091 eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory);
2092 eventNoHistory.setAction(MotionEvent.ACTION_HOVER_EXIT);
2093 dispatchTransformedGenericPointerEvent(
2094 eventNoHistory, child); // exit
2095 eventNoHistory.setAction(action);
Jeff Brown10b62902011-06-20 16:40:37 -07002096 }
2097
Jeff Brown87b7f802011-06-21 18:35:45 -07002098 final HoverTarget nextOldHoverTarget = firstOldHoverTarget.next;
2099 firstOldHoverTarget.recycle();
2100 firstOldHoverTarget = nextOldHoverTarget;
Jeff Brown10b62902011-06-20 16:40:37 -07002101 }
2102
Vladislav Kaznacheev5a77c372016-10-10 16:11:15 -07002103 // Send events to the view group itself if no children have handled it and the view group
2104 // itself is not currently being hover-exited.
2105 boolean newHoveredSelf = !handled &&
2106 (action != MotionEvent.ACTION_HOVER_EXIT) && !event.isHoverExitPending();
Jeff Brown10b62902011-06-20 16:40:37 -07002107 if (newHoveredSelf == mHoveredSelf) {
2108 if (newHoveredSelf) {
2109 // Send event to the view group as before.
2110 handled |= super.dispatchHoverEvent(event);
2111 }
2112 } else {
2113 if (mHoveredSelf) {
2114 // Exit the view group.
2115 if (action == MotionEvent.ACTION_HOVER_EXIT) {
2116 // Send the exit as is.
2117 handled |= super.dispatchHoverEvent(event); // exit
2118 } else {
2119 // Synthesize an exit from a move or enter.
2120 // Ignore the result because hover focus is moving to a different view.
2121 if (action == MotionEvent.ACTION_HOVER_MOVE) {
2122 super.dispatchHoverEvent(event); // move
2123 }
2124 eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory);
2125 eventNoHistory.setAction(MotionEvent.ACTION_HOVER_EXIT);
2126 super.dispatchHoverEvent(eventNoHistory); // exit
2127 eventNoHistory.setAction(action);
2128 }
2129 mHoveredSelf = false;
2130 }
2131
2132 if (newHoveredSelf) {
2133 // Enter the view group.
2134 if (action == MotionEvent.ACTION_HOVER_ENTER) {
2135 // Send the enter as is.
2136 handled |= super.dispatchHoverEvent(event); // enter
2137 mHoveredSelf = true;
2138 } else if (action == MotionEvent.ACTION_HOVER_MOVE) {
2139 // Synthesize an enter from a move.
2140 eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory);
2141 eventNoHistory.setAction(MotionEvent.ACTION_HOVER_ENTER);
2142 handled |= super.dispatchHoverEvent(eventNoHistory); // enter
2143 eventNoHistory.setAction(action);
2144
2145 handled |= super.dispatchHoverEvent(eventNoHistory); // move
2146 mHoveredSelf = true;
Jeff Brown33bbfd22011-02-24 20:55:35 -08002147 }
2148 }
Jeff Brown33bbfd22011-02-24 20:55:35 -08002149 }
2150
Jeff Browna032cc02011-03-07 16:56:21 -08002151 // Recycle the copy of the event that we made.
2152 if (eventNoHistory != event) {
2153 eventNoHistory.recycle();
2154 }
2155
Jeff Browna032cc02011-03-07 16:56:21 -08002156 // Done.
2157 return handled;
2158 }
2159
Jeff Brown59a422e2012-04-19 15:19:19 -07002160 private void exitHoverTargets() {
2161 if (mHoveredSelf || mFirstHoverTarget != null) {
2162 final long now = SystemClock.uptimeMillis();
2163 MotionEvent event = MotionEvent.obtain(now, now,
2164 MotionEvent.ACTION_HOVER_EXIT, 0.0f, 0.0f, 0);
2165 event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
2166 dispatchHoverEvent(event);
2167 event.recycle();
2168 }
2169 }
2170
2171 private void cancelHoverTarget(View view) {
2172 HoverTarget predecessor = null;
2173 HoverTarget target = mFirstHoverTarget;
2174 while (target != null) {
2175 final HoverTarget next = target.next;
2176 if (target.child == view) {
2177 if (predecessor == null) {
2178 mFirstHoverTarget = next;
2179 } else {
2180 predecessor.next = next;
2181 }
2182 target.recycle();
2183
2184 final long now = SystemClock.uptimeMillis();
2185 MotionEvent event = MotionEvent.obtain(now, now,
2186 MotionEvent.ACTION_HOVER_EXIT, 0.0f, 0.0f, 0);
2187 event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
2188 view.dispatchHoverEvent(event);
2189 event.recycle();
2190 return;
2191 }
2192 predecessor = target;
2193 target = next;
2194 }
2195 }
2196
Vladislav Kaznacheevf847ee32016-11-21 14:11:00 -08002197 @Override
2198 boolean dispatchTooltipHoverEvent(MotionEvent event) {
2199 final int action = event.getAction();
2200 switch (action) {
2201 case MotionEvent.ACTION_HOVER_ENTER:
2202 break;
2203
2204 case MotionEvent.ACTION_HOVER_MOVE:
2205 View newTarget = null;
2206
2207 // Check what the child under the pointer says about the tooltip.
2208 final int childrenCount = mChildrenCount;
2209 if (childrenCount != 0) {
2210 final float x = event.getX();
2211 final float y = event.getY();
2212
2213 final ArrayList<View> preorderedList = buildOrderedChildList();
2214 final boolean customOrder = preorderedList == null
2215 && isChildrenDrawingOrderEnabled();
2216 final View[] children = mChildren;
2217 for (int i = childrenCount - 1; i >= 0; i--) {
2218 final int childIndex =
2219 getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
2220 final View child =
2221 getAndVerifyPreorderedView(preorderedList, children, childIndex);
Vladislav Kaznacheev943cf0e2017-01-06 09:52:51 -08002222 if (!canViewReceivePointerEvents(child)
2223 || !isTransformedTouchPointInView(x, y, child, null)) {
2224 continue;
2225 }
2226 if (dispatchTooltipHoverEvent(event, child)) {
2227 newTarget = child;
Vladislav Kaznacheevf847ee32016-11-21 14:11:00 -08002228 break;
2229 }
2230 }
2231 if (preorderedList != null) preorderedList.clear();
2232 }
2233
2234 if (mTooltipHoverTarget != newTarget) {
2235 if (mTooltipHoverTarget != null) {
2236 event.setAction(MotionEvent.ACTION_HOVER_EXIT);
2237 mTooltipHoverTarget.dispatchTooltipHoverEvent(event);
2238 event.setAction(action);
2239 }
2240 mTooltipHoverTarget = newTarget;
2241 }
2242
2243 if (mTooltipHoverTarget != null) {
2244 if (mTooltipHoveredSelf) {
2245 mTooltipHoveredSelf = false;
2246 event.setAction(MotionEvent.ACTION_HOVER_EXIT);
2247 super.dispatchTooltipHoverEvent(event);
2248 event.setAction(action);
2249 }
2250 return true;
2251 }
2252
2253 mTooltipHoveredSelf = super.dispatchTooltipHoverEvent(event);
2254 return mTooltipHoveredSelf;
2255
2256 case MotionEvent.ACTION_HOVER_EXIT:
2257 if (mTooltipHoverTarget != null) {
2258 mTooltipHoverTarget.dispatchTooltipHoverEvent(event);
2259 mTooltipHoverTarget = null;
2260 } else if (mTooltipHoveredSelf) {
2261 super.dispatchTooltipHoverEvent(event);
2262 mTooltipHoveredSelf = false;
2263 }
2264 break;
2265 }
2266 return false;
2267 }
2268
2269 private boolean dispatchTooltipHoverEvent(MotionEvent event, View child) {
2270 final boolean result;
2271 if (!child.hasIdentityMatrix()) {
2272 MotionEvent transformedEvent = getTransformedMotionEvent(event, child);
2273 result = child.dispatchTooltipHoverEvent(transformedEvent);
2274 transformedEvent.recycle();
2275 } else {
2276 final float offsetX = mScrollX - child.mLeft;
2277 final float offsetY = mScrollY - child.mTop;
2278 event.offsetLocation(offsetX, offsetY);
2279 result = child.dispatchTooltipHoverEvent(event);
2280 event.offsetLocation(-offsetX, -offsetY);
2281 }
2282 return result;
2283 }
2284
2285 private void exitTooltipHoverTargets() {
2286 if (mTooltipHoveredSelf || mTooltipHoverTarget != null) {
2287 final long now = SystemClock.uptimeMillis();
2288 MotionEvent event = MotionEvent.obtain(now, now,
2289 MotionEvent.ACTION_HOVER_EXIT, 0.0f, 0.0f, 0);
2290 event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
2291 dispatchTooltipHoverEvent(event);
2292 event.recycle();
2293 }
2294 }
2295
Jeff Brown87b7f802011-06-21 18:35:45 -07002296 /** @hide */
2297 @Override
2298 protected boolean hasHoveredChild() {
2299 return mFirstHoverTarget != null;
2300 }
2301
Svetoslav Ganov42138042012-03-20 11:51:39 -07002302 @Override
Adam Powellcf392d12015-06-25 14:48:45 -07002303 public void addChildrenForAccessibility(ArrayList<View> outChildren) {
Svetoslav762621c2015-06-01 17:21:59 -07002304 if (getAccessibilityNodeProvider() != null) {
2305 return;
2306 }
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07002307 ChildListForAccessibility children = ChildListForAccessibility.obtain(this, true);
2308 try {
2309 final int childrenCount = children.getChildCount();
2310 for (int i = 0; i < childrenCount; i++) {
2311 View child = children.getChildAt(i);
Svetoslav Ganovc406be92012-05-11 16:12:32 -07002312 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07002313 if (child.includeForAccessibility()) {
Adam Powellcf392d12015-06-25 14:48:45 -07002314 outChildren.add(child);
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07002315 } else {
Adam Powellcf392d12015-06-25 14:48:45 -07002316 child.addChildrenForAccessibility(outChildren);
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07002317 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07002318 }
2319 }
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07002320 } finally {
2321 children.recycle();
Svetoslav Ganov42138042012-03-20 11:51:39 -07002322 }
2323 }
2324
2325 /**
Jeff Brown10b62902011-06-20 16:40:37 -07002326 * Implement this method to intercept hover events before they are handled
2327 * by child views.
2328 * <p>
2329 * This method is called before dispatching a hover event to a child of
2330 * the view group or to the view group's own {@link #onHoverEvent} to allow
2331 * the view group a chance to intercept the hover event.
2332 * This method can also be used to watch all pointer motions that occur within
2333 * the bounds of the view group even when the pointer is hovering over
2334 * a child of the view group rather than over the view group itself.
2335 * </p><p>
2336 * The view group can prevent its children from receiving hover events by
2337 * implementing this method and returning <code>true</code> to indicate
2338 * that it would like to intercept hover events. The view group must
2339 * continuously return <code>true</code> from {@link #onInterceptHoverEvent}
2340 * for as long as it wishes to continue intercepting hover events from
2341 * its children.
2342 * </p><p>
2343 * Interception preserves the invariant that at most one view can be
2344 * hovered at a time by transferring hover focus from the currently hovered
2345 * child to the view group or vice-versa as needed.
2346 * </p><p>
2347 * If this method returns <code>true</code> and a child is already hovered, then the
2348 * child view will first receive a hover exit event and then the view group
2349 * itself will receive a hover enter event in {@link #onHoverEvent}.
2350 * Likewise, if this method had previously returned <code>true</code> to intercept hover
2351 * events and instead returns <code>false</code> while the pointer is hovering
2352 * within the bounds of one of a child, then the view group will first receive a
2353 * hover exit event in {@link #onHoverEvent} and then the hovered child will
2354 * receive a hover enter event.
2355 * </p><p>
Keisuke Kuroyanagid85bc502016-01-21 14:50:38 +09002356 * The default implementation handles mouse hover on the scroll bars.
Jeff Brown10b62902011-06-20 16:40:37 -07002357 * </p>
2358 *
2359 * @param event The motion event that describes the hover.
2360 * @return True if the view group would like to intercept the hover event
2361 * and prevent its children from receiving it.
2362 */
2363 public boolean onInterceptHoverEvent(MotionEvent event) {
Keisuke Kuroyanagid85bc502016-01-21 14:50:38 +09002364 if (event.isFromSource(InputDevice.SOURCE_MOUSE)) {
2365 final int action = event.getAction();
2366 final float x = event.getX();
2367 final float y = event.getY();
2368 if ((action == MotionEvent.ACTION_HOVER_MOVE
2369 || action == MotionEvent.ACTION_HOVER_ENTER) && isOnScrollbar(x, y)) {
2370 return true;
2371 }
2372 }
Svetoslav Ganov736c2752011-04-22 18:30:36 -07002373 return false;
2374 }
2375
Jeff Browna032cc02011-03-07 16:56:21 -08002376 private static MotionEvent obtainMotionEventNoHistoryOrSelf(MotionEvent event) {
2377 if (event.getHistorySize() == 0) {
2378 return event;
2379 }
2380 return MotionEvent.obtainNoHistory(event);
2381 }
2382
Jeff Browna032cc02011-03-07 16:56:21 -08002383 @Override
2384 protected boolean dispatchGenericPointerEvent(MotionEvent event) {
2385 // Send the event to the child under the pointer.
2386 final int childrenCount = mChildrenCount;
2387 if (childrenCount != 0) {
Jeff Browna032cc02011-03-07 16:56:21 -08002388 final float x = event.getX();
2389 final float y = event.getY();
2390
Chris Craikab008f02014-05-23 17:55:03 -07002391 final ArrayList<View> preorderedList = buildOrderedChildList();
2392 final boolean customOrder = preorderedList == null
2393 && isChildrenDrawingOrderEnabled();
2394 final View[] children = mChildren;
Jeff Browna032cc02011-03-07 16:56:21 -08002395 for (int i = childrenCount - 1; i >= 0; i--) {
Alan Viverettea7b85e62016-01-22 10:14:02 -05002396 final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
2397 final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);
Jeff Browna032cc02011-03-07 16:56:21 -08002398 if (!canViewReceivePointerEvents(child)
2399 || !isTransformedTouchPointInView(x, y, child, null)) {
2400 continue;
2401 }
2402
2403 if (dispatchTransformedGenericPointerEvent(event, child)) {
Chris Craikab008f02014-05-23 17:55:03 -07002404 if (preorderedList != null) preorderedList.clear();
Jeff Browna032cc02011-03-07 16:56:21 -08002405 return true;
2406 }
2407 }
Chris Craikab008f02014-05-23 17:55:03 -07002408 if (preorderedList != null) preorderedList.clear();
Jeff Browna032cc02011-03-07 16:56:21 -08002409 }
2410
2411 // No child handled the event. Send it to this view group.
2412 return super.dispatchGenericPointerEvent(event);
2413 }
2414
Jeff Browna032cc02011-03-07 16:56:21 -08002415 @Override
2416 protected boolean dispatchGenericFocusedEvent(MotionEvent event) {
Jeff Brown33bbfd22011-02-24 20:55:35 -08002417 // Send the event to the focused child or to this view group if it has focus.
Dianne Hackborn4702a852012-08-17 15:18:29 -07002418 if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
2419 == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
Jeff Browna032cc02011-03-07 16:56:21 -08002420 return super.dispatchGenericFocusedEvent(event);
Dianne Hackborn4702a852012-08-17 15:18:29 -07002421 } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
2422 == PFLAG_HAS_BOUNDS) {
Jeff Browncb1404e2011-01-15 18:14:15 -08002423 return mFocused.dispatchGenericMotionEvent(event);
2424 }
2425 return false;
2426 }
2427
2428 /**
Jeff Browna032cc02011-03-07 16:56:21 -08002429 * Dispatches a generic pointer event to a child, taking into account
2430 * transformations that apply to the child.
2431 *
2432 * @param event The event to send.
2433 * @param child The view to send the event to.
2434 * @return {@code true} if the child handled the event.
2435 */
2436 private boolean dispatchTransformedGenericPointerEvent(MotionEvent event, View child) {
Jeff Browna032cc02011-03-07 16:56:21 -08002437 boolean handled;
2438 if (!child.hasIdentityMatrix()) {
Michael Wrighte051f6f2016-05-13 17:44:16 +01002439 MotionEvent transformedEvent = getTransformedMotionEvent(event, child);
Jeff Browna032cc02011-03-07 16:56:21 -08002440 handled = child.dispatchGenericMotionEvent(transformedEvent);
2441 transformedEvent.recycle();
2442 } else {
Michael Wrighte051f6f2016-05-13 17:44:16 +01002443 final float offsetX = mScrollX - child.mLeft;
2444 final float offsetY = mScrollY - child.mTop;
Jeff Browna032cc02011-03-07 16:56:21 -08002445 event.offsetLocation(offsetX, offsetY);
2446 handled = child.dispatchGenericMotionEvent(event);
2447 event.offsetLocation(-offsetX, -offsetY);
2448 }
2449 return handled;
2450 }
2451
Michael Wrighte051f6f2016-05-13 17:44:16 +01002452 /**
2453 * Returns a MotionEvent that's been transformed into the child's local coordinates.
2454 *
2455 * It's the responsibility of the caller to recycle it once they're finished with it.
2456 * @param event The event to transform.
2457 * @param child The view whose coordinate space is to be used.
2458 * @return A copy of the the given MotionEvent, transformed into the given View's coordinate
2459 * space.
2460 */
2461 private MotionEvent getTransformedMotionEvent(MotionEvent event, View child) {
2462 final float offsetX = mScrollX - child.mLeft;
2463 final float offsetY = mScrollY - child.mTop;
2464 final MotionEvent transformedEvent = MotionEvent.obtain(event);
2465 transformedEvent.offsetLocation(offsetX, offsetY);
2466 if (!child.hasIdentityMatrix()) {
2467 transformedEvent.transform(child.getInverseMatrix());
2468 }
2469 return transformedEvent;
2470 }
2471
Jeff Browncb1404e2011-01-15 18:14:15 -08002472 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002473 public boolean dispatchTouchEvent(MotionEvent ev) {
Jeff Brown21bc5c92011-02-28 18:27:14 -08002474 if (mInputEventConsistencyVerifier != null) {
2475 mInputEventConsistencyVerifier.onTouchEvent(ev, 1);
2476 }
2477
Svet Ganov0a2ccee2015-02-06 10:12:32 -08002478 // If the event targets the accessibility focused view and this is it, start
2479 // normal event dispatch. Maybe a descendant is what will handle the click.
Svet Ganovf33fe1f2015-02-06 19:23:31 -08002480 if (ev.isTargetAccessibilityFocus() && isAccessibilityFocusedViewOrHost()) {
Svet Ganov0a2ccee2015-02-06 10:12:32 -08002481 ev.setTargetAccessibilityFocus(false);
2482 }
2483
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002484 boolean handled = false;
2485 if (onFilterTouchEventForSecurity(ev)) {
2486 final int action = ev.getAction();
2487 final int actionMasked = action & MotionEvent.ACTION_MASK;
Jeff Brown85a31762010-09-01 17:01:00 -07002488
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002489 // Handle an initial down.
2490 if (actionMasked == MotionEvent.ACTION_DOWN) {
2491 // Throw away all previous state when starting a new touch gesture.
2492 // The framework may have dropped the up or cancel event for the previous gesture
2493 // due to an app switch, ANR, or some other state change.
2494 cancelAndClearTouchTargets(ev);
2495 resetTouchState();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002496 }
Adam Powellb08013c2010-09-16 16:28:11 -07002497
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002498 // Check for interception.
2499 final boolean intercepted;
Svet Ganovf33fe1f2015-02-06 19:23:31 -08002500 if (actionMasked == MotionEvent.ACTION_DOWN
2501 || mFirstTouchTarget != null) {
2502 final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
2503 if (!disallowIntercept) {
2504 intercepted = onInterceptTouchEvent(ev);
2505 ev.setAction(action); // restore action in case it was changed
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002506 } else {
Svet Ganovf33fe1f2015-02-06 19:23:31 -08002507 intercepted = false;
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002508 }
2509 } else {
Svet Ganovf33fe1f2015-02-06 19:23:31 -08002510 // There are no touch targets and this action is not an initial down
2511 // so this view group continues to intercept touches.
2512 intercepted = true;
2513 }
2514
2515 // If intercepted, start normal event dispatch. Also if there is already
2516 // a view that is handling the gesture, do normal event dispatch.
2517 if (intercepted || mFirstTouchTarget != null) {
2518 ev.setTargetAccessibilityFocus(false);
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002519 }
Jeff Brown20e987b2010-08-23 12:01:02 -07002520
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002521 // Check for cancelation.
2522 final boolean canceled = resetCancelNextUpFlag(this)
2523 || actionMasked == MotionEvent.ACTION_CANCEL;
Jeff Brown20e987b2010-08-23 12:01:02 -07002524
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002525 // Update list of touch targets for pointer down, if needed.
2526 final boolean split = (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) != 0;
2527 TouchTarget newTouchTarget = null;
2528 boolean alreadyDispatchedToNewTouchTarget = false;
2529 if (!canceled && !intercepted) {
Svetoslavc73cfa02015-02-09 17:14:28 -08002530
2531 // If the event is targeting accessiiblity focus we give it to the
2532 // view that has accessibility focus and if it does not handle it
2533 // we clear the flag and dispatch the event to all children as usual.
2534 // We are looking up the accessibility focused host to avoid keeping
2535 // state since these events are very rare.
2536 View childWithAccessibilityFocus = ev.isTargetAccessibilityFocus()
2537 ? findChildWithAccessibilityFocus() : null;
2538
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002539 if (actionMasked == MotionEvent.ACTION_DOWN
2540 || (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN)
Svet Ganovf33fe1f2015-02-06 19:23:31 -08002541 || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002542 final int actionIndex = ev.getActionIndex(); // always 0 for down
2543 final int idBitsToAssign = split ? 1 << ev.getPointerId(actionIndex)
2544 : TouchTarget.ALL_POINTER_IDS;
Jeff Brown20e987b2010-08-23 12:01:02 -07002545
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002546 // Clean up earlier touch targets for this pointer id in case they
2547 // have become out of sync.
2548 removePointersFromTouchTargets(idBitsToAssign);
2549
2550 final int childrenCount = mChildrenCount;
Chet Haase9c17fe62013-03-22 17:05:55 -07002551 if (newTouchTarget == null && childrenCount != 0) {
Chet Haaseedf6f4b2013-03-26 07:55:30 -07002552 final float x = ev.getX(actionIndex);
2553 final float y = ev.getY(actionIndex);
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002554 // Find a child that can receive the event.
2555 // Scan children from front to back.
Filip Gruszczynskia33bdf32015-11-19 18:22:16 -08002556 final ArrayList<View> preorderedList = buildTouchDispatchChildList();
Chris Craikab008f02014-05-23 17:55:03 -07002557 final boolean customOrder = preorderedList == null
2558 && isChildrenDrawingOrderEnabled();
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002559 final View[] children = mChildren;
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002560 for (int i = childrenCount - 1; i >= 0; i--) {
Alan Viverettea7b85e62016-01-22 10:14:02 -05002561 final int childIndex = getAndVerifyPreorderedIndex(
2562 childrenCount, i, customOrder);
2563 final View child = getAndVerifyPreorderedView(
2564 preorderedList, children, childIndex);
Svetoslavc73cfa02015-02-09 17:14:28 -08002565
2566 // If there is a view that has accessibility focus we want it
2567 // to get the event first and if not handled we will perform a
2568 // normal dispatch. We may do a double iteration but this is
2569 // safer given the timeframe.
2570 if (childWithAccessibilityFocus != null) {
2571 if (childWithAccessibilityFocus != child) {
2572 continue;
2573 }
2574 childWithAccessibilityFocus = null;
2575 i = childrenCount - 1;
2576 }
2577
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002578 if (!canViewReceivePointerEvents(child)
2579 || !isTransformedTouchPointInView(x, y, child, null)) {
Svetoslavc73cfa02015-02-09 17:14:28 -08002580 ev.setTargetAccessibilityFocus(false);
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002581 continue;
2582 }
2583
2584 newTouchTarget = getTouchTarget(child);
2585 if (newTouchTarget != null) {
2586 // Child is already receiving touch within its bounds.
2587 // Give it the new pointer in addition to the ones it is handling.
2588 newTouchTarget.pointerIdBits |= idBitsToAssign;
2589 break;
2590 }
2591
2592 resetCancelNextUpFlag(child);
2593 if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
2594 // Child wants to receive touch within its bounds.
2595 mLastTouchDownTime = ev.getDownTime();
Chris Craikab008f02014-05-23 17:55:03 -07002596 if (preorderedList != null) {
2597 // childIndex points into presorted list, find original index
2598 for (int j = 0; j < childrenCount; j++) {
2599 if (children[childIndex] == mChildren[j]) {
2600 mLastTouchDownIndex = j;
2601 break;
2602 }
2603 }
2604 } else {
2605 mLastTouchDownIndex = childIndex;
2606 }
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002607 mLastTouchDownX = ev.getX();
2608 mLastTouchDownY = ev.getY();
2609 newTouchTarget = addTouchTarget(child, idBitsToAssign);
2610 alreadyDispatchedToNewTouchTarget = true;
2611 break;
2612 }
Svetoslavc73cfa02015-02-09 17:14:28 -08002613
2614 // The accessibility focus didn't handle the event, so clear
2615 // the flag and do a normal dispatch to all children.
2616 ev.setTargetAccessibilityFocus(false);
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002617 }
Chris Craikab008f02014-05-23 17:55:03 -07002618 if (preorderedList != null) preorderedList.clear();
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002619 }
2620
2621 if (newTouchTarget == null && mFirstTouchTarget != null) {
2622 // Did not find a child to receive the event.
2623 // Assign the pointer to the least recently added target.
2624 newTouchTarget = mFirstTouchTarget;
2625 while (newTouchTarget.next != null) {
2626 newTouchTarget = newTouchTarget.next;
2627 }
2628 newTouchTarget.pointerIdBits |= idBitsToAssign;
2629 }
2630 }
2631 }
2632
2633 // Dispatch to touch targets.
2634 if (mFirstTouchTarget == null) {
2635 // No touch targets so treat this as an ordinary view.
2636 handled = dispatchTransformedTouchEvent(ev, canceled, null,
2637 TouchTarget.ALL_POINTER_IDS);
2638 } else {
2639 // Dispatch to touch targets, excluding the new touch target if we already
2640 // dispatched to it. Cancel touch targets if necessary.
2641 TouchTarget predecessor = null;
2642 TouchTarget target = mFirstTouchTarget;
2643 while (target != null) {
2644 final TouchTarget next = target.next;
2645 if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {
2646 handled = true;
2647 } else {
2648 final boolean cancelChild = resetCancelNextUpFlag(target.child)
Chet Haase9c17fe62013-03-22 17:05:55 -07002649 || intercepted;
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002650 if (dispatchTransformedTouchEvent(ev, cancelChild,
2651 target.child, target.pointerIdBits)) {
2652 handled = true;
2653 }
2654 if (cancelChild) {
2655 if (predecessor == null) {
2656 mFirstTouchTarget = next;
2657 } else {
2658 predecessor.next = next;
2659 }
2660 target.recycle();
2661 target = next;
Jeff Brown20e987b2010-08-23 12:01:02 -07002662 continue;
2663 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002664 }
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002665 predecessor = target;
2666 target = next;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002667 }
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002668 }
Jeff Brown20e987b2010-08-23 12:01:02 -07002669
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002670 // Update list of touch targets for pointer up or cancel, if needed.
2671 if (canceled
2672 || actionMasked == MotionEvent.ACTION_UP
2673 || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
2674 resetTouchState();
2675 } else if (split && actionMasked == MotionEvent.ACTION_POINTER_UP) {
2676 final int actionIndex = ev.getActionIndex();
2677 final int idBitsToRemove = 1 << ev.getPointerId(actionIndex);
2678 removePointersFromTouchTargets(idBitsToRemove);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002679 }
2680 }
Romain Guy8506ab42009-06-11 17:35:47 -07002681
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002682 if (!handled && mInputEventConsistencyVerifier != null) {
2683 mInputEventConsistencyVerifier.onUnhandledEvent(ev, 1);
Jeff Brown20e987b2010-08-23 12:01:02 -07002684 }
Jeff Brown20e987b2010-08-23 12:01:02 -07002685 return handled;
2686 }
2687
Romain Guy469b1db2010-10-05 11:49:57 -07002688 /**
Filip Gruszczynskia33bdf32015-11-19 18:22:16 -08002689 * Provide custom ordering of views in which the touch will be dispatched.
2690 *
2691 * This is called within a tight loop, so you are not allowed to allocate objects, including
2692 * the return array. Instead, you should return a pre-allocated list that will be cleared
2693 * after the dispatch is finished.
2694 * @hide
2695 */
2696 public ArrayList<View> buildTouchDispatchChildList() {
2697 return buildOrderedChildList();
2698 }
2699
2700 /**
Svetoslavc73cfa02015-02-09 17:14:28 -08002701 * Finds the child which has accessibility focus.
2702 *
2703 * @return The child that has focus.
2704 */
2705 private View findChildWithAccessibilityFocus() {
2706 ViewRootImpl viewRoot = getViewRootImpl();
2707 if (viewRoot == null) {
2708 return null;
2709 }
2710
2711 View current = viewRoot.getAccessibilityFocusedHost();
2712 if (current == null) {
2713 return null;
2714 }
2715
2716 ViewParent parent = current.getParent();
2717 while (parent instanceof View) {
2718 if (parent == this) {
2719 return current;
2720 }
2721 current = (View) parent;
2722 parent = current.getParent();
2723 }
2724
2725 return null;
2726 }
2727
2728 /**
Romain Guy469b1db2010-10-05 11:49:57 -07002729 * Resets all touch state in preparation for a new cycle.
2730 */
2731 private void resetTouchState() {
Jeff Brown20e987b2010-08-23 12:01:02 -07002732 clearTouchTargets();
2733 resetCancelNextUpFlag(this);
2734 mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
Adam Powell10ba2772014-04-15 09:46:51 -07002735 mNestedScrollAxes = SCROLL_AXIS_NONE;
Jeff Brown20e987b2010-08-23 12:01:02 -07002736 }
2737
Romain Guy469b1db2010-10-05 11:49:57 -07002738 /**
2739 * Resets the cancel next up flag.
2740 * Returns true if the flag was previously set.
2741 */
Alan Viverettea7b85e62016-01-22 10:14:02 -05002742 private static boolean resetCancelNextUpFlag(@NonNull View view) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07002743 if ((view.mPrivateFlags & PFLAG_CANCEL_NEXT_UP_EVENT) != 0) {
2744 view.mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT;
Jeff Brown20e987b2010-08-23 12:01:02 -07002745 return true;
Adam Cohen9b073942010-08-19 16:49:52 -07002746 }
2747 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002748 }
2749
Romain Guy469b1db2010-10-05 11:49:57 -07002750 /**
2751 * Clears all touch targets.
2752 */
2753 private void clearTouchTargets() {
Jeff Brown20e987b2010-08-23 12:01:02 -07002754 TouchTarget target = mFirstTouchTarget;
2755 if (target != null) {
2756 do {
2757 TouchTarget next = target.next;
2758 target.recycle();
2759 target = next;
2760 } while (target != null);
2761 mFirstTouchTarget = null;
2762 }
2763 }
2764
Romain Guy469b1db2010-10-05 11:49:57 -07002765 /**
2766 * Cancels and clears all touch targets.
2767 */
2768 private void cancelAndClearTouchTargets(MotionEvent event) {
Jeff Brown20e987b2010-08-23 12:01:02 -07002769 if (mFirstTouchTarget != null) {
2770 boolean syntheticEvent = false;
2771 if (event == null) {
2772 final long now = SystemClock.uptimeMillis();
2773 event = MotionEvent.obtain(now, now,
2774 MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
Jeff Brown2fdbc5a2011-06-30 12:25:54 -07002775 event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
Jeff Brown20e987b2010-08-23 12:01:02 -07002776 syntheticEvent = true;
2777 }
2778
2779 for (TouchTarget target = mFirstTouchTarget; target != null; target = target.next) {
2780 resetCancelNextUpFlag(target.child);
2781 dispatchTransformedTouchEvent(event, true, target.child, target.pointerIdBits);
2782 }
2783 clearTouchTargets();
2784
2785 if (syntheticEvent) {
2786 event.recycle();
2787 }
2788 }
2789 }
2790
Romain Guy469b1db2010-10-05 11:49:57 -07002791 /**
2792 * Gets the touch target for specified child view.
2793 * Returns null if not found.
2794 */
Alan Viverettea7b85e62016-01-22 10:14:02 -05002795 private TouchTarget getTouchTarget(@NonNull View child) {
Jeff Brown20e987b2010-08-23 12:01:02 -07002796 for (TouchTarget target = mFirstTouchTarget; target != null; target = target.next) {
2797 if (target.child == child) {
2798 return target;
2799 }
2800 }
2801 return null;
2802 }
2803
Romain Guy469b1db2010-10-05 11:49:57 -07002804 /**
2805 * Adds a touch target for specified child to the beginning of the list.
2806 * Assumes the target child is not already present.
2807 */
Alan Viverettea7b85e62016-01-22 10:14:02 -05002808 private TouchTarget addTouchTarget(@NonNull View child, int pointerIdBits) {
2809 final TouchTarget target = TouchTarget.obtain(child, pointerIdBits);
Jeff Brown20e987b2010-08-23 12:01:02 -07002810 target.next = mFirstTouchTarget;
2811 mFirstTouchTarget = target;
2812 return target;
2813 }
2814
Romain Guy469b1db2010-10-05 11:49:57 -07002815 /**
2816 * Removes the pointer ids from consideration.
2817 */
2818 private void removePointersFromTouchTargets(int pointerIdBits) {
Jeff Brown20e987b2010-08-23 12:01:02 -07002819 TouchTarget predecessor = null;
2820 TouchTarget target = mFirstTouchTarget;
2821 while (target != null) {
2822 final TouchTarget next = target.next;
2823 if ((target.pointerIdBits & pointerIdBits) != 0) {
2824 target.pointerIdBits &= ~pointerIdBits;
2825 if (target.pointerIdBits == 0) {
2826 if (predecessor == null) {
2827 mFirstTouchTarget = next;
2828 } else {
2829 predecessor.next = next;
2830 }
2831 target.recycle();
2832 target = next;
2833 continue;
2834 }
2835 }
2836 predecessor = target;
2837 target = next;
2838 }
2839 }
2840
Jeff Brown59a422e2012-04-19 15:19:19 -07002841 private void cancelTouchTarget(View view) {
2842 TouchTarget predecessor = null;
2843 TouchTarget target = mFirstTouchTarget;
2844 while (target != null) {
2845 final TouchTarget next = target.next;
2846 if (target.child == view) {
2847 if (predecessor == null) {
2848 mFirstTouchTarget = next;
2849 } else {
2850 predecessor.next = next;
2851 }
2852 target.recycle();
2853
2854 final long now = SystemClock.uptimeMillis();
2855 MotionEvent event = MotionEvent.obtain(now, now,
2856 MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
2857 event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
2858 view.dispatchTouchEvent(event);
2859 event.recycle();
2860 return;
2861 }
2862 predecessor = target;
2863 target = next;
2864 }
2865 }
2866
Romain Guy469b1db2010-10-05 11:49:57 -07002867 /**
Jeff Browna032cc02011-03-07 16:56:21 -08002868 * Returns true if a child view can receive pointer events.
2869 * @hide
2870 */
Alan Viverettea7b85e62016-01-22 10:14:02 -05002871 private static boolean canViewReceivePointerEvents(@NonNull View child) {
Jeff Browna032cc02011-03-07 16:56:21 -08002872 return (child.mViewFlags & VISIBILITY_MASK) == VISIBLE
2873 || child.getAnimation() != null;
2874 }
2875
Alan Viveretteb942b6f2014-12-08 10:37:39 -08002876 private float[] getTempPoint() {
2877 if (mTempPoint == null) {
2878 mTempPoint = new float[2];
2879 }
2880 return mTempPoint;
2881 }
2882
Jeff Browna032cc02011-03-07 16:56:21 -08002883 /**
Romain Guy469b1db2010-10-05 11:49:57 -07002884 * Returns true if a child view contains the specified point when transformed
Jeff Brown20e987b2010-08-23 12:01:02 -07002885 * into its coordinate space.
Romain Guy469b1db2010-10-05 11:49:57 -07002886 * Child must not be null.
Adam Cohena32edd42010-10-26 10:35:01 -07002887 * @hide
Romain Guy469b1db2010-10-05 11:49:57 -07002888 */
Adam Cohena32edd42010-10-26 10:35:01 -07002889 protected boolean isTransformedTouchPointInView(float x, float y, View child,
Christopher Tate2c095f32010-10-04 14:13:40 -07002890 PointF outLocalPoint) {
Alan Viveretteb942b6f2014-12-08 10:37:39 -08002891 final float[] point = getTempPoint();
2892 point[0] = x;
2893 point[1] = y;
2894 transformPointToViewLocal(point, child);
2895 final boolean isInView = child.pointInView(point[0], point[1]);
Christopher Tate2c095f32010-10-04 14:13:40 -07002896 if (isInView && outLocalPoint != null) {
Alan Viveretteb942b6f2014-12-08 10:37:39 -08002897 outLocalPoint.set(point[0], point[1]);
Christopher Tate2c095f32010-10-04 14:13:40 -07002898 }
2899 return isInView;
Adam Powell2b342f02010-08-18 18:14:13 -07002900 }
2901
Romain Guy469b1db2010-10-05 11:49:57 -07002902 /**
Alan Viveretteb942b6f2014-12-08 10:37:39 -08002903 * @hide
2904 */
2905 public void transformPointToViewLocal(float[] point, View child) {
2906 point[0] += mScrollX - child.mLeft;
2907 point[1] += mScrollY - child.mTop;
2908
2909 if (!child.hasIdentityMatrix()) {
2910 child.getInverseMatrix().mapPoints(point);
2911 }
2912 }
2913
2914 /**
Romain Guy469b1db2010-10-05 11:49:57 -07002915 * Transforms a motion event into the coordinate space of a particular child view,
Jeff Brown20e987b2010-08-23 12:01:02 -07002916 * filters out irrelevant pointer ids, and overrides its action if necessary.
Romain Guy469b1db2010-10-05 11:49:57 -07002917 * If child is null, assumes the MotionEvent will be sent to this ViewGroup instead.
2918 */
2919 private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,
Jeff Brown20e987b2010-08-23 12:01:02 -07002920 View child, int desiredPointerIdBits) {
2921 final boolean handled;
Adam Powell2b342f02010-08-18 18:14:13 -07002922
Jeff Brown20e987b2010-08-23 12:01:02 -07002923 // Canceling motions is a special case. We don't need to perform any transformations
2924 // or filtering. The important part is the action, not the contents.
2925 final int oldAction = event.getAction();
2926 if (cancel || oldAction == MotionEvent.ACTION_CANCEL) {
2927 event.setAction(MotionEvent.ACTION_CANCEL);
2928 if (child == null) {
2929 handled = super.dispatchTouchEvent(event);
2930 } else {
2931 handled = child.dispatchTouchEvent(event);
2932 }
2933 event.setAction(oldAction);
2934 return handled;
2935 }
Adam Powell2b342f02010-08-18 18:14:13 -07002936
Jeff Brown20e987b2010-08-23 12:01:02 -07002937 // Calculate the number of pointers to deliver.
Jeff Brownfe9f8ab2011-05-06 18:20:01 -07002938 final int oldPointerIdBits = event.getPointerIdBits();
2939 final int newPointerIdBits = oldPointerIdBits & desiredPointerIdBits;
Adam Powell2b342f02010-08-18 18:14:13 -07002940
Jeff Brown20e987b2010-08-23 12:01:02 -07002941 // If for some reason we ended up in an inconsistent state where it looks like we
2942 // might produce a motion event with no pointers in it, then drop the event.
Jeff Brownfe9f8ab2011-05-06 18:20:01 -07002943 if (newPointerIdBits == 0) {
Jeff Brown20e987b2010-08-23 12:01:02 -07002944 return false;
2945 }
Adam Powell2b342f02010-08-18 18:14:13 -07002946
Jeff Brown20e987b2010-08-23 12:01:02 -07002947 // If the number of pointers is the same and we don't need to perform any fancy
2948 // irreversible transformations, then we can reuse the motion event for this
2949 // dispatch as long as we are careful to revert any changes we make.
Jeff Brownfe9f8ab2011-05-06 18:20:01 -07002950 // Otherwise we need to make a copy.
2951 final MotionEvent transformedEvent;
2952 if (newPointerIdBits == oldPointerIdBits) {
2953 if (child == null || child.hasIdentityMatrix()) {
2954 if (child == null) {
2955 handled = super.dispatchTouchEvent(event);
2956 } else {
2957 final float offsetX = mScrollX - child.mLeft;
2958 final float offsetY = mScrollY - child.mTop;
2959 event.offsetLocation(offsetX, offsetY);
Adam Powell2b342f02010-08-18 18:14:13 -07002960
Jeff Brownfe9f8ab2011-05-06 18:20:01 -07002961 handled = child.dispatchTouchEvent(event);
Jeff Brown20e987b2010-08-23 12:01:02 -07002962
Jeff Brownfe9f8ab2011-05-06 18:20:01 -07002963 event.offsetLocation(-offsetX, -offsetY);
2964 }
2965 return handled;
Jeff Brown20e987b2010-08-23 12:01:02 -07002966 }
Jeff Brown20e987b2010-08-23 12:01:02 -07002967 transformedEvent = MotionEvent.obtain(event);
2968 } else {
Jeff Brownfe9f8ab2011-05-06 18:20:01 -07002969 transformedEvent = event.split(newPointerIdBits);
Adam Powell2b342f02010-08-18 18:14:13 -07002970 }
2971
Jeff Brown20e987b2010-08-23 12:01:02 -07002972 // Perform any necessary transformations and dispatch.
2973 if (child == null) {
2974 handled = super.dispatchTouchEvent(transformedEvent);
2975 } else {
2976 final float offsetX = mScrollX - child.mLeft;
2977 final float offsetY = mScrollY - child.mTop;
2978 transformedEvent.offsetLocation(offsetX, offsetY);
2979 if (! child.hasIdentityMatrix()) {
2980 transformedEvent.transform(child.getInverseMatrix());
Adam Powell2b342f02010-08-18 18:14:13 -07002981 }
2982
Jeff Brown20e987b2010-08-23 12:01:02 -07002983 handled = child.dispatchTouchEvent(transformedEvent);
Adam Powell2b342f02010-08-18 18:14:13 -07002984 }
2985
Jeff Brown20e987b2010-08-23 12:01:02 -07002986 // Done.
2987 transformedEvent.recycle();
Adam Powell2b342f02010-08-18 18:14:13 -07002988 return handled;
2989 }
2990
Romain Guy469b1db2010-10-05 11:49:57 -07002991 /**
Adam Powell2b342f02010-08-18 18:14:13 -07002992 * Enable or disable the splitting of MotionEvents to multiple children during touch event
Jeff Brown995e7742010-12-22 16:59:36 -08002993 * dispatch. This behavior is enabled by default for applications that target an
2994 * SDK version of {@link Build.VERSION_CODES#HONEYCOMB} or newer.
Adam Powell2b342f02010-08-18 18:14:13 -07002995 *
2996 * <p>When this option is enabled MotionEvents may be split and dispatched to different child
2997 * views depending on where each pointer initially went down. This allows for user interactions
2998 * such as scrolling two panes of content independently, chording of buttons, and performing
2999 * independent gestures on different pieces of content.
3000 *
3001 * @param split <code>true</code> to allow MotionEvents to be split and dispatched to multiple
3002 * child views. <code>false</code> to only allow one child view to be the target of
3003 * any MotionEvent received by this ViewGroup.
Scott Main27a85082013-06-10 10:39:48 -07003004 * @attr ref android.R.styleable#ViewGroup_splitMotionEvents
Adam Powell2b342f02010-08-18 18:14:13 -07003005 */
3006 public void setMotionEventSplittingEnabled(boolean split) {
3007 // TODO Applications really shouldn't change this setting mid-touch event,
3008 // but perhaps this should handle that case and send ACTION_CANCELs to any child views
3009 // with gestures in progress when this is changed.
3010 if (split) {
Adam Powell2b342f02010-08-18 18:14:13 -07003011 mGroupFlags |= FLAG_SPLIT_MOTION_EVENTS;
3012 } else {
3013 mGroupFlags &= ~FLAG_SPLIT_MOTION_EVENTS;
Adam Powell2b342f02010-08-18 18:14:13 -07003014 }
3015 }
3016
3017 /**
Jeff Brown995e7742010-12-22 16:59:36 -08003018 * Returns true if MotionEvents dispatched to this ViewGroup can be split to multiple children.
Adam Powell2b342f02010-08-18 18:14:13 -07003019 * @return true if MotionEvents dispatched to this ViewGroup can be split to multiple children.
3020 */
3021 public boolean isMotionEventSplittingEnabled() {
3022 return (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) == FLAG_SPLIT_MOTION_EVENTS;
3023 }
3024
3025 /**
George Mount0a778ed2013-12-13 13:35:36 -08003026 * Returns true if this ViewGroup should be considered as a single entity for removal
3027 * when executing an Activity transition. If this is false, child elements will move
3028 * individually during the transition.
George Mount427c6412014-11-05 16:45:36 -08003029 *
George Mount0a778ed2013-12-13 13:35:36 -08003030 * @return True if the ViewGroup should be acted on together during an Activity transition.
George Mount427c6412014-11-05 16:45:36 -08003031 * The default value is true when there is a non-null background or if
3032 * {@link #getTransitionName()} is not null or if a
3033 * non-null {@link android.view.ViewOutlineProvider} other than
3034 * {@link android.view.ViewOutlineProvider#BACKGROUND} was given to
3035 * {@link #setOutlineProvider(ViewOutlineProvider)} and false otherwise.
George Mount0a778ed2013-12-13 13:35:36 -08003036 */
3037 public boolean isTransitionGroup() {
3038 if ((mGroupFlags & FLAG_IS_TRANSITION_GROUP_SET) != 0) {
3039 return ((mGroupFlags & FLAG_IS_TRANSITION_GROUP) != 0);
3040 } else {
George Mount427c6412014-11-05 16:45:36 -08003041 final ViewOutlineProvider outlineProvider = getOutlineProvider();
3042 return getBackground() != null || getTransitionName() != null ||
3043 (outlineProvider != null && outlineProvider != ViewOutlineProvider.BACKGROUND);
George Mount0a778ed2013-12-13 13:35:36 -08003044 }
3045 }
3046
3047 /**
3048 * Changes whether or not this ViewGroup should be treated as a single entity during
George Mount31a21722014-03-24 17:44:36 -07003049 * Activity Transitions.
George Mount0a778ed2013-12-13 13:35:36 -08003050 * @param isTransitionGroup Whether or not the ViewGroup should be treated as a unit
3051 * in Activity transitions. If false, the ViewGroup won't transition,
3052 * only its children. If true, the entire ViewGroup will transition
3053 * together.
George Mount62ab9b72014-05-02 13:51:17 -07003054 * @see android.app.ActivityOptions#makeSceneTransitionAnimation(android.app.Activity,
3055 * android.util.Pair[])
George Mount0a778ed2013-12-13 13:35:36 -08003056 */
3057 public void setTransitionGroup(boolean isTransitionGroup) {
3058 mGroupFlags |= FLAG_IS_TRANSITION_GROUP_SET;
3059 if (isTransitionGroup) {
3060 mGroupFlags |= FLAG_IS_TRANSITION_GROUP;
3061 } else {
3062 mGroupFlags &= ~FLAG_IS_TRANSITION_GROUP;
3063 }
3064 }
3065
Alan Viverettebe463f22016-01-21 10:50:10 -05003066 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003067 public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
Romain Guy8506ab42009-06-11 17:35:47 -07003068
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003069 if (disallowIntercept == ((mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0)) {
3070 // We're already in this state, assume our ancestors are too
3071 return;
3072 }
Romain Guy8506ab42009-06-11 17:35:47 -07003073
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003074 if (disallowIntercept) {
3075 mGroupFlags |= FLAG_DISALLOW_INTERCEPT;
3076 } else {
3077 mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
3078 }
Romain Guy8506ab42009-06-11 17:35:47 -07003079
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003080 // Pass it up to our parent
3081 if (mParent != null) {
3082 mParent.requestDisallowInterceptTouchEvent(disallowIntercept);
3083 }
3084 }
3085
3086 /**
3087 * Implement this method to intercept all touch screen motion events. This
3088 * allows you to watch events as they are dispatched to your children, and
3089 * take ownership of the current gesture at any point.
3090 *
3091 * <p>Using this function takes some care, as it has a fairly complicated
3092 * interaction with {@link View#onTouchEvent(MotionEvent)
3093 * View.onTouchEvent(MotionEvent)}, and using it requires implementing
3094 * that method as well as this one in the correct way. Events will be
3095 * received in the following order:
3096 *
3097 * <ol>
3098 * <li> You will receive the down event here.
3099 * <li> The down event will be handled either by a child of this view
3100 * group, or given to your own onTouchEvent() method to handle; this means
3101 * you should implement onTouchEvent() to return true, so you will
3102 * continue to see the rest of the gesture (instead of looking for
3103 * a parent view to handle it). Also, by returning true from
3104 * onTouchEvent(), you will not receive any following
3105 * events in onInterceptTouchEvent() and all touch processing must
3106 * happen in onTouchEvent() like normal.
3107 * <li> For as long as you return false from this function, each following
3108 * event (up to and including the final up) will be delivered first here
3109 * and then to the target's onTouchEvent().
3110 * <li> If you return true from here, you will not receive any
3111 * following events: the target view will receive the same event but
3112 * with the action {@link MotionEvent#ACTION_CANCEL}, and all further
3113 * events will be delivered to your onTouchEvent() method and no longer
3114 * appear here.
3115 * </ol>
3116 *
3117 * @param ev The motion event being dispatched down the hierarchy.
3118 * @return Return true to steal motion events from the children and have
3119 * them dispatched to this ViewGroup through onTouchEvent().
3120 * The current target will receive an ACTION_CANCEL event, and no further
3121 * messages will be delivered here.
3122 */
3123 public boolean onInterceptTouchEvent(MotionEvent ev) {
Keisuke Kuroyanagid85bc502016-01-21 14:50:38 +09003124 if (ev.isFromSource(InputDevice.SOURCE_MOUSE)
3125 && ev.getAction() == MotionEvent.ACTION_DOWN
3126 && ev.isButtonPressed(MotionEvent.BUTTON_PRIMARY)
3127 && isOnScrollbarThumb(ev.getX(), ev.getY())) {
3128 return true;
3129 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003130 return false;
3131 }
3132
3133 /**
3134 * {@inheritDoc}
3135 *
3136 * Looks for a view to give focus to respecting the setting specified by
3137 * {@link #getDescendantFocusability()}.
3138 *
3139 * Uses {@link #onRequestFocusInDescendants(int, android.graphics.Rect)} to
3140 * find focus within the children of this group when appropriate.
3141 *
3142 * @see #FOCUS_BEFORE_DESCENDANTS
3143 * @see #FOCUS_AFTER_DESCENDANTS
3144 * @see #FOCUS_BLOCK_DESCENDANTS
Filip Gruszczynskia33bdf32015-11-19 18:22:16 -08003145 * @see #onRequestFocusInDescendants(int, android.graphics.Rect)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003146 */
3147 @Override
3148 public boolean requestFocus(int direction, Rect previouslyFocusedRect) {
3149 if (DBG) {
3150 System.out.println(this + " ViewGroup.requestFocus direction="
3151 + direction);
3152 }
3153 int descendantFocusability = getDescendantFocusability();
3154
3155 switch (descendantFocusability) {
3156 case FOCUS_BLOCK_DESCENDANTS:
3157 return super.requestFocus(direction, previouslyFocusedRect);
3158 case FOCUS_BEFORE_DESCENDANTS: {
3159 final boolean took = super.requestFocus(direction, previouslyFocusedRect);
3160 return took ? took : onRequestFocusInDescendants(direction, previouslyFocusedRect);
3161 }
3162 case FOCUS_AFTER_DESCENDANTS: {
3163 final boolean took = onRequestFocusInDescendants(direction, previouslyFocusedRect);
3164 return took ? took : super.requestFocus(direction, previouslyFocusedRect);
3165 }
3166 default:
3167 throw new IllegalStateException("descendant focusability must be "
3168 + "one of FOCUS_BEFORE_DESCENDANTS, FOCUS_AFTER_DESCENDANTS, FOCUS_BLOCK_DESCENDANTS "
3169 + "but is " + descendantFocusability);
3170 }
3171 }
3172
3173 /**
3174 * Look for a descendant to call {@link View#requestFocus} on.
3175 * Called by {@link ViewGroup#requestFocus(int, android.graphics.Rect)}
3176 * when it wants to request focus within its children. Override this to
3177 * customize how your {@link ViewGroup} requests focus within its children.
3178 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT
3179 * @param previouslyFocusedRect The rectangle (in this View's coordinate system)
3180 * to give a finer grained hint about where focus is coming from. May be null
3181 * if there is no hint.
3182 * @return Whether focus was taken.
3183 */
3184 @SuppressWarnings({"ConstantConditions"})
3185 protected boolean onRequestFocusInDescendants(int direction,
3186 Rect previouslyFocusedRect) {
3187 int index;
3188 int increment;
3189 int end;
3190 int count = mChildrenCount;
3191 if ((direction & FOCUS_FORWARD) != 0) {
3192 index = 0;
3193 increment = 1;
3194 end = count;
3195 } else {
3196 index = count - 1;
3197 increment = -1;
3198 end = -1;
3199 }
3200 final View[] children = mChildren;
3201 for (int i = index; i != end; i += increment) {
3202 View child = children[i];
Vadim Tryshevb5ced222017-01-17 19:31:35 -08003203 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003204 if (child.requestFocus(direction, previouslyFocusedRect)) {
3205 return true;
3206 }
3207 }
3208 }
3209 return false;
3210 }
Chet Haase5c13d892010-10-08 08:37:55 -07003211
Vadim Tryshev01d8c492016-12-15 11:33:15 -08003212 @Override
Evan Rosky53fcf112017-01-26 14:37:55 -08003213 public boolean restoreDefaultFocus() {
3214 if (mDefaultFocus != null
Vadim Tryshev01d8c492016-12-15 11:33:15 -08003215 && getDescendantFocusability() != FOCUS_BLOCK_DESCENDANTS
Vadim Tryshev5ca73982017-01-04 17:24:43 -08003216 && (mDefaultFocus.mViewFlags & VISIBILITY_MASK) == VISIBLE
Evan Rosky53fcf112017-01-26 14:37:55 -08003217 && mDefaultFocus.restoreDefaultFocus()) {
Vadim Tryshev01d8c492016-12-15 11:33:15 -08003218 return true;
3219 }
Evan Rosky53fcf112017-01-26 14:37:55 -08003220 return super.restoreDefaultFocus();
3221 }
3222
3223 /**
3224 * @hide
3225 */
Evan Rosky3ac64632017-02-13 18:04:43 -08003226 @TestApi
Evan Rosky53fcf112017-01-26 14:37:55 -08003227 @Override
3228 public boolean restoreFocusInCluster(@FocusRealDirection int direction) {
Evan Rosky18b886e2017-02-15 13:26:51 -08003229 // Allow cluster-navigation to enter touchscreenBlocksFocus ViewGroups.
3230 if (isKeyboardNavigationCluster()) {
3231 final boolean blockedFocus = getTouchscreenBlocksFocus();
3232 try {
3233 setTouchscreenBlocksFocusNoRefocus(false);
3234 return restoreFocusInClusterInternal(direction);
3235 } finally {
3236 setTouchscreenBlocksFocusNoRefocus(blockedFocus);
3237 }
3238 } else {
3239 return restoreFocusInClusterInternal(direction);
3240 }
3241 }
3242
3243 private boolean restoreFocusInClusterInternal(@FocusRealDirection int direction) {
Evan Rosky0e8a6832017-04-10 12:35:15 -07003244 if (mFocusedInCluster != null && getDescendantFocusability() != FOCUS_BLOCK_DESCENDANTS
Evan Rosky53fcf112017-01-26 14:37:55 -08003245 && (mFocusedInCluster.mViewFlags & VISIBILITY_MASK) == VISIBLE
3246 && mFocusedInCluster.restoreFocusInCluster(direction)) {
3247 return true;
3248 }
3249 return super.restoreFocusInCluster(direction);
Vadim Tryshev01d8c492016-12-15 11:33:15 -08003250 }
3251
Romain Guya440b002010-02-24 15:57:54 -08003252 /**
Evan Rosky3ac64632017-02-13 18:04:43 -08003253 * @hide
3254 */
3255 @Override
3256 public boolean restoreFocusNotInCluster() {
3257 if (mFocusedInCluster != null) {
3258 // since clusters don't nest; we can assume that a non-null mFocusedInCluster
3259 // will refer to a view not-in a cluster.
3260 return restoreFocusInCluster(View.FOCUS_DOWN);
3261 }
Evan Rosky2ae1bf52017-05-11 11:18:45 -07003262 if (isKeyboardNavigationCluster() || (mViewFlags & VISIBILITY_MASK) != VISIBLE) {
Evan Rosky3ac64632017-02-13 18:04:43 -08003263 return false;
3264 }
3265 int descendentFocusability = getDescendantFocusability();
3266 if (descendentFocusability == FOCUS_BLOCK_DESCENDANTS) {
3267 return super.requestFocus(FOCUS_DOWN, null);
3268 }
3269 if (descendentFocusability == FOCUS_BEFORE_DESCENDANTS
3270 && super.requestFocus(FOCUS_DOWN, null)) {
3271 return true;
3272 }
3273 for (int i = 0; i < mChildrenCount; ++i) {
3274 View child = mChildren[i];
3275 if (!child.isKeyboardNavigationCluster()
3276 && child.restoreFocusNotInCluster()) {
3277 return true;
3278 }
3279 }
Evan Rosky2ae1bf52017-05-11 11:18:45 -07003280 if (descendentFocusability == FOCUS_AFTER_DESCENDANTS && !hasFocusableChild(false)) {
Evan Rosky3ac64632017-02-13 18:04:43 -08003281 return super.requestFocus(FOCUS_DOWN, null);
3282 }
3283 return false;
3284 }
3285
3286 /**
Romain Guya440b002010-02-24 15:57:54 -08003287 * {@inheritDoc}
Chet Haase5c13d892010-10-08 08:37:55 -07003288 *
Romain Guydcc490f2010-02-24 17:59:35 -08003289 * @hide
Romain Guya440b002010-02-24 15:57:54 -08003290 */
3291 @Override
3292 public void dispatchStartTemporaryDetach() {
3293 super.dispatchStartTemporaryDetach();
3294 final int count = mChildrenCount;
3295 final View[] children = mChildren;
3296 for (int i = 0; i < count; i++) {
3297 children[i].dispatchStartTemporaryDetach();
3298 }
3299 }
Chet Haase5c13d892010-10-08 08:37:55 -07003300
Romain Guya440b002010-02-24 15:57:54 -08003301 /**
3302 * {@inheritDoc}
Chet Haase5c13d892010-10-08 08:37:55 -07003303 *
Romain Guydcc490f2010-02-24 17:59:35 -08003304 * @hide
Romain Guya440b002010-02-24 15:57:54 -08003305 */
3306 @Override
3307 public void dispatchFinishTemporaryDetach() {
3308 super.dispatchFinishTemporaryDetach();
3309 final int count = mChildrenCount;
3310 final View[] children = mChildren;
3311 for (int i = 0; i < count; i++) {
3312 children[i].dispatchFinishTemporaryDetach();
3313 }
3314 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003315
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003316 @Override
3317 void dispatchAttachedToWindow(AttachInfo info, int visibility) {
Adam Powell4b867882011-09-16 12:59:46 -07003318 mGroupFlags |= FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003319 super.dispatchAttachedToWindow(info, visibility);
Adam Powell4b867882011-09-16 12:59:46 -07003320 mGroupFlags &= ~FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW;
3321
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003322 final int count = mChildrenCount;
3323 final View[] children = mChildren;
3324 for (int i = 0; i < count; i++) {
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07003325 final View child = children[i];
3326 child.dispatchAttachedToWindow(info,
Adam Powelleb2b0af2015-05-20 18:26:35 -07003327 combineVisibility(visibility, child.getVisibility()));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003328 }
Chet Haasec633d2f2015-04-07 10:29:39 -07003329 final int transientCount = mTransientIndices == null ? 0 : mTransientIndices.size();
3330 for (int i = 0; i < transientCount; ++i) {
3331 View view = mTransientViews.get(i);
Adam Powelleb2b0af2015-05-20 18:26:35 -07003332 view.dispatchAttachedToWindow(info,
3333 combineVisibility(visibility, view.getVisibility()));
Chet Haasec633d2f2015-04-07 10:29:39 -07003334 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003335 }
3336
svetoslavganov75986cf2009-05-14 22:28:01 -07003337 @Override
Romain Guybb9908b2012-03-08 11:14:07 -08003338 void dispatchScreenStateChanged(int screenState) {
3339 super.dispatchScreenStateChanged(screenState);
3340
3341 final int count = mChildrenCount;
3342 final View[] children = mChildren;
3343 for (int i = 0; i < count; i++) {
3344 children[i].dispatchScreenStateChanged(screenState);
3345 }
3346 }
3347
Andrii Kulianb047b8b2017-02-08 18:38:26 -08003348 @Override
Andrii Kuliane5c58ee2017-03-27 19:25:24 -07003349 void dispatchMovedToDisplay(Display display, Configuration config) {
3350 super.dispatchMovedToDisplay(display, config);
Andrii Kulianb047b8b2017-02-08 18:38:26 -08003351
3352 final int count = mChildrenCount;
3353 final View[] children = mChildren;
3354 for (int i = 0; i < count; i++) {
Andrii Kuliane5c58ee2017-03-27 19:25:24 -07003355 children[i].dispatchMovedToDisplay(display, config);
Andrii Kulianb047b8b2017-02-08 18:38:26 -08003356 }
3357 }
3358
Alan Viverettea54956a2015-01-07 16:05:02 -08003359 /** @hide */
Romain Guybb9908b2012-03-08 11:14:07 -08003360 @Override
Alan Viverettea54956a2015-01-07 16:05:02 -08003361 public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07003362 boolean handled = false;
3363 if (includeForAccessibility()) {
3364 handled = super.dispatchPopulateAccessibilityEventInternal(event);
3365 if (handled) {
3366 return handled;
3367 }
Svetoslav Ganovb84b94e2011-09-22 19:26:56 -07003368 }
Svetoslav Ganov736c2752011-04-22 18:30:36 -07003369 // Let our children have a shot in populating the event.
Svetoslav Ganov42138042012-03-20 11:51:39 -07003370 ChildListForAccessibility children = ChildListForAccessibility.obtain(this, true);
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07003371 try {
3372 final int childCount = children.getChildCount();
3373 for (int i = 0; i < childCount; i++) {
3374 View child = children.getChildAt(i);
3375 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
3376 handled = child.dispatchPopulateAccessibilityEvent(event);
3377 if (handled) {
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07003378 return handled;
3379 }
Svetoslav Ganov6179ea32011-06-28 01:12:41 -07003380 }
Svetoslav Ganov736c2752011-04-22 18:30:36 -07003381 }
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07003382 } finally {
3383 children.recycle();
svetoslavganov75986cf2009-05-14 22:28:01 -07003384 }
Svetoslav Ganov736c2752011-04-22 18:30:36 -07003385 return false;
svetoslavganov75986cf2009-05-14 22:28:01 -07003386 }
3387
Dianne Hackborn6251f0d2015-04-01 16:45:03 -07003388 /**
Felipe Leme6d553872016-12-08 17:13:25 -08003389 * Dispatch creation of {@link ViewStructure} down the hierarchy. This implementation
3390 * adds in all child views of the view group, in addition to calling the default View
3391 * implementation.
3392 */
3393 @Override
3394 public void dispatchProvideStructure(ViewStructure structure) {
3395 super.dispatchProvideStructure(structure);
Svet Ganov2f8fb1f2017-03-13 00:21:04 -07003396 if (isAssistBlocked() || structure.getChildCount() != 0) {
3397 return;
3398 }
3399 final int childrenCount = mChildrenCount;
3400 if (childrenCount <= 0) {
3401 return;
3402 }
3403 structure.setChildCount(childrenCount);
3404 ArrayList<View> preorderedList = buildOrderedChildList();
3405 boolean customOrder = preorderedList == null
3406 && isChildrenDrawingOrderEnabled();
3407 for (int i = 0; i < childrenCount; i++) {
3408 int childIndex;
3409 try {
3410 childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
3411 } catch (IndexOutOfBoundsException e) {
3412 childIndex = i;
3413 if (mContext.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.M) {
3414 Log.w(TAG, "Bad getChildDrawingOrder while collecting assist @ "
3415 + i + " of " + childrenCount, e);
3416 // At least one app is failing when we call getChildDrawingOrder
3417 // at this point, so deal semi-gracefully with it by falling back
3418 // on the basic order.
3419 customOrder = false;
3420 if (i > 0) {
3421 // If we failed at the first index, there really isn't
3422 // anything to do -- we will just proceed with the simple
3423 // sequence order.
3424 // Otherwise, we failed in the middle, so need to come up
3425 // with an order for the remaining indices and use that.
3426 // Failed at the first one, easy peasy.
3427 int[] permutation = new int[childrenCount];
3428 SparseBooleanArray usedIndices = new SparseBooleanArray();
3429 // Go back and collected the indices we have done so far.
3430 for (int j = 0; j < i; j++) {
3431 permutation[j] = getChildDrawingOrder(childrenCount, j);
3432 usedIndices.put(permutation[j], true);
3433 }
3434 // Fill in the remaining indices with indices that have not
3435 // yet been used.
3436 int nextIndex = 0;
3437 for (int j = i; j < childrenCount; j++) {
3438 while (usedIndices.get(nextIndex, false)) {
3439 nextIndex++;
3440 }
3441 permutation[j] = nextIndex;
3442 nextIndex++;
3443 }
3444 // Build the final view list.
3445 preorderedList = new ArrayList<>(childrenCount);
3446 for (int j = 0; j < childrenCount; j++) {
3447 final int index = permutation[j];
3448 final View child = mChildren[index];
3449 preorderedList.add(child);
3450 }
3451 }
3452 } else {
3453 throw e;
3454 }
3455 }
3456 final View child = getAndVerifyPreorderedView(preorderedList, mChildren,
3457 childIndex);
3458 final ViewStructure cstructure = structure.newChild(i);
3459 child.dispatchProvideStructure(cstructure);
3460 }
3461 if (preorderedList != null) {
3462 preorderedList.clear();
3463 }
Felipe Leme6d553872016-12-08 17:13:25 -08003464 }
3465
3466 /**
Felipe Leme1ca634a2016-11-28 17:21:21 -08003467 * {@inheritDoc}
3468 *
3469 * <p>This implementation adds in all child views of the view group, in addition to calling the
3470 * default {@link View} implementation.
Dianne Hackborn6251f0d2015-04-01 16:45:03 -07003471 */
Alan Viverettebe463f22016-01-21 10:50:10 -05003472 @Override
Svet Ganovfd31f852017-04-26 15:54:27 -07003473 public void dispatchProvideAutofillStructure(ViewStructure structure,
3474 @AutofillFlags int flags) {
Felipe Leme640f30a2017-03-06 15:44:06 -08003475 super.dispatchProvideAutofillStructure(structure, flags);
Svet Ganovfd31f852017-04-26 15:54:27 -07003476 if (structure.getChildCount() != 0) {
Svet Ganov2f8fb1f2017-03-13 00:21:04 -07003477 return;
3478 }
Svet Ganovfd31f852017-04-26 15:54:27 -07003479 final ChildListForAutoFill children = getChildrenForAutofill(flags);
Svet Ganov2f8fb1f2017-03-13 00:21:04 -07003480 final int childrenCount = children.size();
3481 structure.setChildCount(childrenCount);
3482 for (int i = 0; i < childrenCount; i++) {
3483 final View child = children.get(i);
3484 final ViewStructure cstructure = structure.newChild(i);
3485 child.dispatchProvideAutofillStructure(cstructure, flags);
3486 }
3487 children.recycle();
Felipe Leme6d553872016-12-08 17:13:25 -08003488 }
Felipe Leme1ca634a2016-11-28 17:21:21 -08003489
Svet Ganov2f8fb1f2017-03-13 00:21:04 -07003490 /**
3491 * Gets the children for autofill. Children for autofill are the first
3492 * level descendants that are important for autofill. The returned
3493 * child list object is pooled and the caller must recycle it once done.
3494 * @hide */
Svet Ganovfd31f852017-04-26 15:54:27 -07003495 private @NonNull ChildListForAutoFill getChildrenForAutofill(@AutofillFlags int flags) {
Svet Ganov2f8fb1f2017-03-13 00:21:04 -07003496 final ChildListForAutoFill children = ChildListForAutoFill.obtain();
Svet Ganovfd31f852017-04-26 15:54:27 -07003497 populateChildrenForAutofill(children, flags);
Svet Ganov2f8fb1f2017-03-13 00:21:04 -07003498 return children;
Felipe Lemed04a6972017-03-02 12:56:18 -08003499 }
3500
3501 /** @hide */
Svet Ganovfd31f852017-04-26 15:54:27 -07003502 private void populateChildrenForAutofill(ArrayList<View> list, @AutofillFlags int flags) {
Svet Ganov2f8fb1f2017-03-13 00:21:04 -07003503 final int childrenCount = mChildrenCount;
3504 if (childrenCount <= 0) {
3505 return;
3506 }
3507 final ArrayList<View> preorderedList = buildOrderedChildList();
3508 final boolean customOrder = preorderedList == null
3509 && isChildrenDrawingOrderEnabled();
3510 for (int i = 0; i < childrenCount; i++) {
3511 final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
3512 final View child = (preorderedList == null)
3513 ? mChildren[childIndex] : preorderedList.get(childIndex);
Svet Ganovfd31f852017-04-26 15:54:27 -07003514 if ((flags & AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) != 0
3515 || child.isImportantForAutofill()) {
Felipe Lemed04a6972017-03-02 12:56:18 -08003516 list.add(child);
3517 } else if (child instanceof ViewGroup) {
Svet Ganovfd31f852017-04-26 15:54:27 -07003518 ((ViewGroup) child).populateChildrenForAutofill(list, flags);
Felipe Lemed04a6972017-03-02 12:56:18 -08003519 }
3520 }
3521 }
3522
Alan Viverettea7b85e62016-01-22 10:14:02 -05003523 private static View getAndVerifyPreorderedView(ArrayList<View> preorderedList, View[] children,
3524 int childIndex) {
3525 final View child;
3526 if (preorderedList != null) {
3527 child = preorderedList.get(childIndex);
3528 if (child == null) {
3529 throw new RuntimeException("Invalid preorderedList contained null child at index "
3530 + childIndex);
3531 }
3532 } else {
3533 child = children[childIndex];
3534 }
3535 return child;
3536 }
3537
Alan Viverettea54956a2015-01-07 16:05:02 -08003538 /** @hide */
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003539 @Override
Alan Viverettea54956a2015-01-07 16:05:02 -08003540 public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
Svetoslav Ganov031d9c12011-09-09 16:41:13 -07003541 super.onInitializeAccessibilityNodeInfoInternal(info);
Svet Ganov55bdb102015-02-06 12:41:17 -08003542 if (getAccessibilityNodeProvider() != null) {
3543 return;
3544 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07003545 if (mAttachInfo != null) {
Alan Viverettef0aed092013-11-06 15:33:03 -08003546 final ArrayList<View> childrenForAccessibility = mAttachInfo.mTempArrayList;
Svetoslav Ganov42138042012-03-20 11:51:39 -07003547 childrenForAccessibility.clear();
3548 addChildrenForAccessibility(childrenForAccessibility);
3549 final int childrenForAccessibilityCount = childrenForAccessibility.size();
3550 for (int i = 0; i < childrenForAccessibilityCount; i++) {
Alan Viverettef0aed092013-11-06 15:33:03 -08003551 final View child = childrenForAccessibility.get(i);
3552 info.addChildUnchecked(child);
Svetoslav Ganovea1da3d2011-06-15 17:16:02 -07003553 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07003554 childrenForAccessibility.clear();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003555 }
3556 }
3557
Svetoslav Ganov8a78fd42012-01-17 14:36:46 -08003558 @Override
Maxim Bogatovf399af32015-06-16 15:15:49 -07003559 public CharSequence getAccessibilityClassName() {
3560 return ViewGroup.class.getName();
Svetoslav Ganov8a78fd42012-01-17 14:36:46 -08003561 }
3562
Svetoslav Ganov42138042012-03-20 11:51:39 -07003563 @Override
Alan Viverette77e9a282013-09-12 17:16:09 -07003564 public void notifySubtreeAccessibilityStateChanged(View child, View source, int changeType) {
3565 // If this is a live region, we should send a subtree change event
3566 // from this view. Otherwise, we can let it propagate up.
3567 if (getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE) {
Phil Weaver10e340c2016-11-07 10:05:26 -08003568 notifyViewAccessibilityStateChangedIfNeeded(
3569 AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE);
Alan Viverette77e9a282013-09-12 17:16:09 -07003570 } else if (mParent != null) {
Adam Powell504a10f2013-07-11 15:25:59 -07003571 try {
Alan Viverette77e9a282013-09-12 17:16:09 -07003572 mParent.notifySubtreeAccessibilityStateChanged(this, source, changeType);
Adam Powell504a10f2013-07-11 15:25:59 -07003573 } catch (AbstractMethodError e) {
3574 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() +
3575 " does not fully implement ViewParent", e);
3576 }
Svetoslav6254f482013-06-04 17:22:14 -07003577 }
3578 }
3579
Phil Weaver4d3eec412016-09-01 16:28:34 -07003580 /** @hide */
3581 @Override
3582 public void notifySubtreeAccessibilityStateChangedIfNeeded() {
3583 if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) {
3584 return;
3585 }
3586 // If something important for a11y is happening in this subtree, make sure it's dispatched
3587 // from a view that is important for a11y so it doesn't get lost.
3588 if ((getImportantForAccessibility() != IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS)
3589 && !isImportantForAccessibility() && (getChildCount() > 0)) {
3590 ViewParent a11yParent = getParentForAccessibility();
3591 if (a11yParent instanceof View) {
3592 ((View) a11yParent).notifySubtreeAccessibilityStateChangedIfNeeded();
3593 return;
3594 }
3595 }
3596 super.notifySubtreeAccessibilityStateChangedIfNeeded();
3597 }
3598
Svetoslav6254f482013-06-04 17:22:14 -07003599 @Override
3600 void resetSubtreeAccessibilityStateChanged() {
3601 super.resetSubtreeAccessibilityStateChanged();
Svetoslav Ganov42138042012-03-20 11:51:39 -07003602 View[] children = mChildren;
3603 final int childCount = mChildrenCount;
3604 for (int i = 0; i < childCount; i++) {
Svetoslav6254f482013-06-04 17:22:14 -07003605 children[i].resetSubtreeAccessibilityStateChanged();
Svetoslav Ganov42138042012-03-20 11:51:39 -07003606 }
3607 }
3608
3609 /**
Phil Weaver1f222542016-01-08 11:49:32 -08003610 * Counts the number of children of this View that will be sent to an accessibility service.
3611 *
3612 * @return The number of children an {@code AccessibilityNodeInfo} rooted at this View
3613 * would have.
3614 */
3615 int getNumChildrenForAccessibility() {
3616 int numChildrenForAccessibility = 0;
3617 for (int i = 0; i < getChildCount(); i++) {
3618 View child = getChildAt(i);
3619 if (child.includeForAccessibility()) {
3620 numChildrenForAccessibility++;
3621 } else if (child instanceof ViewGroup) {
3622 numChildrenForAccessibility += ((ViewGroup) child)
3623 .getNumChildrenForAccessibility();
3624 }
3625 }
3626 return numChildrenForAccessibility;
3627 }
3628
3629 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003630 * {@inheritDoc}
Adam Powellb6ab0982015-01-07 17:00:12 -08003631 *
3632 * <p>Subclasses should always call <code>super.onNestedPrePerformAccessibilityAction</code></p>
3633 *
3634 * @param target The target view dispatching this action
3635 * @param action Action being performed; see
3636 * {@link android.view.accessibility.AccessibilityNodeInfo}
3637 * @param args Optional action arguments
3638 * @return false by default. Subclasses should return true if they handle the event.
3639 */
3640 @Override
3641 public boolean onNestedPrePerformAccessibilityAction(View target, int action, Bundle args) {
3642 return false;
3643 }
3644
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003645 @Override
3646 void dispatchDetachedFromWindow() {
Jeff Brown20e987b2010-08-23 12:01:02 -07003647 // If we still have a touch target, we are still in the process of
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003648 // dispatching motion events to a child; we need to get rid of that
3649 // child to avoid dispatching events to it after the window is torn
3650 // down. To make sure we keep the child in a consistent state, we
3651 // first send it an ACTION_CANCEL motion event.
Jeff Brown20e987b2010-08-23 12:01:02 -07003652 cancelAndClearTouchTargets(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003653
Jeff Brown59a422e2012-04-19 15:19:19 -07003654 // Similarly, set ACTION_EXIT to all hover targets and clear them.
3655 exitHoverTargets();
Vladislav Kaznacheevf847ee32016-11-21 14:11:00 -08003656 exitTooltipHoverTargets();
Jeff Brown59a422e2012-04-19 15:19:19 -07003657
Chet Haase9c087442011-01-12 16:20:16 -08003658 // In case view is detached while transition is running
Chet Haaseb9895022013-04-02 15:10:58 -07003659 mLayoutCalledWhileSuppressed = false;
Chet Haase9c087442011-01-12 16:20:16 -08003660
Christopher Tate86cab1b2011-01-13 20:28:55 -08003661 // Tear down our drag tracking
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07003662 mChildrenInterestedInDrag = null;
3663 mIsInterestedInDrag = false;
3664 if (mCurrentDragStartEvent != null) {
3665 mCurrentDragStartEvent.recycle();
3666 mCurrentDragStartEvent = null;
Christopher Tate86cab1b2011-01-13 20:28:55 -08003667 }
3668
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003669 final int count = mChildrenCount;
3670 final View[] children = mChildren;
3671 for (int i = 0; i < count; i++) {
3672 children[i].dispatchDetachedFromWindow();
3673 }
John Reckca7a9da2014-03-05 16:29:07 -08003674 clearDisappearingChildren();
Chet Haasec633d2f2015-04-07 10:29:39 -07003675 final int transientCount = mTransientViews == null ? 0 : mTransientIndices.size();
3676 for (int i = 0; i < transientCount; ++i) {
3677 View view = mTransientViews.get(i);
3678 view.dispatchDetachedFromWindow();
3679 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003680 super.dispatchDetachedFromWindow();
3681 }
3682
Fabrice Di Meglio23c89fd2012-08-13 12:17:42 -07003683 /**
3684 * @hide
3685 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003686 @Override
Fabrice Di Meglio23c89fd2012-08-13 12:17:42 -07003687 protected void internalSetPadding(int left, int top, int right, int bottom) {
Romain Guy2440e672012-08-07 14:43:43 -07003688 super.internalSetPadding(left, top, right, bottom);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003689
Romain Guy13f35f32011-03-24 12:03:17 -07003690 if ((mPaddingLeft | mPaddingTop | mPaddingRight | mPaddingBottom) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003691 mGroupFlags |= FLAG_PADDING_NOT_NULL;
3692 } else {
3693 mGroupFlags &= ~FLAG_PADDING_NOT_NULL;
3694 }
3695 }
3696
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003697 @Override
3698 protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
3699 super.dispatchSaveInstanceState(container);
3700 final int count = mChildrenCount;
3701 final View[] children = mChildren;
3702 for (int i = 0; i < count; i++) {
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07003703 View c = children[i];
3704 if ((c.mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED) {
3705 c.dispatchSaveInstanceState(container);
3706 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003707 }
3708 }
3709
3710 /**
Romain Guy9fc27812011-04-27 14:21:41 -07003711 * Perform dispatching of a {@link #saveHierarchyState(android.util.SparseArray)} freeze()}
3712 * to only this view, not to its children. For use when overriding
3713 * {@link #dispatchSaveInstanceState(android.util.SparseArray)} dispatchFreeze()} to allow
3714 * subclasses to freeze their own state but not the state of their children.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003715 *
3716 * @param container the container
3717 */
3718 protected void dispatchFreezeSelfOnly(SparseArray<Parcelable> container) {
3719 super.dispatchSaveInstanceState(container);
3720 }
3721
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003722 @Override
3723 protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
3724 super.dispatchRestoreInstanceState(container);
3725 final int count = mChildrenCount;
3726 final View[] children = mChildren;
3727 for (int i = 0; i < count; i++) {
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07003728 View c = children[i];
3729 if ((c.mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED) {
3730 c.dispatchRestoreInstanceState(container);
3731 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003732 }
3733 }
3734
3735 /**
Romain Guy02739a82011-05-16 11:43:18 -07003736 * Perform dispatching of a {@link #restoreHierarchyState(android.util.SparseArray)}
3737 * to only this view, not to its children. For use when overriding
3738 * {@link #dispatchRestoreInstanceState(android.util.SparseArray)} to allow
3739 * subclasses to thaw their own state but not the state of their children.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003740 *
3741 * @param container the container
3742 */
3743 protected void dispatchThawSelfOnly(SparseArray<Parcelable> container) {
3744 super.dispatchRestoreInstanceState(container);
3745 }
3746
3747 /**
3748 * Enables or disables the drawing cache for each child of this view group.
3749 *
3750 * @param enabled true to enable the cache, false to dispose of it
3751 */
3752 protected void setChildrenDrawingCacheEnabled(boolean enabled) {
3753 if (enabled || (mPersistentDrawingCache & PERSISTENT_ALL_CACHES) != PERSISTENT_ALL_CACHES) {
3754 final View[] children = mChildren;
3755 final int count = mChildrenCount;
3756 for (int i = 0; i < count; i++) {
3757 children[i].setDrawingCacheEnabled(enabled);
3758 }
3759 }
3760 }
3761
sergeyvb37d44e2016-03-29 20:27:44 -07003762 /**
3763 * @hide
3764 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003765 @Override
sergeyvb37d44e2016-03-29 20:27:44 -07003766 public Bitmap createSnapshot(Bitmap.Config quality, int backgroundColor, boolean skipChildren) {
Romain Guy65554f22010-03-22 18:58:21 -07003767 int count = mChildrenCount;
3768 int[] visibilities = null;
3769
Romain Guy223ff5c2010-03-02 17:07:47 -08003770 if (skipChildren) {
Romain Guy65554f22010-03-22 18:58:21 -07003771 visibilities = new int[count];
3772 for (int i = 0; i < count; i++) {
3773 View child = getChildAt(i);
3774 visibilities[i] = child.getVisibility();
3775 if (visibilities[i] == View.VISIBLE) {
sergeyvb37d44e2016-03-29 20:27:44 -07003776 child.mViewFlags = (child.mViewFlags & ~View.VISIBILITY_MASK)
3777 | (View.INVISIBLE & View.VISIBILITY_MASK);
Romain Guy65554f22010-03-22 18:58:21 -07003778 }
3779 }
Romain Guy223ff5c2010-03-02 17:07:47 -08003780 }
3781
3782 Bitmap b = super.createSnapshot(quality, backgroundColor, skipChildren);
Romain Guy65554f22010-03-22 18:58:21 -07003783
3784 if (skipChildren) {
3785 for (int i = 0; i < count; i++) {
sergeyvb37d44e2016-03-29 20:27:44 -07003786 View child = getChildAt(i);
3787 child.mViewFlags = (child.mViewFlags & ~View.VISIBILITY_MASK)
3788 | (visibilities[i] & View.VISIBILITY_MASK);
Chet Haase5c13d892010-10-08 08:37:55 -07003789 }
Romain Guy65554f22010-03-22 18:58:21 -07003790 }
Romain Guy223ff5c2010-03-02 17:07:47 -08003791
3792 return b;
3793 }
3794
Philip Milne7b757812012-09-19 18:13:44 -07003795 /** Return true if this ViewGroup is laying out using optical bounds. */
3796 boolean isLayoutModeOptical() {
3797 return mLayoutMode == LAYOUT_MODE_OPTICAL_BOUNDS;
3798 }
Romain Guycbc67742012-04-27 16:12:57 -07003799
Alan Viverettebe463f22016-01-21 10:50:10 -05003800 @Override
Philip Milne7b757812012-09-19 18:13:44 -07003801 Insets computeOpticalInsets() {
3802 if (isLayoutModeOptical()) {
3803 int left = 0;
3804 int top = 0;
3805 int right = 0;
3806 int bottom = 0;
3807 for (int i = 0; i < mChildrenCount; i++) {
3808 View child = getChildAt(i);
3809 if (child.getVisibility() == VISIBLE) {
3810 Insets insets = child.getOpticalInsets();
3811 left = Math.max(left, insets.left);
3812 top = Math.max(top, insets.top);
3813 right = Math.max(right, insets.right);
3814 bottom = Math.max(bottom, insets.bottom);
3815 }
3816 }
3817 return Insets.of(left, top, right, bottom);
3818 } else {
3819 return Insets.NONE;
3820 }
3821 }
3822
3823 private static void fillRect(Canvas canvas, Paint paint, int x1, int y1, int x2, int y2) {
3824 if (x1 != x2 && y1 != y2) {
3825 if (x1 > x2) {
3826 int tmp = x1; x1 = x2; x2 = tmp;
3827 }
3828 if (y1 > y2) {
3829 int tmp = y1; y1 = y2; y2 = tmp;
3830 }
3831 canvas.drawRect(x1, y1, x2, y2, paint);
3832 }
3833 }
3834
3835 private static int sign(int x) {
3836 return (x >= 0) ? 1 : -1;
3837 }
3838
3839 private static void drawCorner(Canvas c, Paint paint, int x1, int y1, int dx, int dy, int lw) {
3840 fillRect(c, paint, x1, y1, x1 + dx, y1 + lw * sign(dy));
3841 fillRect(c, paint, x1, y1, x1 + lw * sign(dx), y1 + dy);
3842 }
3843
Romain Guy6410c0a2013-06-17 11:21:58 -07003844 private static void drawRectCorners(Canvas canvas, int x1, int y1, int x2, int y2, Paint paint,
3845 int lineLength, int lineWidth) {
Philip Milne7b757812012-09-19 18:13:44 -07003846 drawCorner(canvas, paint, x1, y1, lineLength, lineLength, lineWidth);
3847 drawCorner(canvas, paint, x1, y2, lineLength, -lineLength, lineWidth);
3848 drawCorner(canvas, paint, x2, y1, -lineLength, lineLength, lineWidth);
3849 drawCorner(canvas, paint, x2, y2, -lineLength, -lineLength, lineWidth);
3850 }
3851
3852 private static void fillDifference(Canvas canvas,
3853 int x2, int y2, int x3, int y3,
3854 int dx1, int dy1, int dx2, int dy2, Paint paint) {
3855 int x1 = x2 - dx1;
3856 int y1 = y2 - dy1;
3857
3858 int x4 = x3 + dx2;
3859 int y4 = y3 + dy2;
3860
3861 fillRect(canvas, paint, x1, y1, x4, y2);
3862 fillRect(canvas, paint, x1, y2, x2, y3);
3863 fillRect(canvas, paint, x3, y2, x4, y3);
3864 fillRect(canvas, paint, x1, y3, x4, y4);
Philip Milne10ca24a2012-04-23 15:38:27 -07003865 }
3866
3867 /**
3868 * @hide
3869 */
Philip Milne7b757812012-09-19 18:13:44 -07003870 protected void onDebugDrawMargins(Canvas canvas, Paint paint) {
Philip Milne10ca24a2012-04-23 15:38:27 -07003871 for (int i = 0; i < getChildCount(); i++) {
3872 View c = getChildAt(i);
Philip Milne7b757812012-09-19 18:13:44 -07003873 c.getLayoutParams().onDebugDraw(c, canvas, paint);
Philip Milne10ca24a2012-04-23 15:38:27 -07003874 }
3875 }
3876
3877 /**
3878 * @hide
3879 */
3880 protected void onDebugDraw(Canvas canvas) {
Philip Milne7b757812012-09-19 18:13:44 -07003881 Paint paint = getDebugPaint();
3882
Philip Milne10ca24a2012-04-23 15:38:27 -07003883 // Draw optical bounds
Philip Milne7b757812012-09-19 18:13:44 -07003884 {
3885 paint.setColor(Color.RED);
3886 paint.setStyle(Paint.Style.STROKE);
Philip Milne7b757812012-09-19 18:13:44 -07003887
Philip Milne10ca24a2012-04-23 15:38:27 -07003888 for (int i = 0; i < getChildCount(); i++) {
3889 View c = getChildAt(i);
Chris Craika1dab8b2015-06-30 13:51:25 -07003890 if (c.getVisibility() != View.GONE) {
3891 Insets insets = c.getOpticalInsets();
Philip Milne7b757812012-09-19 18:13:44 -07003892
Chris Craika1dab8b2015-06-30 13:51:25 -07003893 drawRect(canvas, paint,
3894 c.getLeft() + insets.left,
3895 c.getTop() + insets.top,
3896 c.getRight() - insets.right - 1,
3897 c.getBottom() - insets.bottom - 1);
3898 }
Philip Milne10ca24a2012-04-23 15:38:27 -07003899 }
3900 }
3901
Philip Milne10ca24a2012-04-23 15:38:27 -07003902 // Draw margins
Philip Milne7b757812012-09-19 18:13:44 -07003903 {
3904 paint.setColor(Color.argb(63, 255, 0, 255));
3905 paint.setStyle(Paint.Style.FILL);
Philip Milne604f4402012-04-24 19:27:11 -07003906
Philip Milne7b757812012-09-19 18:13:44 -07003907 onDebugDrawMargins(canvas, paint);
3908 }
3909
3910 // Draw clip bounds
3911 {
Vadim Tryshevcdf38ba2016-10-11 18:33:10 -07003912 paint.setColor(DEBUG_CORNERS_COLOR);
Philip Milne7b757812012-09-19 18:13:44 -07003913 paint.setStyle(Paint.Style.FILL);
3914
Vadim Tryshevcdf38ba2016-10-11 18:33:10 -07003915 int lineLength = dipsToPixels(DEBUG_CORNERS_SIZE_DIP);
Philip Milne7b757812012-09-19 18:13:44 -07003916 int lineWidth = dipsToPixels(1);
3917 for (int i = 0; i < getChildCount(); i++) {
3918 View c = getChildAt(i);
Chris Craika1dab8b2015-06-30 13:51:25 -07003919 if (c.getVisibility() != View.GONE) {
3920 drawRectCorners(canvas, c.getLeft(), c.getTop(), c.getRight(), c.getBottom(),
3921 paint, lineLength, lineWidth);
3922 }
Philip Milne7b757812012-09-19 18:13:44 -07003923 }
Philip Milne604f4402012-04-24 19:27:11 -07003924 }
Philip Milne10ca24a2012-04-23 15:38:27 -07003925 }
3926
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003927 @Override
3928 protected void dispatchDraw(Canvas canvas) {
Chris Craika753f4c2014-07-24 12:39:17 -07003929 boolean usingRenderNodeProperties = canvas.isRecordingFor(mRenderNode);
Chris Craikab008f02014-05-23 17:55:03 -07003930 final int childrenCount = mChildrenCount;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003931 final View[] children = mChildren;
3932 int flags = mGroupFlags;
3933
3934 if ((flags & FLAG_RUN_ANIMATION) != 0 && canAnimate()) {
Romain Guy0d9275e2010-10-26 14:22:30 -07003935 final boolean buildCache = !isHardwareAccelerated();
Chris Craikab008f02014-05-23 17:55:03 -07003936 for (int i = 0; i < childrenCount; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003937 final View child = children[i];
3938 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
3939 final LayoutParams params = child.getLayoutParams();
Chris Craikab008f02014-05-23 17:55:03 -07003940 attachLayoutAnimationParameters(child, params, i, childrenCount);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003941 bindLayoutAnimation(child);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003942 }
3943 }
3944
3945 final LayoutAnimationController controller = mLayoutAnimationController;
3946 if (controller.willOverlap()) {
3947 mGroupFlags |= FLAG_OPTIMIZE_INVALIDATE;
3948 }
3949
3950 controller.start();
3951
3952 mGroupFlags &= ~FLAG_RUN_ANIMATION;
3953 mGroupFlags &= ~FLAG_ANIMATION_DONE;
3954
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003955 if (mAnimationListener != null) {
3956 mAnimationListener.onAnimationStart(controller.getAnimation());
3957 }
3958 }
3959
Selim Cinek19cadc22014-04-16 17:27:19 +02003960 int clipSaveCount = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003961 final boolean clipToPadding = (flags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK;
3962 if (clipToPadding) {
John Reck41f864e2016-05-12 15:07:49 -07003963 clipSaveCount = canvas.save(Canvas.CLIP_SAVE_FLAG);
Romain Guy8f2d94f2009-03-25 18:04:42 -07003964 canvas.clipRect(mScrollX + mPaddingLeft, mScrollY + mPaddingTop,
3965 mScrollX + mRight - mLeft - mPaddingRight,
3966 mScrollY + mBottom - mTop - mPaddingBottom);
Selim Cinek19cadc22014-04-16 17:27:19 +02003967 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003968
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003969 // We will draw our child's animation, let's reset the flag
Dianne Hackborn4702a852012-08-17 15:18:29 -07003970 mPrivateFlags &= ~PFLAG_DRAW_ANIMATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003971 mGroupFlags &= ~FLAG_INVALIDATE_REQUIRED;
3972
3973 boolean more = false;
3974 final long drawingTime = getDrawingTime();
3975
Chris Craik8afd0f22014-08-21 17:41:57 -07003976 if (usingRenderNodeProperties) canvas.insertReorderBarrier();
Chet Haasec633d2f2015-04-07 10:29:39 -07003977 final int transientCount = mTransientIndices == null ? 0 : mTransientIndices.size();
3978 int transientIndex = transientCount != 0 ? 0 : -1;
Chris Craikab008f02014-05-23 17:55:03 -07003979 // Only use the preordered list if not HW accelerated, since the HW pipeline will do the
3980 // draw reordering internally
Chris Craika753f4c2014-07-24 12:39:17 -07003981 final ArrayList<View> preorderedList = usingRenderNodeProperties
Chris Craikab008f02014-05-23 17:55:03 -07003982 ? null : buildOrderedChildList();
3983 final boolean customOrder = preorderedList == null
3984 && isChildrenDrawingOrderEnabled();
3985 for (int i = 0; i < childrenCount; i++) {
Chet Haasec633d2f2015-04-07 10:29:39 -07003986 while (transientIndex >= 0 && mTransientIndices.get(transientIndex) == i) {
3987 final View transientChild = mTransientViews.get(transientIndex);
3988 if ((transientChild.mViewFlags & VISIBILITY_MASK) == VISIBLE ||
3989 transientChild.getAnimation() != null) {
3990 more |= drawChild(canvas, transientChild, drawingTime);
3991 }
3992 transientIndex++;
3993 if (transientIndex >= transientCount) {
3994 transientIndex = -1;
3995 }
3996 }
Alan Viverettea7b85e62016-01-22 10:14:02 -05003997
3998 final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
3999 final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);
Chris Craikab008f02014-05-23 17:55:03 -07004000 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
4001 more |= drawChild(canvas, child, drawingTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004002 }
4003 }
Chet Haasec633d2f2015-04-07 10:29:39 -07004004 while (transientIndex >= 0) {
4005 // there may be additional transient views after the normal views
4006 final View transientChild = mTransientViews.get(transientIndex);
4007 if ((transientChild.mViewFlags & VISIBILITY_MASK) == VISIBLE ||
4008 transientChild.getAnimation() != null) {
4009 more |= drawChild(canvas, transientChild, drawingTime);
4010 }
4011 transientIndex++;
4012 if (transientIndex >= transientCount) {
4013 break;
4014 }
4015 }
Chris Craikab008f02014-05-23 17:55:03 -07004016 if (preorderedList != null) preorderedList.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004017
4018 // Draw any disappearing views that have animations
4019 if (mDisappearingChildren != null) {
4020 final ArrayList<View> disappearingChildren = mDisappearingChildren;
4021 final int disappearingCount = disappearingChildren.size() - 1;
4022 // Go backwards -- we may delete as animations finish
4023 for (int i = disappearingCount; i >= 0; i--) {
4024 final View child = disappearingChildren.get(i);
4025 more |= drawChild(canvas, child, drawingTime);
4026 }
4027 }
Chris Craik8afd0f22014-08-21 17:41:57 -07004028 if (usingRenderNodeProperties) canvas.insertInorderBarrier();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004029
Philip Milne10ca24a2012-04-23 15:38:27 -07004030 if (debugDraw()) {
4031 onDebugDraw(canvas);
4032 }
4033
Chris Craike4cf1522014-08-04 17:55:22 -07004034 if (clipToPadding) {
Selim Cinek19cadc22014-04-16 17:27:19 +02004035 canvas.restoreToCount(clipSaveCount);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004036 }
4037
4038 // mGroupFlags might have been updated by drawChild()
4039 flags = mGroupFlags;
4040
4041 if ((flags & FLAG_INVALIDATE_REQUIRED) == FLAG_INVALIDATE_REQUIRED) {
Romain Guy849d0a32011-02-01 17:20:48 -08004042 invalidate(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004043 }
4044
4045 if ((flags & FLAG_ANIMATION_DONE) == 0 && (flags & FLAG_NOTIFY_ANIMATION_LISTENER) == 0 &&
4046 mLayoutAnimationController.isDone() && !more) {
4047 // We want to erase the drawing cache and notify the listener after the
4048 // next frame is drawn because one extra invalidate() is caused by
4049 // drawChild() after the animation is over
4050 mGroupFlags |= FLAG_NOTIFY_ANIMATION_LISTENER;
4051 final Runnable end = new Runnable() {
Alan Viverettebe463f22016-01-21 10:50:10 -05004052 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004053 public void run() {
4054 notifyAnimationListener();
4055 }
4056 };
4057 post(end);
4058 }
4059 }
Romain Guy8506ab42009-06-11 17:35:47 -07004060
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004061 /**
Chet Haaseedf6f4b2013-03-26 07:55:30 -07004062 * Returns the ViewGroupOverlay for this view group, creating it if it does
4063 * not yet exist. In addition to {@link ViewOverlay}'s support for drawables,
4064 * {@link ViewGroupOverlay} allows views to be added to the overlay. These
4065 * views, like overlay drawables, are visual-only; they do not receive input
4066 * events and should not be used as anything other than a temporary
4067 * representation of a view in a parent container, such as might be used
4068 * by an animation effect.
4069 *
Chet Haase95399492013-04-08 14:30:31 -07004070 * <p>Note: Overlays do not currently work correctly with {@link
4071 * SurfaceView} or {@link TextureView}; contents in overlays for these
4072 * types of views may not display correctly.</p>
4073 *
Chet Haaseedf6f4b2013-03-26 07:55:30 -07004074 * @return The ViewGroupOverlay object for this view.
4075 * @see ViewGroupOverlay
4076 */
4077 @Override
4078 public ViewGroupOverlay getOverlay() {
4079 if (mOverlay == null) {
4080 mOverlay = new ViewGroupOverlay(mContext, this);
4081 }
4082 return (ViewGroupOverlay) mOverlay;
4083 }
4084
4085 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004086 * Returns the index of the child to draw for this iteration. Override this
4087 * if you want to change the drawing order of children. By default, it
4088 * returns i.
4089 * <p>
Romain Guy293451e2009-11-04 13:59:48 -08004090 * NOTE: In order for this method to be called, you must enable child ordering
4091 * first by calling {@link #setChildrenDrawingOrderEnabled(boolean)}.
Romain Guy8506ab42009-06-11 17:35:47 -07004092 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004093 * @param i The current iteration.
4094 * @return The index of the child to draw this iteration.
Chet Haase5c13d892010-10-08 08:37:55 -07004095 *
Romain Guy293451e2009-11-04 13:59:48 -08004096 * @see #setChildrenDrawingOrderEnabled(boolean)
4097 * @see #isChildrenDrawingOrderEnabled()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004098 */
4099 protected int getChildDrawingOrder(int childCount, int i) {
4100 return i;
4101 }
Romain Guy8506ab42009-06-11 17:35:47 -07004102
Chris Craikab008f02014-05-23 17:55:03 -07004103 private boolean hasChildWithZ() {
4104 for (int i = 0; i < mChildrenCount; i++) {
4105 if (mChildren[i].getZ() != 0) return true;
4106 }
4107 return false;
4108 }
4109
4110 /**
4111 * Populates (and returns) mPreSortedChildren with a pre-ordered list of the View's children,
Chris Craik57c79c82014-09-30 12:54:31 -07004112 * sorted first by Z, then by child drawing order (if applicable). This list must be cleared
4113 * after use to avoid leaking child Views.
Chris Craikab008f02014-05-23 17:55:03 -07004114 *
4115 * Uses a stable, insertion sort which is commonly O(n) for ViewGroups with very few elevated
4116 * children.
4117 */
George Mount81206522014-09-26 21:53:39 -07004118 ArrayList<View> buildOrderedChildList() {
Alan Viverettea7b85e62016-01-22 10:14:02 -05004119 final int childrenCount = mChildrenCount;
4120 if (childrenCount <= 1 || !hasChildWithZ()) return null;
Chris Craikab008f02014-05-23 17:55:03 -07004121
4122 if (mPreSortedChildren == null) {
Alan Viverettea7b85e62016-01-22 10:14:02 -05004123 mPreSortedChildren = new ArrayList<>(childrenCount);
Chris Craikab008f02014-05-23 17:55:03 -07004124 } else {
Chris Craikfc563772016-05-04 13:34:30 -07004125 // callers should clear, so clear shouldn't be necessary, but for safety...
4126 mPreSortedChildren.clear();
Alan Viverettea7b85e62016-01-22 10:14:02 -05004127 mPreSortedChildren.ensureCapacity(childrenCount);
Chris Craikab008f02014-05-23 17:55:03 -07004128 }
4129
Alan Viverettea7b85e62016-01-22 10:14:02 -05004130 final boolean customOrder = isChildrenDrawingOrderEnabled();
4131 for (int i = 0; i < childrenCount; i++) {
Chris Craikab008f02014-05-23 17:55:03 -07004132 // add next child (in child order) to end of list
Alan Viverettea7b85e62016-01-22 10:14:02 -05004133 final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
4134 final View nextChild = mChildren[childIndex];
4135 final float currentZ = nextChild.getZ();
Chris Craikab008f02014-05-23 17:55:03 -07004136
4137 // insert ahead of any Views with greater Z
4138 int insertIndex = i;
4139 while (insertIndex > 0 && mPreSortedChildren.get(insertIndex - 1).getZ() > currentZ) {
4140 insertIndex--;
4141 }
4142 mPreSortedChildren.add(insertIndex, nextChild);
4143 }
4144 return mPreSortedChildren;
4145 }
4146
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004147 private void notifyAnimationListener() {
4148 mGroupFlags &= ~FLAG_NOTIFY_ANIMATION_LISTENER;
4149 mGroupFlags |= FLAG_ANIMATION_DONE;
4150
4151 if (mAnimationListener != null) {
4152 final Runnable end = new Runnable() {
Alan Viverettebe463f22016-01-21 10:50:10 -05004153 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004154 public void run() {
4155 mAnimationListener.onAnimationEnd(mLayoutAnimationController.getAnimation());
4156 }
4157 };
4158 post(end);
4159 }
4160
Romain Guy849d0a32011-02-01 17:20:48 -08004161 invalidate(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004162 }
4163
4164 /**
Chet Haasedaf98e92011-01-10 14:10:36 -08004165 * This method is used to cause children of this ViewGroup to restore or recreate their
4166 * display lists. It is called by getDisplayList() when the parent ViewGroup does not need
4167 * to recreate its own display list, which would happen if it went through the normal
4168 * draw/dispatchDraw mechanisms.
4169 *
4170 * @hide
4171 */
4172 @Override
4173 protected void dispatchGetDisplayList() {
4174 final int count = mChildrenCount;
4175 final View[] children = mChildren;
4176 for (int i = 0; i < count; i++) {
4177 final View child = children[i];
John Reckc2330f52015-04-28 13:18:52 -07004178 if (((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null)) {
Chet Haase6c0665f2014-08-01 13:32:27 -07004179 recreateChildDisplayList(child);
Romain Guy2f57ba52011-02-03 18:03:29 -08004180 }
Chet Haasedaf98e92011-01-10 14:10:36 -08004181 }
Chet Haase91cedf12013-03-11 07:56:30 -07004182 if (mOverlay != null) {
Chet Haaseedf6f4b2013-03-26 07:55:30 -07004183 View overlayView = mOverlay.getOverlayView();
Chet Haase6c0665f2014-08-01 13:32:27 -07004184 recreateChildDisplayList(overlayView);
Chet Haase91cedf12013-03-11 07:56:30 -07004185 }
Chet Haase6c0665f2014-08-01 13:32:27 -07004186 if (mDisappearingChildren != null) {
4187 final ArrayList<View> disappearingChildren = mDisappearingChildren;
4188 final int disappearingCount = disappearingChildren.size();
4189 for (int i = 0; i < disappearingCount; ++i) {
4190 final View child = disappearingChildren.get(i);
4191 recreateChildDisplayList(child);
4192 }
4193 }
4194 }
4195
4196 private void recreateChildDisplayList(View child) {
Chris Craik31a2d062015-05-01 14:22:47 -07004197 child.mRecreateDisplayList = (child.mPrivateFlags & PFLAG_INVALIDATED) != 0;
Chet Haase6c0665f2014-08-01 13:32:27 -07004198 child.mPrivateFlags &= ~PFLAG_INVALIDATED;
Chris Craik31a2d062015-05-01 14:22:47 -07004199 child.updateDisplayListIfDirty();
Chet Haase6c0665f2014-08-01 13:32:27 -07004200 child.mRecreateDisplayList = false;
Chet Haasedaf98e92011-01-10 14:10:36 -08004201 }
4202
4203 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004204 * Draw one child of this View Group. This method is responsible for getting
4205 * the canvas in the right state. This includes clipping, translating so
4206 * that the child's scrolled origin is at 0, 0, and applying any animation
4207 * transformations.
4208 *
4209 * @param canvas The canvas on which to draw the child
4210 * @param child Who to draw
Chet Haasebcca79a2012-02-14 08:45:14 -08004211 * @param drawingTime The time at which draw is occurring
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004212 * @return True if an invalidate() was issued
4213 */
4214 protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
Chet Haase64a48c12012-02-13 16:33:29 -08004215 return child.draw(canvas, this, drawingTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004216 }
4217
Alan Viverette922e1c62015-05-05 17:18:27 -07004218 @Override
4219 void getScrollIndicatorBounds(@NonNull Rect out) {
4220 super.getScrollIndicatorBounds(out);
4221
4222 // If we have padding and we're supposed to clip children to that
4223 // padding, offset the scroll indicators to match our clip bounds.
4224 final boolean clipToPadding = (mGroupFlags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK;
4225 if (clipToPadding) {
4226 out.left += mPaddingLeft;
4227 out.right -= mPaddingRight;
4228 out.top += mPaddingTop;
4229 out.bottom -= mPaddingBottom;
4230 }
4231 }
4232
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004233 /**
Chris Craikd863a102013-12-19 13:31:15 -08004234 * Returns whether this group's children are clipped to their bounds before drawing.
Chet Haase430742f2013-04-12 11:18:36 -07004235 * The default value is true.
4236 * @see #setClipChildren(boolean)
4237 *
4238 * @return True if the group's children will be clipped to their bounds,
4239 * false otherwise.
4240 */
Chris Craik5c75c522014-09-05 14:08:08 -07004241 @ViewDebug.ExportedProperty(category = "drawing")
Chet Haase430742f2013-04-12 11:18:36 -07004242 public boolean getClipChildren() {
4243 return ((mGroupFlags & FLAG_CLIP_CHILDREN) != 0);
4244 }
4245
4246 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004247 * By default, children are clipped to their bounds before drawing. This
4248 * allows view groups to override this behavior for animations, etc.
4249 *
4250 * @param clipChildren true to clip children to their bounds,
4251 * false otherwise
4252 * @attr ref android.R.styleable#ViewGroup_clipChildren
4253 */
4254 public void setClipChildren(boolean clipChildren) {
Chet Haasea1cff502012-02-21 13:43:44 -08004255 boolean previousValue = (mGroupFlags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN;
4256 if (clipChildren != previousValue) {
4257 setBooleanFlag(FLAG_CLIP_CHILDREN, clipChildren);
Chet Haase1271e2c2012-04-20 09:54:27 -07004258 for (int i = 0; i < mChildrenCount; ++i) {
4259 View child = getChildAt(i);
Chris Craik64a12e12014-03-28 18:12:12 -07004260 if (child.mRenderNode != null) {
4261 child.mRenderNode.setClipToBounds(clipChildren);
Chet Haasea1cff502012-02-21 13:43:44 -08004262 }
4263 }
John Reckaae9f3b2014-07-28 09:30:36 -07004264 invalidate(true);
Chet Haasea1cff502012-02-21 13:43:44 -08004265 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004266 }
4267
4268 /**
Doris Liub134b5e2015-05-28 17:26:46 -07004269 * Sets whether this ViewGroup will clip its children to its padding and resize (but not
4270 * clip) any EdgeEffect to the padded region, if padding is present.
Chris Craikb1652962014-11-14 17:05:06 -08004271 * <p>
4272 * By default, children are clipped to the padding of their parent
Doris Liub134b5e2015-05-28 17:26:46 -07004273 * ViewGroup. This clipping behavior is only enabled if padding is non-zero.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004274 *
Doris Liub134b5e2015-05-28 17:26:46 -07004275 * @param clipToPadding true to clip children to the padding of the group, and resize (but
4276 * not clip) any EdgeEffect to the padded region. False otherwise.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004277 * @attr ref android.R.styleable#ViewGroup_clipToPadding
4278 */
4279 public void setClipToPadding(boolean clipToPadding) {
John Reck9fa3a242014-06-27 15:57:19 -07004280 if (hasBooleanFlag(FLAG_CLIP_TO_PADDING) != clipToPadding) {
4281 setBooleanFlag(FLAG_CLIP_TO_PADDING, clipToPadding);
John Reckaae9f3b2014-07-28 09:30:36 -07004282 invalidate(true);
John Reck9fa3a242014-06-27 15:57:19 -07004283 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004284 }
4285
4286 /**
Doris Liub134b5e2015-05-28 17:26:46 -07004287 * Returns whether this ViewGroup will clip its children to its padding, and resize (but
4288 * not clip) any EdgeEffect to the padded region, if padding is present.
Chris Craikb1652962014-11-14 17:05:06 -08004289 * <p>
4290 * By default, children are clipped to the padding of their parent
4291 * Viewgroup. This clipping behavior is only enabled if padding is non-zero.
Adam Powell1c35b082014-07-11 15:37:15 -07004292 *
Doris Liub134b5e2015-05-28 17:26:46 -07004293 * @return true if this ViewGroup clips children to its padding and resizes (but doesn't
4294 * clip) any EdgeEffect to the padded region, false otherwise.
Adam Powell1c35b082014-07-11 15:37:15 -07004295 *
4296 * @attr ref android.R.styleable#ViewGroup_clipToPadding
4297 */
Chris Craik5c75c522014-09-05 14:08:08 -07004298 @ViewDebug.ExportedProperty(category = "drawing")
Adam Powell1c35b082014-07-11 15:37:15 -07004299 public boolean getClipToPadding() {
4300 return hasBooleanFlag(FLAG_CLIP_TO_PADDING);
4301 }
4302
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004303 @Override
4304 public void dispatchSetSelected(boolean selected) {
4305 final View[] children = mChildren;
4306 final int count = mChildrenCount;
4307 for (int i = 0; i < count; i++) {
4308 children[i].setSelected(selected);
4309 }
4310 }
Romain Guy8506ab42009-06-11 17:35:47 -07004311
Dianne Hackbornd0fa3712010-09-14 18:57:14 -07004312 @Override
4313 public void dispatchSetActivated(boolean activated) {
4314 final View[] children = mChildren;
4315 final int count = mChildrenCount;
4316 for (int i = 0; i < count; i++) {
Dianne Hackbornd0fa3712010-09-14 18:57:14 -07004317 children[i].setActivated(activated);
4318 }
4319 }
4320
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004321 @Override
4322 protected void dispatchSetPressed(boolean pressed) {
4323 final View[] children = mChildren;
4324 final int count = mChildrenCount;
4325 for (int i = 0; i < count; i++) {
Adam Powell035a1fc2012-02-27 15:23:50 -08004326 final View child = children[i];
4327 // Children that are clickable on their own should not
4328 // show a pressed state when their parent view does.
4329 // Clearing a pressed state always propagates.
4330 if (!pressed || (!child.isClickable() && !child.isLongClickable())) {
4331 child.setPressed(pressed);
4332 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004333 }
4334 }
4335
Alan Viveretteb942b6f2014-12-08 10:37:39 -08004336 /**
4337 * Dispatches drawable hotspot changes to child views that meet at least
4338 * one of the following criteria:
4339 * <ul>
4340 * <li>Returns {@code false} from both {@link View#isClickable()} and
4341 * {@link View#isLongClickable()}</li>
4342 * <li>Requests duplication of parent state via
4343 * {@link View#setDuplicateParentStateEnabled(boolean)}</li>
4344 * </ul>
4345 *
4346 * @param x hotspot x coordinate
4347 * @param y hotspot y coordinate
4348 * @see #drawableHotspotChanged(float, float)
4349 */
4350 @Override
4351 public void dispatchDrawableHotspotChanged(float x, float y) {
4352 final int count = mChildrenCount;
4353 if (count == 0) {
4354 return;
4355 }
4356
4357 final View[] children = mChildren;
4358 for (int i = 0; i < count; i++) {
4359 final View child = children[i];
4360 // Children that are clickable on their own should not
4361 // receive hotspots when their parent view does.
4362 final boolean nonActionable = !child.isClickable() && !child.isLongClickable();
4363 final boolean duplicatesState = (child.mViewFlags & DUPLICATE_PARENT_STATE) != 0;
4364 if (nonActionable || duplicatesState) {
4365 final float[] point = getTempPoint();
4366 point[0] = x;
4367 point[1] = y;
4368 transformPointToViewLocal(point, child);
4369 child.drawableHotspotChanged(point[0], point[1]);
4370 }
4371 }
4372 }
4373
Adam Powell14874662013-07-18 19:42:41 -07004374 @Override
4375 void dispatchCancelPendingInputEvents() {
4376 super.dispatchCancelPendingInputEvents();
4377
4378 final View[] children = mChildren;
4379 final int count = mChildrenCount;
4380 for (int i = 0; i < count; i++) {
4381 children[i].dispatchCancelPendingInputEvents();
4382 }
4383 }
4384
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004385 /**
4386 * When this property is set to true, this ViewGroup supports static transformations on
4387 * children; this causes
4388 * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} to be
4389 * invoked when a child is drawn.
4390 *
4391 * Any subclass overriding
4392 * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} should
4393 * set this property to true.
4394 *
4395 * @param enabled True to enable static transformations on children, false otherwise.
4396 *
Chet Haase599913d2012-07-23 16:22:05 -07004397 * @see #getChildStaticTransformation(View, android.view.animation.Transformation)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004398 */
4399 protected void setStaticTransformationsEnabled(boolean enabled) {
4400 setBooleanFlag(FLAG_SUPPORT_STATIC_TRANSFORMATIONS, enabled);
4401 }
4402
4403 /**
Chet Haase2d46fcc2011-12-19 18:01:05 -08004404 * Sets <code>t</code> to be the static transformation of the child, if set, returning a
4405 * boolean to indicate whether a static transform was set. The default implementation
4406 * simply returns <code>false</code>; subclasses may override this method for different
Chet Haase599913d2012-07-23 16:22:05 -07004407 * behavior. {@link #setStaticTransformationsEnabled(boolean)} must be set to true
4408 * for this method to be called.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004409 *
Chet Haase2d46fcc2011-12-19 18:01:05 -08004410 * @param child The child view whose static transform is being requested
4411 * @param t The Transformation which will hold the result
4412 * @return true if the transformation was set, false otherwise
Romain Guy8506ab42009-06-11 17:35:47 -07004413 * @see #setStaticTransformationsEnabled(boolean)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004414 */
4415 protected boolean getChildStaticTransformation(View child, Transformation t) {
4416 return false;
4417 }
4418
Romain Guyf6991302013-06-05 17:19:01 -07004419 Transformation getChildTransformation() {
4420 if (mChildTransformation == null) {
4421 mChildTransformation = new Transformation();
4422 }
4423 return mChildTransformation;
4424 }
4425
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004426 /**
4427 * {@hide}
4428 */
4429 @Override
Alan Viverette8e1a7292017-02-27 10:57:58 -05004430 protected <T extends View> T findViewTraversal(@IdRes int id) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004431 if (id == mID) {
Alan Viverette8e1a7292017-02-27 10:57:58 -05004432 return (T) this;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004433 }
4434
4435 final View[] where = mChildren;
4436 final int len = mChildrenCount;
4437
4438 for (int i = 0; i < len; i++) {
4439 View v = where[i];
4440
Dianne Hackborn4702a852012-08-17 15:18:29 -07004441 if ((v.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004442 v = v.findViewById(id);
4443
4444 if (v != null) {
Alan Viverette8e1a7292017-02-27 10:57:58 -05004445 return (T) v;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004446 }
4447 }
4448 }
4449
4450 return null;
4451 }
4452
4453 /**
4454 * {@hide}
4455 */
4456 @Override
Alan Viverette8e1a7292017-02-27 10:57:58 -05004457 protected <T extends View> T findViewWithTagTraversal(Object tag) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004458 if (tag != null && tag.equals(mTag)) {
Alan Viverette8e1a7292017-02-27 10:57:58 -05004459 return (T) this;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004460 }
4461
4462 final View[] where = mChildren;
4463 final int len = mChildrenCount;
4464
4465 for (int i = 0; i < len; i++) {
4466 View v = where[i];
4467
Dianne Hackborn4702a852012-08-17 15:18:29 -07004468 if ((v.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004469 v = v.findViewWithTag(tag);
4470
4471 if (v != null) {
Alan Viverette8e1a7292017-02-27 10:57:58 -05004472 return (T) v;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004473 }
4474 }
4475 }
4476
4477 return null;
4478 }
4479
4480 /**
Jeff Brown4e6319b2010-12-13 10:36:51 -08004481 * {@hide}
4482 */
4483 @Override
Alan Viverette8e1a7292017-02-27 10:57:58 -05004484 protected <T extends View> T findViewByPredicateTraversal(Predicate<View> predicate,
4485 View childToSkip) {
Paul Duffinca4964c2017-02-07 15:04:10 +00004486 if (predicate.test(this)) {
Alan Viverette8e1a7292017-02-27 10:57:58 -05004487 return (T) this;
Jeff Brown4e6319b2010-12-13 10:36:51 -08004488 }
4489
4490 final View[] where = mChildren;
4491 final int len = mChildrenCount;
4492
4493 for (int i = 0; i < len; i++) {
4494 View v = where[i];
4495
Dianne Hackborn4702a852012-08-17 15:18:29 -07004496 if (v != childToSkip && (v.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
Jeff Brown4e6319b2010-12-13 10:36:51 -08004497 v = v.findViewByPredicate(predicate);
4498
4499 if (v != null) {
Alan Viverette8e1a7292017-02-27 10:57:58 -05004500 return (T) v;
Jeff Brown4e6319b2010-12-13 10:36:51 -08004501 }
4502 }
4503 }
4504
4505 return null;
4506 }
4507
4508 /**
Chet Haasec633d2f2015-04-07 10:29:39 -07004509 * This method adds a view to this container at the specified index purely for the
4510 * purposes of allowing that view to draw even though it is not a normal child of
4511 * the container. That is, the view does not participate in layout, focus, accessibility,
4512 * input, or other normal view operations; it is purely an item to be drawn during the normal
4513 * rendering operation of this container. The index that it is added at is the order
4514 * in which it will be drawn, with respect to the other views in the container.
4515 * For example, a transient view added at index 0 will be drawn before all other views
4516 * in the container because it will be drawn first (including before any real view
4517 * at index 0). There can be more than one transient view at any particular index;
4518 * these views will be drawn in the order in which they were added to the list of
4519 * transient views. The index of transient views can also be greater than the number
4520 * of normal views in the container; that just means that they will be drawn after all
4521 * other views are drawn.
4522 *
4523 * <p>Note that since transient views do not participate in layout, they must be sized
4524 * manually or, more typically, they should just use the size that they had before they
4525 * were removed from their container.</p>
4526 *
4527 * <p>Transient views are useful for handling animations of views that have been removed
4528 * from the container, but which should be animated out after the removal. Adding these
4529 * views as transient views allows them to participate in drawing without side-effecting
4530 * the layout of the container.</p>
4531 *
4532 * <p>Transient views must always be explicitly {@link #removeTransientView(View) removed}
4533 * from the container when they are no longer needed. For example, a transient view
4534 * which is added in order to fade it out in its old location should be removed
4535 * once the animation is complete.</p>
4536 *
4537 * @param view The view to be added
4538 * @param index The index at which this view should be drawn, must be >= 0.
4539 * This value is relative to the {@link #getChildAt(int) index} values in the normal
4540 * child list of this container, where any transient view at a particular index will
4541 * be drawn before any normal child at that same index.
Chris Craik66b41392015-04-17 10:08:10 -07004542 *
4543 * @hide
Chet Haasec633d2f2015-04-07 10:29:39 -07004544 */
4545 public void addTransientView(View view, int index) {
4546 if (index < 0) {
4547 return;
4548 }
4549 if (mTransientIndices == null) {
4550 mTransientIndices = new ArrayList<Integer>();
4551 mTransientViews = new ArrayList<View>();
4552 }
4553 final int oldSize = mTransientIndices.size();
4554 if (oldSize > 0) {
4555 int insertionIndex;
4556 for (insertionIndex = 0; insertionIndex < oldSize; ++insertionIndex) {
4557 if (index < mTransientIndices.get(insertionIndex)) {
4558 break;
4559 }
4560 }
4561 mTransientIndices.add(insertionIndex, index);
4562 mTransientViews.add(insertionIndex, view);
4563 } else {
4564 mTransientIndices.add(index);
4565 mTransientViews.add(view);
4566 }
4567 view.mParent = this;
4568 view.dispatchAttachedToWindow(mAttachInfo, (mViewFlags&VISIBILITY_MASK));
4569 invalidate(true);
4570 }
4571
4572 /**
4573 * Removes a view from the list of transient views in this container. If there is no
4574 * such transient view, this method does nothing.
4575 *
4576 * @param view The transient view to be removed
Chris Craik66b41392015-04-17 10:08:10 -07004577 *
4578 * @hide
Chet Haasec633d2f2015-04-07 10:29:39 -07004579 */
4580 public void removeTransientView(View view) {
4581 if (mTransientViews == null) {
4582 return;
4583 }
4584 final int size = mTransientViews.size();
4585 for (int i = 0; i < size; ++i) {
4586 if (view == mTransientViews.get(i)) {
4587 mTransientViews.remove(i);
4588 mTransientIndices.remove(i);
4589 view.mParent = null;
4590 view.dispatchDetachedFromWindow();
4591 invalidate(true);
4592 return;
4593 }
4594 }
4595 }
4596
4597 /**
4598 * Returns the number of transient views in this container. Specific transient
4599 * views and the index at which they were added can be retrieved via
4600 * {@link #getTransientView(int)} and {@link #getTransientViewIndex(int)}.
4601 *
4602 * @see #addTransientView(View, int)
4603 * @return The number of transient views in this container
Chris Craik66b41392015-04-17 10:08:10 -07004604 *
4605 * @hide
Chet Haasec633d2f2015-04-07 10:29:39 -07004606 */
4607 public int getTransientViewCount() {
4608 return mTransientIndices == null ? 0 : mTransientIndices.size();
4609 }
4610
4611 /**
4612 * Given a valid position within the list of transient views, returns the index of
4613 * the transient view at that position.
4614 *
4615 * @param position The position of the index being queried. Must be at least 0
4616 * and less than the value returned by {@link #getTransientViewCount()}.
4617 * @return The index of the transient view stored in the given position if the
4618 * position is valid, otherwise -1
Chris Craik66b41392015-04-17 10:08:10 -07004619 *
4620 * @hide
Chet Haasec633d2f2015-04-07 10:29:39 -07004621 */
4622 public int getTransientViewIndex(int position) {
4623 if (position < 0 || mTransientIndices == null || position >= mTransientIndices.size()) {
4624 return -1;
4625 }
4626 return mTransientIndices.get(position);
4627 }
4628
4629 /**
4630 * Given a valid position within the list of transient views, returns the
4631 * transient view at that position.
4632 *
4633 * @param position The position of the view being queried. Must be at least 0
4634 * and less than the value returned by {@link #getTransientViewCount()}.
4635 * @return The transient view stored in the given position if the
4636 * position is valid, otherwise null
Chris Craik66b41392015-04-17 10:08:10 -07004637 *
4638 * @hide
Chet Haasec633d2f2015-04-07 10:29:39 -07004639 */
4640 public View getTransientView(int position) {
4641 if (mTransientViews == null || position >= mTransientViews.size()) {
4642 return null;
4643 }
4644 return mTransientViews.get(position);
4645 }
4646
4647 /**
Romain Guy393a52c2012-05-22 20:21:08 -07004648 * <p>Adds a child view. If no layout parameters are already set on the child, the
4649 * default parameters for this ViewGroup are set on the child.</p>
Filip Gruszczynskia33bdf32015-11-19 18:22:16 -08004650 *
Romain Guy393a52c2012-05-22 20:21:08 -07004651 * <p><strong>Note:</strong> do not invoke this method from
4652 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
4653 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004654 *
4655 * @param child the child view to add
4656 *
4657 * @see #generateDefaultLayoutParams()
4658 */
4659 public void addView(View child) {
4660 addView(child, -1);
4661 }
4662
4663 /**
4664 * Adds a child view. If no layout parameters are already set on the child, the
4665 * default parameters for this ViewGroup are set on the child.
Filip Gruszczynskia33bdf32015-11-19 18:22:16 -08004666 *
Romain Guy393a52c2012-05-22 20:21:08 -07004667 * <p><strong>Note:</strong> do not invoke this method from
4668 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
4669 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004670 *
4671 * @param child the child view to add
4672 * @param index the position at which to add the child
4673 *
4674 * @see #generateDefaultLayoutParams()
4675 */
4676 public void addView(View child, int index) {
Adam Powell45a9da52014-10-09 09:44:18 -07004677 if (child == null) {
4678 throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup");
4679 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004680 LayoutParams params = child.getLayoutParams();
4681 if (params == null) {
4682 params = generateDefaultLayoutParams();
4683 if (params == null) {
4684 throw new IllegalArgumentException("generateDefaultLayoutParams() cannot return null");
4685 }
4686 }
4687 addView(child, index, params);
4688 }
4689
4690 /**
4691 * Adds a child view with this ViewGroup's default layout parameters and the
4692 * specified width and height.
4693 *
Romain Guy393a52c2012-05-22 20:21:08 -07004694 * <p><strong>Note:</strong> do not invoke this method from
4695 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
4696 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
4697 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004698 * @param child the child view to add
4699 */
4700 public void addView(View child, int width, int height) {
4701 final LayoutParams params = generateDefaultLayoutParams();
4702 params.width = width;
4703 params.height = height;
4704 addView(child, -1, params);
4705 }
4706
4707 /**
4708 * Adds a child view with the specified layout parameters.
4709 *
Romain Guy393a52c2012-05-22 20:21:08 -07004710 * <p><strong>Note:</strong> do not invoke this method from
4711 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
4712 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
4713 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004714 * @param child the child view to add
4715 * @param params the layout parameters to set on the child
4716 */
Alan Viverettebe463f22016-01-21 10:50:10 -05004717 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004718 public void addView(View child, LayoutParams params) {
4719 addView(child, -1, params);
4720 }
4721
4722 /**
4723 * Adds a child view with the specified layout parameters.
4724 *
Romain Guy393a52c2012-05-22 20:21:08 -07004725 * <p><strong>Note:</strong> do not invoke this method from
4726 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
4727 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
4728 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004729 * @param child the child view to add
Alan Viverette77bb6f12015-02-11 17:24:33 -08004730 * @param index the position at which to add the child or -1 to add last
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004731 * @param params the layout parameters to set on the child
4732 */
4733 public void addView(View child, int index, LayoutParams params) {
4734 if (DBG) {
4735 System.out.println(this + " addView");
4736 }
4737
Adam Powell45a9da52014-10-09 09:44:18 -07004738 if (child == null) {
4739 throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup");
4740 }
4741
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004742 // addViewInner() will call child.requestLayout() when setting the new LayoutParams
4743 // therefore, we call requestLayout() on ourselves before, so that the child's request
4744 // will be blocked at our level
4745 requestLayout();
Romain Guy849d0a32011-02-01 17:20:48 -08004746 invalidate(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004747 addViewInner(child, index, params, false);
4748 }
4749
Alan Viverettebe463f22016-01-21 10:50:10 -05004750 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004751 public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
4752 if (!checkLayoutParams(params)) {
4753 throw new IllegalArgumentException("Invalid LayoutParams supplied to " + this);
4754 }
4755 if (view.mParent != this) {
4756 throw new IllegalArgumentException("Given view not a child of " + this);
4757 }
4758 view.setLayoutParams(params);
4759 }
4760
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004761 protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
4762 return p != null;
4763 }
4764
4765 /**
4766 * Interface definition for a callback to be invoked when the hierarchy
4767 * within this view changed. The hierarchy changes whenever a child is added
4768 * to or removed from this view.
4769 */
4770 public interface OnHierarchyChangeListener {
4771 /**
4772 * Called when a new child is added to a parent view.
4773 *
4774 * @param parent the view in which a child was added
4775 * @param child the new child view added in the hierarchy
4776 */
4777 void onChildViewAdded(View parent, View child);
4778
4779 /**
4780 * Called when a child is removed from a parent view.
4781 *
4782 * @param parent the view from which the child was removed
4783 * @param child the child removed from the hierarchy
4784 */
4785 void onChildViewRemoved(View parent, View child);
4786 }
4787
4788 /**
4789 * Register a callback to be invoked when a child is added to or removed
4790 * from this view.
4791 *
4792 * @param listener the callback to invoke on hierarchy change
4793 */
4794 public void setOnHierarchyChangeListener(OnHierarchyChangeListener listener) {
4795 mOnHierarchyChangeListener = listener;
4796 }
4797
Adam Powell6690d012015-06-17 16:41:56 -07004798 void dispatchViewAdded(View child) {
4799 onViewAdded(child);
Philip Milnef51d91c2011-07-18 16:12:19 -07004800 if (mOnHierarchyChangeListener != null) {
4801 mOnHierarchyChangeListener.onChildViewAdded(this, child);
4802 }
4803 }
4804
4805 /**
Adam Powell6690d012015-06-17 16:41:56 -07004806 * Called when a new child is added to this ViewGroup. Overrides should always
4807 * call super.onViewAdded.
4808 *
4809 * @param child the added child view
Philip Milnef51d91c2011-07-18 16:12:19 -07004810 */
Adam Powell6690d012015-06-17 16:41:56 -07004811 public void onViewAdded(View child) {
4812 }
4813
4814 void dispatchViewRemoved(View child) {
4815 onViewRemoved(child);
Philip Milnef51d91c2011-07-18 16:12:19 -07004816 if (mOnHierarchyChangeListener != null) {
4817 mOnHierarchyChangeListener.onChildViewRemoved(this, child);
4818 }
4819 }
4820
Adam Powell6690d012015-06-17 16:41:56 -07004821 /**
4822 * Called when a child view is removed from this ViewGroup. Overrides should always
4823 * call super.onViewRemoved.
4824 *
4825 * @param child the removed child view
4826 */
4827 public void onViewRemoved(View child) {
4828 }
4829
Philip Milnecfb631b2012-10-26 10:51:46 -07004830 private void clearCachedLayoutMode() {
Svetoslav6254f482013-06-04 17:22:14 -07004831 if (!hasBooleanFlag(FLAG_LAYOUT_MODE_WAS_EXPLICITLY_SET)) {
Philip Milnecfb631b2012-10-26 10:51:46 -07004832 mLayoutMode = LAYOUT_MODE_UNDEFINED;
4833 }
4834 }
4835
4836 @Override
4837 protected void onAttachedToWindow() {
4838 super.onAttachedToWindow();
4839 clearCachedLayoutMode();
4840 }
4841
4842 @Override
4843 protected void onDetachedFromWindow() {
4844 super.onDetachedFromWindow();
4845 clearCachedLayoutMode();
4846 }
4847
John Reck2de950d2017-01-25 10:58:30 -08004848 /** @hide */
4849 @Override
4850 protected void destroyHardwareResources() {
4851 super.destroyHardwareResources();
4852 int count = getChildCount();
4853 for (int i = 0; i < count; i++) {
4854 getChildAt(i).destroyHardwareResources();
4855 }
4856 }
4857
Philip Milnef51d91c2011-07-18 16:12:19 -07004858 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004859 * Adds a view during layout. This is useful if in your onLayout() method,
4860 * you need to add more views (as does the list view for example).
4861 *
4862 * If index is negative, it means put it at the end of the list.
4863 *
4864 * @param child the view to add to the group
Alan Viverette77bb6f12015-02-11 17:24:33 -08004865 * @param index the index at which the child must be added or -1 to add last
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004866 * @param params the layout parameters to associate with the child
4867 * @return true if the child was added, false otherwise
4868 */
4869 protected boolean addViewInLayout(View child, int index, LayoutParams params) {
4870 return addViewInLayout(child, index, params, false);
4871 }
4872
4873 /**
4874 * Adds a view during layout. This is useful if in your onLayout() method,
4875 * you need to add more views (as does the list view for example).
4876 *
4877 * If index is negative, it means put it at the end of the list.
4878 *
4879 * @param child the view to add to the group
Alan Viverette77bb6f12015-02-11 17:24:33 -08004880 * @param index the index at which the child must be added or -1 to add last
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004881 * @param params the layout parameters to associate with the child
4882 * @param preventRequestLayout if true, calling this method will not trigger a
4883 * layout request on child
4884 * @return true if the child was added, false otherwise
4885 */
4886 protected boolean addViewInLayout(View child, int index, LayoutParams params,
4887 boolean preventRequestLayout) {
Adam Powell45a9da52014-10-09 09:44:18 -07004888 if (child == null) {
4889 throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup");
4890 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004891 child.mParent = null;
4892 addViewInner(child, index, params, preventRequestLayout);
Dianne Hackborn4702a852012-08-17 15:18:29 -07004893 child.mPrivateFlags = (child.mPrivateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004894 return true;
4895 }
4896
4897 /**
4898 * Prevents the specified child to be laid out during the next layout pass.
4899 *
4900 * @param child the child on which to perform the cleanup
4901 */
4902 protected void cleanupLayoutState(View child) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07004903 child.mPrivateFlags &= ~View.PFLAG_FORCE_LAYOUT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004904 }
4905
4906 private void addViewInner(View child, int index, LayoutParams params,
4907 boolean preventRequestLayout) {
4908
Chet Haasee8e45d32011-03-02 17:07:35 -08004909 if (mTransition != null) {
4910 // Don't prevent other add transitions from completing, but cancel remove
4911 // transitions to let them complete the process before we add to the container
4912 mTransition.cancel(LayoutTransition.DISAPPEARING);
Chet Haaseadd65772011-02-09 16:47:29 -08004913 }
4914
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004915 if (child.getParent() != null) {
4916 throw new IllegalStateException("The specified child already has a parent. " +
4917 "You must call removeView() on the child's parent first.");
4918 }
4919
Chet Haase21cd1382010-09-01 17:42:29 -07004920 if (mTransition != null) {
Chet Haase5e25c2c2010-09-16 11:15:56 -07004921 mTransition.addChild(this, child);
Chet Haase21cd1382010-09-01 17:42:29 -07004922 }
4923
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004924 if (!checkLayoutParams(params)) {
4925 params = generateLayoutParams(params);
4926 }
4927
4928 if (preventRequestLayout) {
4929 child.mLayoutParams = params;
4930 } else {
4931 child.setLayoutParams(params);
4932 }
4933
4934 if (index < 0) {
4935 index = mChildrenCount;
4936 }
4937
4938 addInArray(child, index);
4939
4940 // tell our children
4941 if (preventRequestLayout) {
4942 child.assignParent(this);
4943 } else {
4944 child.mParent = this;
4945 }
4946
Evan Rosky2ae1bf52017-05-11 11:18:45 -07004947 final boolean childHasFocus = child.hasFocus();
4948 if (childHasFocus) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004949 requestChildFocus(child, child.findFocus());
4950 }
Romain Guy8506ab42009-06-11 17:35:47 -07004951
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004952 AttachInfo ai = mAttachInfo;
Adam Powell4b867882011-09-16 12:59:46 -07004953 if (ai != null && (mGroupFlags & FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW) == 0) {
Romain Guy8506ab42009-06-11 17:35:47 -07004954 boolean lastKeepOn = ai.mKeepScreenOn;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004955 ai.mKeepScreenOn = false;
4956 child.dispatchAttachedToWindow(mAttachInfo, (mViewFlags&VISIBILITY_MASK));
4957 if (ai.mKeepScreenOn) {
4958 needGlobalAttributesUpdate(true);
4959 }
4960 ai.mKeepScreenOn = lastKeepOn;
4961 }
4962
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07004963 if (child.isLayoutDirectionInherited()) {
Fabrice Di Meglioa7e0bcd2012-10-16 19:55:01 -07004964 child.resetRtlProperties();
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07004965 }
4966
Adam Powell6690d012015-06-17 16:41:56 -07004967 dispatchViewAdded(child);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004968
4969 if ((child.mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE) {
4970 mGroupFlags |= FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE;
4971 }
Adam Powell539ee872012-02-03 19:00:49 -08004972
4973 if (child.hasTransientState()) {
4974 childHasTransientStateChanged(child, true);
4975 }
Svetoslav6254f482013-06-04 17:22:14 -07004976
Svetoslav8e3feb12014-02-24 13:46:47 -08004977 if (child.getVisibility() != View.GONE) {
Svetoslav00dbe812013-06-10 12:51:09 -07004978 notifySubtreeAccessibilityStateChangedIfNeeded();
Svetoslav6254f482013-06-04 17:22:14 -07004979 }
Chet Haasec633d2f2015-04-07 10:29:39 -07004980
4981 if (mTransientIndices != null) {
4982 final int transientCount = mTransientIndices.size();
4983 for (int i = 0; i < transientCount; ++i) {
4984 final int oldIndex = mTransientIndices.get(i);
4985 if (index <= oldIndex) {
4986 mTransientIndices.set(i, oldIndex + 1);
4987 }
4988 }
4989 }
Vadim Tryshev02ed4a02015-10-23 17:39:33 -07004990
4991 if (mCurrentDragStartEvent != null && child.getVisibility() == VISIBLE) {
4992 notifyChildOfDragStart(child);
4993 }
Vadim Tryshev5ca73982017-01-04 17:24:43 -08004994
4995 if (child.hasDefaultFocus()) {
4996 // When adding a child that contains default focus, either during inflation or while
4997 // manually assembling the hierarchy, update the ancestor default-focus chain.
4998 setDefaultFocus(child);
4999 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005000 }
5001
5002 private void addInArray(View child, int index) {
5003 View[] children = mChildren;
5004 final int count = mChildrenCount;
5005 final int size = children.length;
5006 if (index == count) {
5007 if (size == count) {
5008 mChildren = new View[size + ARRAY_CAPACITY_INCREMENT];
5009 System.arraycopy(children, 0, mChildren, 0, size);
5010 children = mChildren;
5011 }
5012 children[mChildrenCount++] = child;
5013 } else if (index < count) {
5014 if (size == count) {
5015 mChildren = new View[size + ARRAY_CAPACITY_INCREMENT];
5016 System.arraycopy(children, 0, mChildren, 0, index);
5017 System.arraycopy(children, index, mChildren, index + 1, count - index);
5018 children = mChildren;
5019 } else {
5020 System.arraycopy(children, index, children, index + 1, count - index);
5021 }
5022 children[index] = child;
5023 mChildrenCount++;
Joe Onorato03ab0c72011-01-06 15:46:27 -08005024 if (mLastTouchDownIndex >= index) {
5025 mLastTouchDownIndex++;
5026 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005027 } else {
5028 throw new IndexOutOfBoundsException("index=" + index + " count=" + count);
5029 }
5030 }
5031
5032 // This method also sets the child's mParent to null
5033 private void removeFromArray(int index) {
5034 final View[] children = mChildren;
Chet Haase21cd1382010-09-01 17:42:29 -07005035 if (!(mTransitioningViews != null && mTransitioningViews.contains(children[index]))) {
5036 children[index].mParent = null;
5037 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005038 final int count = mChildrenCount;
5039 if (index == count - 1) {
5040 children[--mChildrenCount] = null;
5041 } else if (index >= 0 && index < count) {
5042 System.arraycopy(children, index + 1, children, index, count - index - 1);
5043 children[--mChildrenCount] = null;
5044 } else {
5045 throw new IndexOutOfBoundsException();
5046 }
Joe Onorato03ab0c72011-01-06 15:46:27 -08005047 if (mLastTouchDownIndex == index) {
5048 mLastTouchDownTime = 0;
5049 mLastTouchDownIndex = -1;
5050 } else if (mLastTouchDownIndex > index) {
5051 mLastTouchDownIndex--;
5052 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005053 }
5054
5055 // This method also sets the children's mParent to null
5056 private void removeFromArray(int start, int count) {
5057 final View[] children = mChildren;
5058 final int childrenCount = mChildrenCount;
5059
5060 start = Math.max(0, start);
5061 final int end = Math.min(childrenCount, start + count);
5062
5063 if (start == end) {
5064 return;
5065 }
5066
5067 if (end == childrenCount) {
5068 for (int i = start; i < end; i++) {
5069 children[i].mParent = null;
5070 children[i] = null;
5071 }
5072 } else {
5073 for (int i = start; i < end; i++) {
5074 children[i].mParent = null;
5075 }
5076
5077 // Since we're looping above, we might as well do the copy, but is arraycopy()
5078 // faster than the extra 2 bounds checks we would do in the loop?
5079 System.arraycopy(children, end, children, start, childrenCount - end);
5080
5081 for (int i = childrenCount - (end - start); i < childrenCount; i++) {
5082 children[i] = null;
5083 }
5084 }
5085
5086 mChildrenCount -= (end - start);
5087 }
5088
5089 private void bindLayoutAnimation(View child) {
5090 Animation a = mLayoutAnimationController.getAnimationForView(child);
5091 child.setAnimation(a);
5092 }
5093
5094 /**
5095 * Subclasses should override this method to set layout animation
5096 * parameters on the supplied child.
5097 *
5098 * @param child the child to associate with animation parameters
5099 * @param params the child's layout parameters which hold the animation
5100 * parameters
5101 * @param index the index of the child in the view group
5102 * @param count the number of children in the view group
5103 */
5104 protected void attachLayoutAnimationParameters(View child,
5105 LayoutParams params, int index, int count) {
5106 LayoutAnimationController.AnimationParameters animationParams =
5107 params.layoutAnimationParameters;
5108 if (animationParams == null) {
5109 animationParams = new LayoutAnimationController.AnimationParameters();
5110 params.layoutAnimationParameters = animationParams;
5111 }
5112
5113 animationParams.count = count;
5114 animationParams.index = index;
5115 }
5116
5117 /**
5118 * {@inheritDoc}
Filip Gruszczynskia33bdf32015-11-19 18:22:16 -08005119 *
Romain Guy393a52c2012-05-22 20:21:08 -07005120 * <p><strong>Note:</strong> do not invoke this method from
5121 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
5122 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005123 */
Alan Viverettebe463f22016-01-21 10:50:10 -05005124 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005125 public void removeView(View view) {
Alan Viverette177ec4602014-10-17 13:34:50 -07005126 if (removeViewInternal(view)) {
5127 requestLayout();
5128 invalidate(true);
5129 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005130 }
5131
5132 /**
5133 * Removes a view during layout. This is useful if in your onLayout() method,
5134 * you need to remove more views.
5135 *
Romain Guy393a52c2012-05-22 20:21:08 -07005136 * <p><strong>Note:</strong> do not invoke this method from
5137 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
5138 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
Filip Gruszczynskia33bdf32015-11-19 18:22:16 -08005139 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005140 * @param view the view to remove from the group
5141 */
5142 public void removeViewInLayout(View view) {
5143 removeViewInternal(view);
5144 }
5145
5146 /**
5147 * Removes a range of views during layout. This is useful if in your onLayout() method,
5148 * you need to remove more views.
5149 *
Romain Guy393a52c2012-05-22 20:21:08 -07005150 * <p><strong>Note:</strong> do not invoke this method from
5151 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
5152 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
5153 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005154 * @param start the index of the first view to remove from the group
5155 * @param count the number of views to remove from the group
5156 */
5157 public void removeViewsInLayout(int start, int count) {
5158 removeViewsInternal(start, count);
5159 }
5160
5161 /**
5162 * Removes the view at the specified position in the group.
5163 *
Romain Guy393a52c2012-05-22 20:21:08 -07005164 * <p><strong>Note:</strong> do not invoke this method from
5165 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
5166 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
Filip Gruszczynskia33bdf32015-11-19 18:22:16 -08005167 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005168 * @param index the position in the group of the view to remove
5169 */
5170 public void removeViewAt(int index) {
5171 removeViewInternal(index, getChildAt(index));
5172 requestLayout();
Romain Guy849d0a32011-02-01 17:20:48 -08005173 invalidate(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005174 }
5175
5176 /**
5177 * Removes the specified range of views from the group.
5178 *
Romain Guy393a52c2012-05-22 20:21:08 -07005179 * <p><strong>Note:</strong> do not invoke this method from
5180 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
5181 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
5182 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005183 * @param start the first position in the group of the range of views to remove
5184 * @param count the number of views to remove
5185 */
5186 public void removeViews(int start, int count) {
5187 removeViewsInternal(start, count);
5188 requestLayout();
Romain Guy849d0a32011-02-01 17:20:48 -08005189 invalidate(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005190 }
5191
Alan Viverette177ec4602014-10-17 13:34:50 -07005192 private boolean removeViewInternal(View view) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005193 final int index = indexOfChild(view);
5194 if (index >= 0) {
5195 removeViewInternal(index, view);
Alan Viverette177ec4602014-10-17 13:34:50 -07005196 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005197 }
Alan Viverette177ec4602014-10-17 13:34:50 -07005198 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005199 }
5200
5201 private void removeViewInternal(int index, View view) {
Chet Haase21cd1382010-09-01 17:42:29 -07005202 if (mTransition != null) {
Chet Haase5e25c2c2010-09-16 11:15:56 -07005203 mTransition.removeChild(this, view);
Chet Haase21cd1382010-09-01 17:42:29 -07005204 }
5205
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005206 boolean clearChildFocus = false;
5207 if (view == mFocused) {
Alan Viverette223622a2013-12-17 13:29:02 -08005208 view.unFocus(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005209 clearChildFocus = true;
5210 }
Evan Rosky53fcf112017-01-26 14:37:55 -08005211 if (view == mFocusedInCluster) {
Evan Rosky0e8a6832017-04-10 12:35:15 -07005212 clearFocusedInCluster(view);
Vadim Tryshev01d8c492016-12-15 11:33:15 -08005213 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005214
Alan Viverette632af842014-10-28 13:45:11 -07005215 view.clearAccessibilityFocus();
Svetoslav Ganov961bf0e2012-05-08 09:40:03 -07005216
Jeff Brown59a422e2012-04-19 15:19:19 -07005217 cancelTouchTarget(view);
5218 cancelHoverTarget(view);
5219
Chet Haase21cd1382010-09-01 17:42:29 -07005220 if (view.getAnimation() != null ||
5221 (mTransitioningViews != null && mTransitioningViews.contains(view))) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005222 addDisappearingView(view);
5223 } else if (view.mAttachInfo != null) {
5224 view.dispatchDetachedFromWindow();
5225 }
5226
Adam Powell539ee872012-02-03 19:00:49 -08005227 if (view.hasTransientState()) {
5228 childHasTransientStateChanged(view, false);
5229 }
5230
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005231 needGlobalAttributesUpdate(false);
Romain Guy8506ab42009-06-11 17:35:47 -07005232
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005233 removeFromArray(index);
5234
Evan Rosky53fcf112017-01-26 14:37:55 -08005235 if (view == mDefaultFocus) {
5236 clearDefaultFocus(view);
5237 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005238 if (clearChildFocus) {
5239 clearChildFocus(view);
Svetoslav Ganov149567f2013-01-08 15:23:34 -08005240 if (!rootViewRequestFocus()) {
5241 notifyGlobalFocusCleared(this);
5242 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07005243 }
Romain Guy6fb05632012-11-29 10:50:33 -08005244
Adam Powell6690d012015-06-17 16:41:56 -07005245 dispatchViewRemoved(view);
Svetoslav6254f482013-06-04 17:22:14 -07005246
Svetoslav8e3feb12014-02-24 13:46:47 -08005247 if (view.getVisibility() != View.GONE) {
Svetoslav00dbe812013-06-10 12:51:09 -07005248 notifySubtreeAccessibilityStateChangedIfNeeded();
Svetoslav6254f482013-06-04 17:22:14 -07005249 }
Chet Haasec633d2f2015-04-07 10:29:39 -07005250
5251 int transientCount = mTransientIndices == null ? 0 : mTransientIndices.size();
5252 for (int i = 0; i < transientCount; ++i) {
5253 final int oldIndex = mTransientIndices.get(i);
5254 if (index < oldIndex) {
5255 mTransientIndices.set(i, oldIndex - 1);
5256 }
5257 }
Vadim Tryshev02ed4a02015-10-23 17:39:33 -07005258
5259 if (mCurrentDragStartEvent != null) {
5260 mChildrenInterestedInDrag.remove(view);
5261 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005262 }
5263
Chet Haase21cd1382010-09-01 17:42:29 -07005264 /**
5265 * Sets the LayoutTransition object for this ViewGroup. If the LayoutTransition object is
5266 * not null, changes in layout which occur because of children being added to or removed from
5267 * the ViewGroup will be animated according to the animations defined in that LayoutTransition
5268 * object. By default, the transition object is null (so layout changes are not animated).
5269 *
Chet Haaseef3cbfd2013-08-21 14:01:02 -07005270 * <p>Replacing a non-null transition will cause that previous transition to be
5271 * canceled, if it is currently running, to restore this container to
5272 * its correct post-transition state.</p>
5273 *
Chet Haase21cd1382010-09-01 17:42:29 -07005274 * @param transition The LayoutTransition object that will animated changes in layout. A value
5275 * of <code>null</code> means no transition will run on layout changes.
Chet Haase13cc1202010-09-03 15:39:20 -07005276 * @attr ref android.R.styleable#ViewGroup_animateLayoutChanges
Chet Haase21cd1382010-09-01 17:42:29 -07005277 */
5278 public void setLayoutTransition(LayoutTransition transition) {
Chet Haaseb20db3e2010-09-10 13:07:30 -07005279 if (mTransition != null) {
Chet Haasefee6f2b2013-08-27 12:22:29 -07005280 LayoutTransition previousTransition = mTransition;
5281 previousTransition.cancel();
5282 previousTransition.removeTransitionListener(mLayoutTransitionListener);
Chet Haaseb20db3e2010-09-10 13:07:30 -07005283 }
Chet Haase21cd1382010-09-01 17:42:29 -07005284 mTransition = transition;
Chet Haase13cc1202010-09-03 15:39:20 -07005285 if (mTransition != null) {
5286 mTransition.addTransitionListener(mLayoutTransitionListener);
5287 }
5288 }
5289
5290 /**
5291 * Gets the LayoutTransition object for this ViewGroup. If the LayoutTransition object is
5292 * not null, changes in layout which occur because of children being added to or removed from
5293 * the ViewGroup will be animated according to the animations defined in that LayoutTransition
5294 * object. By default, the transition object is null (so layout changes are not animated).
5295 *
5296 * @return LayoutTranstion The LayoutTransition object that will animated changes in layout.
5297 * A value of <code>null</code> means no transition will run on layout changes.
5298 */
5299 public LayoutTransition getLayoutTransition() {
5300 return mTransition;
Chet Haase21cd1382010-09-01 17:42:29 -07005301 }
5302
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005303 private void removeViewsInternal(int start, int count) {
Chris Craik18a759d2015-10-14 14:16:33 -07005304 final int end = start + count;
5305
5306 if (start < 0 || count < 0 || end > mChildrenCount) {
5307 throw new IndexOutOfBoundsException();
5308 }
5309
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005310 final View focused = mFocused;
5311 final boolean detach = mAttachInfo != null;
Svetoslav Ganov149567f2013-01-08 15:23:34 -08005312 boolean clearChildFocus = false;
Evan Rosky53fcf112017-01-26 14:37:55 -08005313 View clearDefaultFocus = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005314
5315 final View[] children = mChildren;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005316
5317 for (int i = start; i < end; i++) {
5318 final View view = children[i];
5319
Chet Haase21cd1382010-09-01 17:42:29 -07005320 if (mTransition != null) {
Chet Haase5e25c2c2010-09-16 11:15:56 -07005321 mTransition.removeChild(this, view);
Chet Haase21cd1382010-09-01 17:42:29 -07005322 }
5323
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005324 if (view == focused) {
Alan Viverette223622a2013-12-17 13:29:02 -08005325 view.unFocus(null);
Svetoslav Ganov149567f2013-01-08 15:23:34 -08005326 clearChildFocus = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005327 }
Vadim Tryshev5ca73982017-01-04 17:24:43 -08005328 if (view == mDefaultFocus) {
Evan Rosky53fcf112017-01-26 14:37:55 -08005329 clearDefaultFocus = view;
5330 }
5331 if (view == mFocusedInCluster) {
Evan Rosky0e8a6832017-04-10 12:35:15 -07005332 clearFocusedInCluster(view);
Vadim Tryshev01d8c492016-12-15 11:33:15 -08005333 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005334
Alan Viverette632af842014-10-28 13:45:11 -07005335 view.clearAccessibilityFocus();
Svetoslav Ganov961bf0e2012-05-08 09:40:03 -07005336
Jeff Brown59a422e2012-04-19 15:19:19 -07005337 cancelTouchTarget(view);
5338 cancelHoverTarget(view);
5339
Chet Haase21cd1382010-09-01 17:42:29 -07005340 if (view.getAnimation() != null ||
5341 (mTransitioningViews != null && mTransitioningViews.contains(view))) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005342 addDisappearingView(view);
5343 } else if (detach) {
5344 view.dispatchDetachedFromWindow();
5345 }
5346
Adam Powell539ee872012-02-03 19:00:49 -08005347 if (view.hasTransientState()) {
5348 childHasTransientStateChanged(view, false);
5349 }
5350
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005351 needGlobalAttributesUpdate(false);
Romain Guy8506ab42009-06-11 17:35:47 -07005352
Adam Powell6690d012015-06-17 16:41:56 -07005353 dispatchViewRemoved(view);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005354 }
5355
5356 removeFromArray(start, count);
5357
Evan Rosky53fcf112017-01-26 14:37:55 -08005358 if (clearDefaultFocus != null) {
5359 clearDefaultFocus(clearDefaultFocus);
5360 }
Svetoslav Ganov149567f2013-01-08 15:23:34 -08005361 if (clearChildFocus) {
5362 clearChildFocus(focused);
5363 if (!rootViewRequestFocus()) {
5364 notifyGlobalFocusCleared(focused);
5365 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005366 }
5367 }
5368
5369 /**
5370 * Call this method to remove all child views from the
5371 * ViewGroup.
Filip Gruszczynskia33bdf32015-11-19 18:22:16 -08005372 *
Romain Guy393a52c2012-05-22 20:21:08 -07005373 * <p><strong>Note:</strong> do not invoke this method from
5374 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
5375 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005376 */
5377 public void removeAllViews() {
5378 removeAllViewsInLayout();
5379 requestLayout();
Romain Guy849d0a32011-02-01 17:20:48 -08005380 invalidate(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005381 }
5382
5383 /**
5384 * Called by a ViewGroup subclass to remove child views from itself,
5385 * when it must first know its size on screen before it can calculate how many
5386 * child views it will render. An example is a Gallery or a ListView, which
5387 * may "have" 50 children, but actually only render the number of children
5388 * that can currently fit inside the object on screen. Do not call
5389 * this method unless you are extending ViewGroup and understand the
5390 * view measuring and layout pipeline.
Romain Guy393a52c2012-05-22 20:21:08 -07005391 *
5392 * <p><strong>Note:</strong> do not invoke this method from
5393 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
5394 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005395 */
5396 public void removeAllViewsInLayout() {
5397 final int count = mChildrenCount;
5398 if (count <= 0) {
5399 return;
5400 }
5401
5402 final View[] children = mChildren;
5403 mChildrenCount = 0;
5404
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005405 final View focused = mFocused;
5406 final boolean detach = mAttachInfo != null;
Svetoslav Ganov149567f2013-01-08 15:23:34 -08005407 boolean clearChildFocus = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005408
5409 needGlobalAttributesUpdate(false);
Romain Guy8506ab42009-06-11 17:35:47 -07005410
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005411 for (int i = count - 1; i >= 0; i--) {
5412 final View view = children[i];
5413
Chet Haase21cd1382010-09-01 17:42:29 -07005414 if (mTransition != null) {
Chet Haase5e25c2c2010-09-16 11:15:56 -07005415 mTransition.removeChild(this, view);
Chet Haase21cd1382010-09-01 17:42:29 -07005416 }
5417
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005418 if (view == focused) {
Alan Viverette223622a2013-12-17 13:29:02 -08005419 view.unFocus(null);
Svetoslav Ganov149567f2013-01-08 15:23:34 -08005420 clearChildFocus = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005421 }
5422
Alan Viverette632af842014-10-28 13:45:11 -07005423 view.clearAccessibilityFocus();
Svetoslav Ganov961bf0e2012-05-08 09:40:03 -07005424
Jeff Brown59a422e2012-04-19 15:19:19 -07005425 cancelTouchTarget(view);
5426 cancelHoverTarget(view);
5427
Chet Haase21cd1382010-09-01 17:42:29 -07005428 if (view.getAnimation() != null ||
5429 (mTransitioningViews != null && mTransitioningViews.contains(view))) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005430 addDisappearingView(view);
5431 } else if (detach) {
5432 view.dispatchDetachedFromWindow();
5433 }
5434
Adam Powell539ee872012-02-03 19:00:49 -08005435 if (view.hasTransientState()) {
5436 childHasTransientStateChanged(view, false);
5437 }
5438
Adam Powell6690d012015-06-17 16:41:56 -07005439 dispatchViewRemoved(view);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005440
5441 view.mParent = null;
5442 children[i] = null;
5443 }
5444
Evan Rosky53fcf112017-01-26 14:37:55 -08005445 if (mDefaultFocus != null) {
5446 clearDefaultFocus(mDefaultFocus);
5447 }
Evan Rosky776fa5f2017-04-26 16:47:54 -07005448 if (mFocusedInCluster != null) {
5449 clearFocusedInCluster(mFocusedInCluster);
5450 }
Svetoslav Ganov149567f2013-01-08 15:23:34 -08005451 if (clearChildFocus) {
5452 clearChildFocus(focused);
5453 if (!rootViewRequestFocus()) {
5454 notifyGlobalFocusCleared(focused);
5455 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005456 }
5457 }
5458
5459 /**
5460 * Finishes the removal of a detached view. This method will dispatch the detached from
5461 * window event and notify the hierarchy change listener.
Chet Haaseca479d42012-08-30 17:20:08 -07005462 * <p>
5463 * This method is intended to be lightweight and makes no assumptions about whether the
5464 * parent or child should be redrawn. Proper use of this method will include also making
5465 * any appropriate {@link #requestLayout()} or {@link #invalidate()} calls.
5466 * For example, callers can {@link #post(Runnable) post} a {@link Runnable}
5467 * which performs a {@link #requestLayout()} on the next frame, after all detach/remove
5468 * calls are finished, causing layout to be run prior to redrawing the view hierarchy.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005469 *
5470 * @param child the child to be definitely removed from the view hierarchy
5471 * @param animate if true and the view has an animation, the view is placed in the
5472 * disappearing views list, otherwise, it is detached from the window
5473 *
5474 * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
5475 * @see #detachAllViewsFromParent()
5476 * @see #detachViewFromParent(View)
5477 * @see #detachViewFromParent(int)
5478 */
5479 protected void removeDetachedView(View child, boolean animate) {
Chet Haase21cd1382010-09-01 17:42:29 -07005480 if (mTransition != null) {
Chet Haase5e25c2c2010-09-16 11:15:56 -07005481 mTransition.removeChild(this, child);
Chet Haase21cd1382010-09-01 17:42:29 -07005482 }
5483
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005484 if (child == mFocused) {
5485 child.clearFocus();
5486 }
Vadim Tryshev5ca73982017-01-04 17:24:43 -08005487 if (child == mDefaultFocus) {
Evan Rosky53fcf112017-01-26 14:37:55 -08005488 clearDefaultFocus(child);
5489 }
5490 if (child == mFocusedInCluster) {
Evan Rosky0e8a6832017-04-10 12:35:15 -07005491 clearFocusedInCluster(child);
Vadim Tryshev01d8c492016-12-15 11:33:15 -08005492 }
Romain Guy8506ab42009-06-11 17:35:47 -07005493
Svetoslav Ganov961bf0e2012-05-08 09:40:03 -07005494 child.clearAccessibilityFocus();
5495
Jeff Brown59a422e2012-04-19 15:19:19 -07005496 cancelTouchTarget(child);
5497 cancelHoverTarget(child);
5498
Chet Haase21cd1382010-09-01 17:42:29 -07005499 if ((animate && child.getAnimation() != null) ||
5500 (mTransitioningViews != null && mTransitioningViews.contains(child))) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005501 addDisappearingView(child);
5502 } else if (child.mAttachInfo != null) {
5503 child.dispatchDetachedFromWindow();
5504 }
5505
Adam Powell539ee872012-02-03 19:00:49 -08005506 if (child.hasTransientState()) {
5507 childHasTransientStateChanged(child, false);
5508 }
5509
Adam Powell6690d012015-06-17 16:41:56 -07005510 dispatchViewRemoved(child);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005511 }
5512
5513 /**
5514 * Attaches a view to this view group. Attaching a view assigns this group as the parent,
Chet Haaseca479d42012-08-30 17:20:08 -07005515 * sets the layout parameters and puts the view in the list of children so that
5516 * it can be retrieved by calling {@link #getChildAt(int)}.
5517 * <p>
5518 * This method is intended to be lightweight and makes no assumptions about whether the
5519 * parent or child should be redrawn. Proper use of this method will include also making
5520 * any appropriate {@link #requestLayout()} or {@link #invalidate()} calls.
5521 * For example, callers can {@link #post(Runnable) post} a {@link Runnable}
5522 * which performs a {@link #requestLayout()} on the next frame, after all detach/attach
5523 * calls are finished, causing layout to be run prior to redrawing the view hierarchy.
5524 * <p>
5525 * This method should be called only for views which were detached from their parent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005526 *
5527 * @param child the child to attach
5528 * @param index the index at which the child should be attached
5529 * @param params the layout parameters of the child
5530 *
5531 * @see #removeDetachedView(View, boolean)
5532 * @see #detachAllViewsFromParent()
5533 * @see #detachViewFromParent(View)
5534 * @see #detachViewFromParent(int)
5535 */
5536 protected void attachViewToParent(View child, int index, LayoutParams params) {
5537 child.mLayoutParams = params;
5538
5539 if (index < 0) {
5540 index = mChildrenCount;
5541 }
5542
5543 addInArray(child, index);
5544
5545 child.mParent = this;
Dianne Hackborn4702a852012-08-17 15:18:29 -07005546 child.mPrivateFlags = (child.mPrivateFlags & ~PFLAG_DIRTY_MASK
5547 & ~PFLAG_DRAWING_CACHE_VALID)
5548 | PFLAG_DRAWN | PFLAG_INVALIDATED;
5549 this.mPrivateFlags |= PFLAG_INVALIDATED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005550
5551 if (child.hasFocus()) {
5552 requestChildFocus(child, child.findFocus());
5553 }
Adam Powellc5874092016-03-17 16:27:24 -07005554 dispatchVisibilityAggregated(isAttachedToWindow() && getWindowVisibility() == VISIBLE
5555 && isShown());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005556 }
5557
5558 /**
Chet Haaseca479d42012-08-30 17:20:08 -07005559 * Detaches a view from its parent. Detaching a view should be followed
5560 * either by a call to
5561 * {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
5562 * or a call to {@link #removeDetachedView(View, boolean)}. Detachment should only be
5563 * temporary; reattachment or removal should happen within the same drawing cycle as
5564 * detachment. When a view is detached, its parent is null and cannot be retrieved by a
5565 * call to {@link #getChildAt(int)}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005566 *
5567 * @param child the child to detach
5568 *
5569 * @see #detachViewFromParent(int)
5570 * @see #detachViewsFromParent(int, int)
5571 * @see #detachAllViewsFromParent()
5572 * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
5573 * @see #removeDetachedView(View, boolean)
5574 */
5575 protected void detachViewFromParent(View child) {
5576 removeFromArray(indexOfChild(child));
5577 }
5578
5579 /**
Chet Haaseca479d42012-08-30 17:20:08 -07005580 * Detaches a view from its parent. Detaching a view should be followed
5581 * either by a call to
5582 * {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
5583 * or a call to {@link #removeDetachedView(View, boolean)}. Detachment should only be
5584 * temporary; reattachment or removal should happen within the same drawing cycle as
5585 * detachment. When a view is detached, its parent is null and cannot be retrieved by a
5586 * call to {@link #getChildAt(int)}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005587 *
5588 * @param index the index of the child to detach
5589 *
5590 * @see #detachViewFromParent(View)
5591 * @see #detachAllViewsFromParent()
5592 * @see #detachViewsFromParent(int, int)
5593 * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
5594 * @see #removeDetachedView(View, boolean)
5595 */
5596 protected void detachViewFromParent(int index) {
5597 removeFromArray(index);
5598 }
5599
5600 /**
Chet Haaseca479d42012-08-30 17:20:08 -07005601 * Detaches a range of views from their parents. Detaching a view should be followed
5602 * either by a call to
5603 * {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
5604 * or a call to {@link #removeDetachedView(View, boolean)}. Detachment should only be
5605 * temporary; reattachment or removal should happen within the same drawing cycle as
5606 * detachment. When a view is detached, its parent is null and cannot be retrieved by a
5607 * call to {@link #getChildAt(int)}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005608 *
5609 * @param start the first index of the childrend range to detach
5610 * @param count the number of children to detach
5611 *
5612 * @see #detachViewFromParent(View)
5613 * @see #detachViewFromParent(int)
5614 * @see #detachAllViewsFromParent()
5615 * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
5616 * @see #removeDetachedView(View, boolean)
5617 */
5618 protected void detachViewsFromParent(int start, int count) {
5619 removeFromArray(start, count);
5620 }
5621
5622 /**
Chet Haaseca479d42012-08-30 17:20:08 -07005623 * Detaches all views from the parent. Detaching a view should be followed
5624 * either by a call to
5625 * {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
5626 * or a call to {@link #removeDetachedView(View, boolean)}. Detachment should only be
5627 * temporary; reattachment or removal should happen within the same drawing cycle as
5628 * detachment. When a view is detached, its parent is null and cannot be retrieved by a
5629 * call to {@link #getChildAt(int)}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005630 *
5631 * @see #detachViewFromParent(View)
5632 * @see #detachViewFromParent(int)
5633 * @see #detachViewsFromParent(int, int)
5634 * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
5635 * @see #removeDetachedView(View, boolean)
5636 */
5637 protected void detachAllViewsFromParent() {
5638 final int count = mChildrenCount;
5639 if (count <= 0) {
5640 return;
5641 }
5642
5643 final View[] children = mChildren;
5644 mChildrenCount = 0;
5645
5646 for (int i = count - 1; i >= 0; i--) {
5647 children[i].mParent = null;
5648 children[i] = null;
5649 }
5650 }
5651
Chris Craik9de95db2017-01-18 17:59:23 -08005652 @Override
5653 @CallSuper
5654 public void onDescendantInvalidated(@NonNull View child, @NonNull View target) {
5655 /*
5656 * HW-only, Rect-ignoring damage codepath
5657 *
5658 * We don't deal with rectangles here, since RenderThread native code computes damage for
5659 * everything drawn by HWUI (and SW layer / drawing cache doesn't keep track of damage area)
5660 */
5661
5662 // if set, combine the animation flag into the parent
5663 mPrivateFlags |= (target.mPrivateFlags & PFLAG_DRAW_ANIMATION);
5664
5665 if ((target.mPrivateFlags & ~PFLAG_DIRTY_MASK) != 0) {
5666 // We lazily use PFLAG_DIRTY, since computing opaque isn't worth the potential
5667 // optimization in provides in a DisplayList world.
5668 mPrivateFlags = (mPrivateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DIRTY;
5669
5670 // simplified invalidateChildInParent behavior: clear cache validity to be safe...
5671 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
Chris Craik3f06c6d2017-01-09 18:19:48 +00005672 }
5673
Chris Craik9de95db2017-01-18 17:59:23 -08005674 // ... and mark inval if in software layer that needs to repaint (hw handled in native)
5675 if (mLayerType == LAYER_TYPE_SOFTWARE) {
5676 // Layered parents should be invalidated. Escalate to a full invalidate (and note that
5677 // we do this after consuming any relevant flags from the originating descendant)
5678 mPrivateFlags |= PFLAG_INVALIDATED | PFLAG_DIRTY;
5679 target = this;
Chris Craik3f06c6d2017-01-09 18:19:48 +00005680 }
5681
Chris Craik9de95db2017-01-18 17:59:23 -08005682 if (mParent != null) {
5683 mParent.onDescendantInvalidated(this, target);
Chris Craik3f06c6d2017-01-09 18:19:48 +00005684 }
Chris Craik3f06c6d2017-01-09 18:19:48 +00005685 }
5686
5687
5688 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005689 * Don't call or override this method. It is used for the implementation of
5690 * the view hierarchy.
Chris Craik9de95db2017-01-18 17:59:23 -08005691 *
5692 * @deprecated Use {@link #onDescendantInvalidated(View, View)} instead to observe updates to
5693 * draw state in descendants.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005694 */
Chris Craik9de95db2017-01-18 17:59:23 -08005695 @Deprecated
Alan Viverettebe463f22016-01-21 10:50:10 -05005696 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005697 public final void invalidateChild(View child, final Rect dirty) {
Chris Craik9de95db2017-01-18 17:59:23 -08005698 final AttachInfo attachInfo = mAttachInfo;
5699 if (attachInfo != null && attachInfo.mHardwareAccelerated) {
5700 // HW accelerated fast path
5701 onDescendantInvalidated(child, child);
Chris Craik3f06c6d2017-01-09 18:19:48 +00005702 return;
5703 }
5704
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005705 ViewParent parent = this;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005706 if (attachInfo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005707 // If the child is drawing an animation, we want to copy this flag onto
5708 // ourselves and the parent to make sure the invalidate request goes
5709 // through
Chris Craik3f06c6d2017-01-09 18:19:48 +00005710 final boolean drawAnimation = (child.mPrivateFlags & PFLAG_DRAW_ANIMATION) != 0;
Romain Guy24443ea2009-05-11 11:56:30 -07005711
Romain Guyfe455af2012-02-15 16:40:20 -08005712 // Check whether the child that requests the invalidate is fully opaque
5713 // Views being animated or transformed are not considered opaque because we may
5714 // be invalidating their old position and need the parent to paint behind them.
5715 Matrix childMatrix = child.getMatrix();
5716 final boolean isOpaque = child.isOpaque() && !drawAnimation &&
5717 child.getAnimation() == null && childMatrix.isIdentity();
5718 // Mark the child as dirty, using the appropriate flag
5719 // Make sure we do not set both flags at the same time
Dianne Hackborn4702a852012-08-17 15:18:29 -07005720 int opaqueFlag = isOpaque ? PFLAG_DIRTY_OPAQUE : PFLAG_DIRTY;
Romain Guyfe455af2012-02-15 16:40:20 -08005721
John Reck96bb8ad2014-06-19 10:53:03 -07005722 if (child.mLayerType != LAYER_TYPE_NONE) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07005723 mPrivateFlags |= PFLAG_INVALIDATED;
5724 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
Romain Guyfe455af2012-02-15 16:40:20 -08005725 }
5726
5727 final int[] location = attachInfo.mInvalidateChildLocation;
5728 location[CHILD_LEFT_INDEX] = child.mLeft;
5729 location[CHILD_TOP_INDEX] = child.mTop;
Chet Haase599913d2012-07-23 16:22:05 -07005730 if (!childMatrix.isIdentity() ||
5731 (mGroupFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) {
Romain Guyfe455af2012-02-15 16:40:20 -08005732 RectF boundingRect = attachInfo.mTmpTransformRect;
5733 boundingRect.set(dirty);
Chet Haase599913d2012-07-23 16:22:05 -07005734 Matrix transformMatrix;
5735 if ((mGroupFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) {
5736 Transformation t = attachInfo.mTmpTransformation;
5737 boolean transformed = getChildStaticTransformation(child, t);
5738 if (transformed) {
5739 transformMatrix = attachInfo.mTmpMatrix;
5740 transformMatrix.set(t.getMatrix());
5741 if (!childMatrix.isIdentity()) {
5742 transformMatrix.preConcat(childMatrix);
5743 }
5744 } else {
5745 transformMatrix = childMatrix;
5746 }
5747 } else {
5748 transformMatrix = childMatrix;
5749 }
5750 transformMatrix.mapRect(boundingRect);
Alan Viverettec45b1d42015-11-16 15:38:59 -05005751 dirty.set((int) Math.floor(boundingRect.left),
5752 (int) Math.floor(boundingRect.top),
5753 (int) Math.ceil(boundingRect.right),
5754 (int) Math.ceil(boundingRect.bottom));
Romain Guyfe455af2012-02-15 16:40:20 -08005755 }
5756
5757 do {
5758 View view = null;
5759 if (parent instanceof View) {
5760 view = (View) parent;
Romain Guyfe455af2012-02-15 16:40:20 -08005761 }
5762
5763 if (drawAnimation) {
5764 if (view != null) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07005765 view.mPrivateFlags |= PFLAG_DRAW_ANIMATION;
Romain Guyfe455af2012-02-15 16:40:20 -08005766 } else if (parent instanceof ViewRootImpl) {
5767 ((ViewRootImpl) parent).mIsAnimating = true;
5768 }
5769 }
5770
5771 // If the parent is dirty opaque or not dirty, mark it dirty with the opaque
5772 // flag coming from the child that initiated the invalidate
5773 if (view != null) {
5774 if ((view.mViewFlags & FADING_EDGE_MASK) != 0 &&
5775 view.getSolidColor() == 0) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07005776 opaqueFlag = PFLAG_DIRTY;
Romain Guyfe455af2012-02-15 16:40:20 -08005777 }
Dianne Hackborn4702a852012-08-17 15:18:29 -07005778 if ((view.mPrivateFlags & PFLAG_DIRTY_MASK) != PFLAG_DIRTY) {
5779 view.mPrivateFlags = (view.mPrivateFlags & ~PFLAG_DIRTY_MASK) | opaqueFlag;
Romain Guyfe455af2012-02-15 16:40:20 -08005780 }
5781 }
5782
5783 parent = parent.invalidateChildInParent(location, dirty);
5784 if (view != null) {
5785 // Account for transform on current parent
5786 Matrix m = view.getMatrix();
5787 if (!m.isIdentity()) {
5788 RectF boundingRect = attachInfo.mTmpTransformRect;
5789 boundingRect.set(dirty);
5790 m.mapRect(boundingRect);
Alan Viverettec45b1d42015-11-16 15:38:59 -05005791 dirty.set((int) Math.floor(boundingRect.left),
5792 (int) Math.floor(boundingRect.top),
5793 (int) Math.ceil(boundingRect.right),
5794 (int) Math.ceil(boundingRect.bottom));
Romain Guyfe455af2012-02-15 16:40:20 -08005795 }
5796 }
5797 } while (parent != null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005798 }
5799 }
5800
5801 /**
5802 * Don't call or override this method. It is used for the implementation of
5803 * the view hierarchy.
5804 *
5805 * This implementation returns null if this ViewGroup does not have a parent,
5806 * if this ViewGroup is already fully invalidated or if the dirty rectangle
5807 * does not intersect with this ViewGroup's bounds.
Chris Craik9de95db2017-01-18 17:59:23 -08005808 *
5809 * @deprecated Use {@link #onDescendantInvalidated(View, View)} instead to observe updates to
5810 * draw state in descendants.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005811 */
Chris Craik9de95db2017-01-18 17:59:23 -08005812 @Deprecated
Alan Viverettebe463f22016-01-21 10:50:10 -05005813 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005814 public ViewParent invalidateChildInParent(final int[] location, final Rect dirty) {
Chris Craik3f06c6d2017-01-09 18:19:48 +00005815 if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID)) != 0) {
5816 // either DRAWN, or DRAWING_CACHE_VALID
5817 if ((mGroupFlags & (FLAG_OPTIMIZE_INVALIDATE | FLAG_ANIMATION_DONE))
5818 != FLAG_OPTIMIZE_INVALIDATE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005819 dirty.offset(location[CHILD_LEFT_INDEX] - mScrollX,
5820 location[CHILD_TOP_INDEX] - mScrollY);
Chet Haasea4f14eb2013-04-22 11:11:39 -07005821 if ((mGroupFlags & FLAG_CLIP_CHILDREN) == 0) {
5822 dirty.union(0, 0, mRight - mLeft, mBottom - mTop);
5823 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005824
5825 final int left = mLeft;
5826 final int top = mTop;
5827
Chet Haase05e91ed2012-07-03 14:17:57 -07005828 if ((mGroupFlags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN) {
5829 if (!dirty.intersect(0, 0, mRight - left, mBottom - top)) {
5830 dirty.setEmpty();
Romain Guy3a3133d2011-02-01 22:59:58 -08005831 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005832 }
Chet Haase05e91ed2012-07-03 14:17:57 -07005833
5834 location[CHILD_LEFT_INDEX] = left;
5835 location[CHILD_TOP_INDEX] = top;
Selim Cinek1cb8b082016-12-21 15:34:30 +00005836 } else {
Selim Cinek1cb8b082016-12-21 15:34:30 +00005837
Chet Haasea3db8662011-07-19 10:36:05 -07005838 if ((mGroupFlags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN) {
5839 dirty.set(0, 0, mRight - mLeft, mBottom - mTop);
5840 } else {
5841 // in case the dirty rect extends outside the bounds of this container
5842 dirty.union(0, 0, mRight - mLeft, mBottom - mTop);
5843 }
Chris Craik3f06c6d2017-01-09 18:19:48 +00005844 location[CHILD_LEFT_INDEX] = mLeft;
5845 location[CHILD_TOP_INDEX] = mTop;
Romain Guy3a3133d2011-02-01 22:59:58 -08005846
Chris Craik3f06c6d2017-01-09 18:19:48 +00005847 mPrivateFlags &= ~PFLAG_DRAWN;
Selim Cinek1cb8b082016-12-21 15:34:30 +00005848 }
Chris Craik3f06c6d2017-01-09 18:19:48 +00005849 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
5850 if (mLayerType != LAYER_TYPE_NONE) {
5851 mPrivateFlags |= PFLAG_INVALIDATED;
5852 }
5853
5854 return mParent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005855 }
5856
5857 return null;
5858 }
5859
5860 /**
5861 * Offset a rectangle that is in a descendant's coordinate
5862 * space into our coordinate space.
5863 * @param descendant A descendant of this view
5864 * @param rect A rectangle defined in descendant's coordinate space.
5865 */
5866 public final void offsetDescendantRectToMyCoords(View descendant, Rect rect) {
5867 offsetRectBetweenParentAndChild(descendant, rect, true, false);
5868 }
5869
5870 /**
5871 * Offset a rectangle that is in our coordinate space into an ancestor's
5872 * coordinate space.
5873 * @param descendant A descendant of this view
5874 * @param rect A rectangle defined in descendant's coordinate space.
5875 */
5876 public final void offsetRectIntoDescendantCoords(View descendant, Rect rect) {
5877 offsetRectBetweenParentAndChild(descendant, rect, false, false);
5878 }
5879
5880 /**
5881 * Helper method that offsets a rect either from parent to descendant or
5882 * descendant to parent.
5883 */
5884 void offsetRectBetweenParentAndChild(View descendant, Rect rect,
5885 boolean offsetFromChildToParent, boolean clipToBounds) {
5886
5887 // already in the same coord system :)
5888 if (descendant == this) {
5889 return;
5890 }
5891
5892 ViewParent theParent = descendant.mParent;
5893
5894 // search and offset up to the parent
5895 while ((theParent != null)
5896 && (theParent instanceof View)
5897 && (theParent != this)) {
5898
5899 if (offsetFromChildToParent) {
Hyunyoung Song4eb1a4e2016-03-09 22:51:02 +00005900 rect.offset(descendant.mLeft - descendant.mScrollX,
5901 descendant.mTop - descendant.mScrollY);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005902 if (clipToBounds) {
5903 View p = (View) theParent;
Doris Liu9607fbe2015-05-28 17:17:28 -07005904 boolean intersected = rect.intersect(0, 0, p.mRight - p.mLeft,
5905 p.mBottom - p.mTop);
5906 if (!intersected) {
5907 rect.setEmpty();
5908 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005909 }
5910 } else {
5911 if (clipToBounds) {
5912 View p = (View) theParent;
Doris Liu9607fbe2015-05-28 17:17:28 -07005913 boolean intersected = rect.intersect(0, 0, p.mRight - p.mLeft,
5914 p.mBottom - p.mTop);
5915 if (!intersected) {
5916 rect.setEmpty();
5917 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005918 }
Hyunyoung Song4eb1a4e2016-03-09 22:51:02 +00005919 rect.offset(descendant.mScrollX - descendant.mLeft,
5920 descendant.mScrollY - descendant.mTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005921 }
5922
5923 descendant = (View) theParent;
5924 theParent = descendant.mParent;
5925 }
5926
5927 // now that we are up to this view, need to offset one more time
5928 // to get into our coordinate space
5929 if (theParent == this) {
5930 if (offsetFromChildToParent) {
Hyunyoung Song4eb1a4e2016-03-09 22:51:02 +00005931 rect.offset(descendant.mLeft - descendant.mScrollX,
5932 descendant.mTop - descendant.mScrollY);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005933 } else {
Hyunyoung Song4eb1a4e2016-03-09 22:51:02 +00005934 rect.offset(descendant.mScrollX - descendant.mLeft,
5935 descendant.mScrollY - descendant.mTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005936 }
5937 } else {
5938 throw new IllegalArgumentException("parameter must be a descendant of this view");
5939 }
5940 }
5941
5942 /**
5943 * Offset the vertical location of all children of this view by the specified number of pixels.
5944 *
5945 * @param offset the number of pixels to offset
5946 *
5947 * @hide
5948 */
5949 public void offsetChildrenTopAndBottom(int offset) {
5950 final int count = mChildrenCount;
5951 final View[] children = mChildren;
Romain Guy5549cb52013-05-06 18:42:08 -07005952 boolean invalidate = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005953
5954 for (int i = 0; i < count; i++) {
5955 final View v = children[i];
5956 v.mTop += offset;
5957 v.mBottom += offset;
Chris Craik64a12e12014-03-28 18:12:12 -07005958 if (v.mRenderNode != null) {
Romain Guy5549cb52013-05-06 18:42:08 -07005959 invalidate = true;
Chris Craik64a12e12014-03-28 18:12:12 -07005960 v.mRenderNode.offsetTopAndBottom(offset);
Chet Haasea1cff502012-02-21 13:43:44 -08005961 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005962 }
Romain Guy5549cb52013-05-06 18:42:08 -07005963
5964 if (invalidate) {
5965 invalidateViewProperty(false, false);
5966 }
Guang Zhu84e25092014-05-01 21:12:55 -07005967 notifySubtreeAccessibilityStateChangedIfNeeded();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005968 }
5969
Alan Viverettebe463f22016-01-21 10:50:10 -05005970 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005971 public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) {
Abodunrinwa Toki4e7a1202016-05-03 18:23:12 +01005972 return getChildVisibleRect(child, r, offset, false);
5973 }
5974
5975 /**
Abodunrinwa Tokicb664062016-05-13 19:26:03 +01005976 * @param forceParentCheck true to guarantee that this call will propagate to all ancestors,
5977 * false otherwise
5978 *
Abodunrinwa Toki4e7a1202016-05-03 18:23:12 +01005979 * @hide
5980 */
5981 public boolean getChildVisibleRect(
5982 View child, Rect r, android.graphics.Point offset, boolean forceParentCheck) {
Adam Powellf93bb6d2011-12-12 15:21:57 -08005983 // It doesn't make a whole lot of sense to call this on a view that isn't attached,
5984 // but for some simple tests it can be useful. If we don't have attach info this
5985 // will allocate memory.
5986 final RectF rect = mAttachInfo != null ? mAttachInfo.mTmpTransformRect : new RectF();
Gilles Debunnecea45132011-11-24 02:19:27 +01005987 rect.set(r);
5988
5989 if (!child.hasIdentityMatrix()) {
George Mount002d43d2014-11-11 12:54:43 -08005990 child.getMatrix().mapRect(rect);
Gilles Debunnecea45132011-11-24 02:19:27 +01005991 }
5992
Alan Viveretteab2cf6d2014-11-26 14:34:36 -08005993 final int dx = child.mLeft - mScrollX;
5994 final int dy = child.mTop - mScrollY;
Gilles Debunnecea45132011-11-24 02:19:27 +01005995
5996 rect.offset(dx, dy);
5997
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005998 if (offset != null) {
Gilles Debunnecea45132011-11-24 02:19:27 +01005999 if (!child.hasIdentityMatrix()) {
Adam Powellf93bb6d2011-12-12 15:21:57 -08006000 float[] position = mAttachInfo != null ? mAttachInfo.mTmpTransformLocation
6001 : new float[2];
Gilles Debunnecea45132011-11-24 02:19:27 +01006002 position[0] = offset.x;
6003 position[1] = offset.y;
6004 child.getMatrix().mapPoints(position);
Alan Viverettec45b1d42015-11-16 15:38:59 -05006005 offset.x = Math.round(position[0]);
6006 offset.y = Math.round(position[1]);
Gilles Debunnecea45132011-11-24 02:19:27 +01006007 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006008 offset.x += dx;
6009 offset.y += dy;
6010 }
Gilles Debunnecea45132011-11-24 02:19:27 +01006011
Alan Viveretteab2cf6d2014-11-26 14:34:36 -08006012 final int width = mRight - mLeft;
6013 final int height = mBottom - mTop;
6014
George Mount002d43d2014-11-11 12:54:43 -08006015 boolean rectIsVisible = true;
Adam Powell35da41e2014-12-10 18:59:34 -08006016 if (mParent == null ||
6017 (mParent instanceof ViewGroup && ((ViewGroup) mParent).getClipChildren())) {
Alan Viveretteab2cf6d2014-11-26 14:34:36 -08006018 // Clip to bounds.
6019 rectIsVisible = rect.intersect(0, 0, width, height);
Gilles Debunnecea45132011-11-24 02:19:27 +01006020 }
6021
Abodunrinwa Toki4e7a1202016-05-03 18:23:12 +01006022 if ((forceParentCheck || rectIsVisible)
6023 && (mGroupFlags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK) {
Alan Viveretteab2cf6d2014-11-26 14:34:36 -08006024 // Clip to padding.
George Mount002d43d2014-11-11 12:54:43 -08006025 rectIsVisible = rect.intersect(mPaddingLeft, mPaddingTop,
Alan Viveretteab2cf6d2014-11-26 14:34:36 -08006026 width - mPaddingRight, height - mPaddingBottom);
George Mount002d43d2014-11-11 12:54:43 -08006027 }
6028
Abodunrinwa Toki4e7a1202016-05-03 18:23:12 +01006029 if ((forceParentCheck || rectIsVisible) && mClipBounds != null) {
Alan Viveretteab2cf6d2014-11-26 14:34:36 -08006030 // Clip to clipBounds.
George Mount002d43d2014-11-11 12:54:43 -08006031 rectIsVisible = rect.intersect(mClipBounds.left, mClipBounds.top, mClipBounds.right,
6032 mClipBounds.bottom);
6033 }
Alan Viverettec45b1d42015-11-16 15:38:59 -05006034 r.set((int) Math.floor(rect.left), (int) Math.floor(rect.top),
6035 (int) Math.ceil(rect.right), (int) Math.ceil(rect.bottom));
Abodunrinwa Toki4e7a1202016-05-03 18:23:12 +01006036
6037 if ((forceParentCheck || rectIsVisible) && mParent != null) {
Abodunrinwa Tokicb664062016-05-13 19:26:03 +01006038 if (mParent instanceof ViewGroup) {
6039 rectIsVisible = ((ViewGroup) mParent)
6040 .getChildVisibleRect(this, r, offset, forceParentCheck);
6041 } else {
6042 rectIsVisible = mParent.getChildVisibleRect(this, r, offset);
6043 }
George Mount002d43d2014-11-11 12:54:43 -08006044 }
6045 return rectIsVisible;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006046 }
6047
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006048 @Override
Chet Haase9c087442011-01-12 16:20:16 -08006049 public final void layout(int l, int t, int r, int b) {
Chet Haase430742f2013-04-12 11:18:36 -07006050 if (!mSuppressLayout && (mTransition == null || !mTransition.isChangingLayout())) {
Chet Haase7dd4a532012-04-16 13:35:09 -07006051 if (mTransition != null) {
6052 mTransition.layoutChange(this);
6053 }
Chet Haase9c087442011-01-12 16:20:16 -08006054 super.layout(l, t, r, b);
6055 } else {
6056 // record the fact that we noop'd it; request layout when transition finishes
Chet Haaseb9895022013-04-02 15:10:58 -07006057 mLayoutCalledWhileSuppressed = true;
Chet Haase9c087442011-01-12 16:20:16 -08006058 }
6059 }
6060
Chet Haase9c087442011-01-12 16:20:16 -08006061 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006062 protected abstract void onLayout(boolean changed,
6063 int l, int t, int r, int b);
6064
6065 /**
6066 * Indicates whether the view group has the ability to animate its children
6067 * after the first layout.
6068 *
6069 * @return true if the children can be animated, false otherwise
6070 */
6071 protected boolean canAnimate() {
6072 return mLayoutAnimationController != null;
6073 }
6074
6075 /**
6076 * Runs the layout animation. Calling this method triggers a relayout of
6077 * this view group.
6078 */
6079 public void startLayoutAnimation() {
6080 if (mLayoutAnimationController != null) {
6081 mGroupFlags |= FLAG_RUN_ANIMATION;
6082 requestLayout();
6083 }
6084 }
6085
6086 /**
6087 * Schedules the layout animation to be played after the next layout pass
6088 * of this view group. This can be used to restart the layout animation
6089 * when the content of the view group changes or when the activity is
6090 * paused and resumed.
6091 */
6092 public void scheduleLayoutAnimation() {
6093 mGroupFlags |= FLAG_RUN_ANIMATION;
6094 }
6095
6096 /**
6097 * Sets the layout animation controller used to animate the group's
6098 * children after the first layout.
6099 *
6100 * @param controller the animation controller
6101 */
6102 public void setLayoutAnimation(LayoutAnimationController controller) {
6103 mLayoutAnimationController = controller;
6104 if (mLayoutAnimationController != null) {
6105 mGroupFlags |= FLAG_RUN_ANIMATION;
6106 }
6107 }
6108
6109 /**
6110 * Returns the layout animation controller used to animate the group's
6111 * children.
6112 *
6113 * @return the current animation controller
6114 */
6115 public LayoutAnimationController getLayoutAnimation() {
6116 return mLayoutAnimationController;
6117 }
6118
6119 /**
6120 * Indicates whether the children's drawing cache is used during a layout
6121 * animation. By default, the drawing cache is enabled but this will prevent
6122 * nested layout animations from working. To nest animations, you must disable
6123 * the cache.
6124 *
6125 * @return true if the animation cache is enabled, false otherwise
6126 *
6127 * @see #setAnimationCacheEnabled(boolean)
6128 * @see View#setDrawingCacheEnabled(boolean)
Chris Craik5a6bbae2015-04-10 17:41:34 -07006129 *
Dianne Hackborn0e3de6c2015-07-29 15:20:21 -07006130 * @deprecated As of {@link android.os.Build.VERSION_CODES#M}, this property is ignored.
Chris Craik5a6bbae2015-04-10 17:41:34 -07006131 * Caching behavior of children may be controlled through {@link View#setLayerType(int, Paint)}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006132 */
Aurimas Liutikas514c5ef2016-05-24 15:22:55 -07006133 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006134 public boolean isAnimationCacheEnabled() {
6135 return (mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE;
6136 }
6137
6138 /**
6139 * Enables or disables the children's drawing cache during a layout animation.
6140 * By default, the drawing cache is enabled but this will prevent nested
6141 * layout animations from working. To nest animations, you must disable the
6142 * cache.
6143 *
6144 * @param enabled true to enable the animation cache, false otherwise
6145 *
6146 * @see #isAnimationCacheEnabled()
6147 * @see View#setDrawingCacheEnabled(boolean)
Chris Craik5a6bbae2015-04-10 17:41:34 -07006148 *
Dianne Hackborn0e3de6c2015-07-29 15:20:21 -07006149 * @deprecated As of {@link android.os.Build.VERSION_CODES#M}, this property is ignored.
Chris Craik5a6bbae2015-04-10 17:41:34 -07006150 * Caching behavior of children may be controlled through {@link View#setLayerType(int, Paint)}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006151 */
Aurimas Liutikas514c5ef2016-05-24 15:22:55 -07006152 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006153 public void setAnimationCacheEnabled(boolean enabled) {
6154 setBooleanFlag(FLAG_ANIMATION_CACHE, enabled);
6155 }
6156
6157 /**
6158 * Indicates whether this ViewGroup will always try to draw its children using their
6159 * drawing cache. By default this property is enabled.
6160 *
6161 * @return true if the animation cache is enabled, false otherwise
6162 *
6163 * @see #setAlwaysDrawnWithCacheEnabled(boolean)
6164 * @see #setChildrenDrawnWithCacheEnabled(boolean)
6165 * @see View#setDrawingCacheEnabled(boolean)
Chris Craik5a6bbae2015-04-10 17:41:34 -07006166 *
Dianne Hackborn0e3de6c2015-07-29 15:20:21 -07006167 * @deprecated As of {@link android.os.Build.VERSION_CODES#M}, this property is ignored.
Chris Craik5a6bbae2015-04-10 17:41:34 -07006168 * Child views may no longer have their caching behavior disabled by parents.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006169 */
Aurimas Liutikas514c5ef2016-05-24 15:22:55 -07006170 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006171 public boolean isAlwaysDrawnWithCacheEnabled() {
6172 return (mGroupFlags & FLAG_ALWAYS_DRAWN_WITH_CACHE) == FLAG_ALWAYS_DRAWN_WITH_CACHE;
6173 }
6174
6175 /**
6176 * Indicates whether this ViewGroup will always try to draw its children using their
6177 * drawing cache. This property can be set to true when the cache rendering is
6178 * slightly different from the children's normal rendering. Renderings can be different,
6179 * for instance, when the cache's quality is set to low.
6180 *
6181 * When this property is disabled, the ViewGroup will use the drawing cache of its
6182 * children only when asked to. It's usually the task of subclasses to tell ViewGroup
6183 * when to start using the drawing cache and when to stop using it.
6184 *
6185 * @param always true to always draw with the drawing cache, false otherwise
6186 *
6187 * @see #isAlwaysDrawnWithCacheEnabled()
6188 * @see #setChildrenDrawnWithCacheEnabled(boolean)
6189 * @see View#setDrawingCacheEnabled(boolean)
6190 * @see View#setDrawingCacheQuality(int)
Chris Craik5a6bbae2015-04-10 17:41:34 -07006191 *
Dianne Hackborn0e3de6c2015-07-29 15:20:21 -07006192 * @deprecated As of {@link android.os.Build.VERSION_CODES#M}, this property is ignored.
Chris Craik5a6bbae2015-04-10 17:41:34 -07006193 * Child views may no longer have their caching behavior disabled by parents.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006194 */
Aurimas Liutikas514c5ef2016-05-24 15:22:55 -07006195 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006196 public void setAlwaysDrawnWithCacheEnabled(boolean always) {
6197 setBooleanFlag(FLAG_ALWAYS_DRAWN_WITH_CACHE, always);
6198 }
6199
6200 /**
6201 * Indicates whether the ViewGroup is currently drawing its children using
6202 * their drawing cache.
6203 *
6204 * @return true if children should be drawn with their cache, false otherwise
6205 *
6206 * @see #setAlwaysDrawnWithCacheEnabled(boolean)
6207 * @see #setChildrenDrawnWithCacheEnabled(boolean)
Chris Craik5a6bbae2015-04-10 17:41:34 -07006208 *
Dianne Hackborn0e3de6c2015-07-29 15:20:21 -07006209 * @deprecated As of {@link android.os.Build.VERSION_CODES#M}, this property is ignored.
Chris Craik5a6bbae2015-04-10 17:41:34 -07006210 * Child views may no longer be forced to cache their rendering state by their parents.
6211 * Use {@link View#setLayerType(int, Paint)} on individual Views instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006212 */
Aurimas Liutikas514c5ef2016-05-24 15:22:55 -07006213 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006214 protected boolean isChildrenDrawnWithCacheEnabled() {
6215 return (mGroupFlags & FLAG_CHILDREN_DRAWN_WITH_CACHE) == FLAG_CHILDREN_DRAWN_WITH_CACHE;
6216 }
6217
6218 /**
6219 * Tells the ViewGroup to draw its children using their drawing cache. This property
6220 * is ignored when {@link #isAlwaysDrawnWithCacheEnabled()} is true. A child's drawing cache
6221 * will be used only if it has been enabled.
6222 *
6223 * Subclasses should call this method to start and stop using the drawing cache when
6224 * they perform performance sensitive operations, like scrolling or animating.
6225 *
6226 * @param enabled true if children should be drawn with their cache, false otherwise
6227 *
6228 * @see #setAlwaysDrawnWithCacheEnabled(boolean)
6229 * @see #isChildrenDrawnWithCacheEnabled()
Chris Craik5a6bbae2015-04-10 17:41:34 -07006230 *
Dianne Hackborn0e3de6c2015-07-29 15:20:21 -07006231 * @deprecated As of {@link android.os.Build.VERSION_CODES#M}, this property is ignored.
Chris Craik5a6bbae2015-04-10 17:41:34 -07006232 * Child views may no longer be forced to cache their rendering state by their parents.
6233 * Use {@link View#setLayerType(int, Paint)} on individual Views instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006234 */
Aurimas Liutikas514c5ef2016-05-24 15:22:55 -07006235 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006236 protected void setChildrenDrawnWithCacheEnabled(boolean enabled) {
6237 setBooleanFlag(FLAG_CHILDREN_DRAWN_WITH_CACHE, enabled);
6238 }
6239
Romain Guy293451e2009-11-04 13:59:48 -08006240 /**
6241 * Indicates whether the ViewGroup is drawing its children in the order defined by
6242 * {@link #getChildDrawingOrder(int, int)}.
6243 *
6244 * @return true if children drawing order is defined by {@link #getChildDrawingOrder(int, int)},
6245 * false otherwise
6246 *
6247 * @see #setChildrenDrawingOrderEnabled(boolean)
6248 * @see #getChildDrawingOrder(int, int)
6249 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07006250 @ViewDebug.ExportedProperty(category = "drawing")
Romain Guy293451e2009-11-04 13:59:48 -08006251 protected boolean isChildrenDrawingOrderEnabled() {
6252 return (mGroupFlags & FLAG_USE_CHILD_DRAWING_ORDER) == FLAG_USE_CHILD_DRAWING_ORDER;
6253 }
6254
6255 /**
6256 * Tells the ViewGroup whether to draw its children in the order defined by the method
6257 * {@link #getChildDrawingOrder(int, int)}.
Chris Craike83cbd42014-09-03 17:52:24 -07006258 * <p>
6259 * Note that {@link View#getZ() Z} reordering, done by {@link #dispatchDraw(Canvas)},
6260 * will override custom child ordering done via this method.
Romain Guy293451e2009-11-04 13:59:48 -08006261 *
6262 * @param enabled true if the order of the children when drawing is determined by
6263 * {@link #getChildDrawingOrder(int, int)}, false otherwise
6264 *
6265 * @see #isChildrenDrawingOrderEnabled()
6266 * @see #getChildDrawingOrder(int, int)
6267 */
6268 protected void setChildrenDrawingOrderEnabled(boolean enabled) {
6269 setBooleanFlag(FLAG_USE_CHILD_DRAWING_ORDER, enabled);
6270 }
6271
Svetoslav6254f482013-06-04 17:22:14 -07006272 private boolean hasBooleanFlag(int flag) {
Philip Milnef091b662013-02-27 11:15:21 -08006273 return (mGroupFlags & flag) == flag;
6274 }
6275
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006276 private void setBooleanFlag(int flag, boolean value) {
6277 if (value) {
6278 mGroupFlags |= flag;
6279 } else {
6280 mGroupFlags &= ~flag;
6281 }
6282 }
6283
6284 /**
6285 * Returns an integer indicating what types of drawing caches are kept in memory.
6286 *
6287 * @see #setPersistentDrawingCache(int)
6288 * @see #setAnimationCacheEnabled(boolean)
6289 *
6290 * @return one or a combination of {@link #PERSISTENT_NO_CACHE},
6291 * {@link #PERSISTENT_ANIMATION_CACHE}, {@link #PERSISTENT_SCROLLING_CACHE}
6292 * and {@link #PERSISTENT_ALL_CACHES}
6293 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07006294 @ViewDebug.ExportedProperty(category = "drawing", mapping = {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006295 @ViewDebug.IntToString(from = PERSISTENT_NO_CACHE, to = "NONE"),
Romain Guy203688c2010-05-12 15:41:32 -07006296 @ViewDebug.IntToString(from = PERSISTENT_ANIMATION_CACHE, to = "ANIMATION"),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006297 @ViewDebug.IntToString(from = PERSISTENT_SCROLLING_CACHE, to = "SCROLLING"),
6298 @ViewDebug.IntToString(from = PERSISTENT_ALL_CACHES, to = "ALL")
6299 })
6300 public int getPersistentDrawingCache() {
6301 return mPersistentDrawingCache;
6302 }
6303
6304 /**
6305 * Indicates what types of drawing caches should be kept in memory after
6306 * they have been created.
6307 *
6308 * @see #getPersistentDrawingCache()
6309 * @see #setAnimationCacheEnabled(boolean)
6310 *
6311 * @param drawingCacheToKeep one or a combination of {@link #PERSISTENT_NO_CACHE},
6312 * {@link #PERSISTENT_ANIMATION_CACHE}, {@link #PERSISTENT_SCROLLING_CACHE}
6313 * and {@link #PERSISTENT_ALL_CACHES}
6314 */
6315 public void setPersistentDrawingCache(int drawingCacheToKeep) {
6316 mPersistentDrawingCache = drawingCacheToKeep & PERSISTENT_ALL_CACHES;
6317 }
6318
Philip Milnef091b662013-02-27 11:15:21 -08006319 private void setLayoutMode(int layoutMode, boolean explicitly) {
6320 mLayoutMode = layoutMode;
6321 setBooleanFlag(FLAG_LAYOUT_MODE_WAS_EXPLICITLY_SET, explicitly);
6322 }
6323
6324 /**
6325 * Recursively traverse the view hierarchy, resetting the layoutMode of any
6326 * descendants that had inherited a different layoutMode from a previous parent.
6327 * Recursion terminates when a descendant's mode is:
6328 * <ul>
6329 * <li>Undefined</li>
6330 * <li>The same as the root node's</li>
6331 * <li>A mode that had been explicitly set</li>
6332 * <ul/>
6333 * The first two clauses are optimizations.
6334 * @param layoutModeOfRoot
6335 */
6336 @Override
6337 void invalidateInheritedLayoutMode(int layoutModeOfRoot) {
6338 if (mLayoutMode == LAYOUT_MODE_UNDEFINED ||
6339 mLayoutMode == layoutModeOfRoot ||
Svetoslav6254f482013-06-04 17:22:14 -07006340 hasBooleanFlag(FLAG_LAYOUT_MODE_WAS_EXPLICITLY_SET)) {
Philip Milnef091b662013-02-27 11:15:21 -08006341 return;
6342 }
6343 setLayoutMode(LAYOUT_MODE_UNDEFINED, false);
6344
6345 // apply recursively
6346 for (int i = 0, N = getChildCount(); i < N; i++) {
6347 getChildAt(i).invalidateInheritedLayoutMode(layoutModeOfRoot);
6348 }
6349 }
6350
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006351 /**
Philip Milnecfb631b2012-10-26 10:51:46 -07006352 * Returns the basis of alignment during layout operations on this ViewGroup:
Philip Milne7b757812012-09-19 18:13:44 -07006353 * either {@link #LAYOUT_MODE_CLIP_BOUNDS} or {@link #LAYOUT_MODE_OPTICAL_BOUNDS}.
Philip Milnecfb631b2012-10-26 10:51:46 -07006354 * <p>
6355 * If no layoutMode was explicitly set, either programmatically or in an XML resource,
6356 * the method returns the layoutMode of the view's parent ViewGroup if such a parent exists,
6357 * otherwise the method returns a default value of {@link #LAYOUT_MODE_CLIP_BOUNDS}.
Philip Milne1557fd72012-04-04 23:41:34 -07006358 *
Philip Milnefcc6a0f2012-04-16 16:12:19 -07006359 * @return the layout mode to use during layout operations
Philip Milne1557fd72012-04-04 23:41:34 -07006360 *
6361 * @see #setLayoutMode(int)
6362 */
6363 public int getLayoutMode() {
Philip Milnecfb631b2012-10-26 10:51:46 -07006364 if (mLayoutMode == LAYOUT_MODE_UNDEFINED) {
Philip Milnef091b662013-02-27 11:15:21 -08006365 int inheritedLayoutMode = (mParent instanceof ViewGroup) ?
6366 ((ViewGroup) mParent).getLayoutMode() : LAYOUT_MODE_DEFAULT;
6367 setLayoutMode(inheritedLayoutMode, false);
Philip Milnecfb631b2012-10-26 10:51:46 -07006368 }
Philip Milne1557fd72012-04-04 23:41:34 -07006369 return mLayoutMode;
6370 }
6371
6372 /**
Philip Milnecfb631b2012-10-26 10:51:46 -07006373 * Sets the basis of alignment during the layout of this ViewGroup.
Philip Milne7b757812012-09-19 18:13:44 -07006374 * Valid values are either {@link #LAYOUT_MODE_CLIP_BOUNDS} or
6375 * {@link #LAYOUT_MODE_OPTICAL_BOUNDS}.
Philip Milne1557fd72012-04-04 23:41:34 -07006376 *
Philip Milnefcc6a0f2012-04-16 16:12:19 -07006377 * @param layoutMode the layout mode to use during layout operations
Philip Milne1557fd72012-04-04 23:41:34 -07006378 *
6379 * @see #getLayoutMode()
Scott Main27a85082013-06-10 10:39:48 -07006380 * @attr ref android.R.styleable#ViewGroup_layoutMode
Philip Milne1557fd72012-04-04 23:41:34 -07006381 */
6382 public void setLayoutMode(int layoutMode) {
6383 if (mLayoutMode != layoutMode) {
Philip Milnef091b662013-02-27 11:15:21 -08006384 invalidateInheritedLayoutMode(layoutMode);
6385 setLayoutMode(layoutMode, layoutMode != LAYOUT_MODE_UNDEFINED);
Philip Milne1557fd72012-04-04 23:41:34 -07006386 requestLayout();
6387 }
6388 }
6389
6390 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006391 * Returns a new set of layout parameters based on the supplied attributes set.
6392 *
6393 * @param attrs the attributes to build the layout parameters from
6394 *
6395 * @return an instance of {@link android.view.ViewGroup.LayoutParams} or one
6396 * of its descendants
6397 */
6398 public LayoutParams generateLayoutParams(AttributeSet attrs) {
6399 return new LayoutParams(getContext(), attrs);
6400 }
6401
6402 /**
6403 * Returns a safe set of layout parameters based on the supplied layout params.
6404 * When a ViewGroup is passed a View whose layout params do not pass the test of
6405 * {@link #checkLayoutParams(android.view.ViewGroup.LayoutParams)}, this method
6406 * is invoked. This method should return a new set of layout params suitable for
6407 * this ViewGroup, possibly by copying the appropriate attributes from the
6408 * specified set of layout params.
6409 *
6410 * @param p The layout parameters to convert into a suitable set of layout parameters
6411 * for this ViewGroup.
6412 *
6413 * @return an instance of {@link android.view.ViewGroup.LayoutParams} or one
6414 * of its descendants
6415 */
6416 protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
Chet Haase4610eef2015-12-03 07:38:11 -08006417 return p;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006418 }
6419
6420 /**
6421 * Returns a set of default layout parameters. These parameters are requested
6422 * when the View passed to {@link #addView(View)} has no layout parameters
6423 * already set. If null is returned, an exception is thrown from addView.
6424 *
6425 * @return a set of default layout parameters or null
6426 */
6427 protected LayoutParams generateDefaultLayoutParams() {
6428 return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
6429 }
6430
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006431 @Override
6432 protected void debug(int depth) {
6433 super.debug(depth);
6434 String output;
6435
6436 if (mFocused != null) {
6437 output = debugIndent(depth);
6438 output += "mFocused";
6439 Log.d(VIEW_LOG_TAG, output);
Vadim Tryshev01d8c492016-12-15 11:33:15 -08006440 mFocused.debug(depth + 1);
6441 }
Vadim Tryshev5ca73982017-01-04 17:24:43 -08006442 if (mDefaultFocus != null) {
Vadim Tryshev01d8c492016-12-15 11:33:15 -08006443 output = debugIndent(depth);
Vadim Tryshev5ca73982017-01-04 17:24:43 -08006444 output += "mDefaultFocus";
Vadim Tryshev01d8c492016-12-15 11:33:15 -08006445 Log.d(VIEW_LOG_TAG, output);
Vadim Tryshev5ca73982017-01-04 17:24:43 -08006446 mDefaultFocus.debug(depth + 1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006447 }
Evan Rosky53fcf112017-01-26 14:37:55 -08006448 if (mFocusedInCluster != null) {
6449 output = debugIndent(depth);
6450 output += "mFocusedInCluster";
6451 Log.d(VIEW_LOG_TAG, output);
6452 mFocusedInCluster.debug(depth + 1);
6453 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006454 if (mChildrenCount != 0) {
6455 output = debugIndent(depth);
6456 output += "{";
6457 Log.d(VIEW_LOG_TAG, output);
6458 }
6459 int count = mChildrenCount;
6460 for (int i = 0; i < count; i++) {
6461 View child = mChildren[i];
6462 child.debug(depth + 1);
6463 }
6464
6465 if (mChildrenCount != 0) {
6466 output = debugIndent(depth);
6467 output += "}";
6468 Log.d(VIEW_LOG_TAG, output);
6469 }
6470 }
6471
6472 /**
6473 * Returns the position in the group of the specified child view.
6474 *
6475 * @param child the view for which to get the position
6476 * @return a positive integer representing the position of the view in the
6477 * group, or -1 if the view does not exist in the group
6478 */
6479 public int indexOfChild(View child) {
6480 final int count = mChildrenCount;
6481 final View[] children = mChildren;
6482 for (int i = 0; i < count; i++) {
6483 if (children[i] == child) {
6484 return i;
6485 }
6486 }
6487 return -1;
6488 }
6489
6490 /**
6491 * Returns the number of children in the group.
6492 *
6493 * @return a positive integer representing the number of children in
6494 * the group
6495 */
6496 public int getChildCount() {
6497 return mChildrenCount;
6498 }
6499
6500 /**
6501 * Returns the view at the specified position in the group.
6502 *
6503 * @param index the position at which to get the view from
6504 * @return the view at the specified position or null if the position
6505 * does not exist within the group
6506 */
6507 public View getChildAt(int index) {
Adam Powell3ba8f5d62011-03-07 15:36:33 -08006508 if (index < 0 || index >= mChildrenCount) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006509 return null;
6510 }
Adam Powell3ba8f5d62011-03-07 15:36:33 -08006511 return mChildren[index];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006512 }
6513
6514 /**
6515 * Ask all of the children of this view to measure themselves, taking into
6516 * account both the MeasureSpec requirements for this view and its padding.
6517 * We skip children that are in the GONE state The heavy lifting is done in
6518 * getChildMeasureSpec.
6519 *
6520 * @param widthMeasureSpec The width requirements for this view
6521 * @param heightMeasureSpec The height requirements for this view
6522 */
6523 protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec) {
6524 final int size = mChildrenCount;
6525 final View[] children = mChildren;
6526 for (int i = 0; i < size; ++i) {
6527 final View child = children[i];
6528 if ((child.mViewFlags & VISIBILITY_MASK) != GONE) {
6529 measureChild(child, widthMeasureSpec, heightMeasureSpec);
6530 }
6531 }
6532 }
6533
6534 /**
6535 * Ask one of the children of this view to measure itself, taking into
6536 * account both the MeasureSpec requirements for this view and its padding.
6537 * The heavy lifting is done in getChildMeasureSpec.
6538 *
6539 * @param child The child to measure
6540 * @param parentWidthMeasureSpec The width requirements for this view
6541 * @param parentHeightMeasureSpec The height requirements for this view
6542 */
6543 protected void measureChild(View child, int parentWidthMeasureSpec,
6544 int parentHeightMeasureSpec) {
6545 final LayoutParams lp = child.getLayoutParams();
6546
6547 final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
6548 mPaddingLeft + mPaddingRight, lp.width);
6549 final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
6550 mPaddingTop + mPaddingBottom, lp.height);
6551
6552 child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
6553 }
6554
6555 /**
6556 * Ask one of the children of this view to measure itself, taking into
6557 * account both the MeasureSpec requirements for this view and its padding
6558 * and margins. The child must have MarginLayoutParams The heavy lifting is
6559 * done in getChildMeasureSpec.
6560 *
6561 * @param child The child to measure
6562 * @param parentWidthMeasureSpec The width requirements for this view
6563 * @param widthUsed Extra space that has been used up by the parent
6564 * horizontally (possibly by other children of the parent)
6565 * @param parentHeightMeasureSpec The height requirements for this view
6566 * @param heightUsed Extra space that has been used up by the parent
6567 * vertically (possibly by other children of the parent)
6568 */
6569 protected void measureChildWithMargins(View child,
6570 int parentWidthMeasureSpec, int widthUsed,
6571 int parentHeightMeasureSpec, int heightUsed) {
6572 final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
6573
6574 final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
6575 mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin
6576 + widthUsed, lp.width);
6577 final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
6578 mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin
6579 + heightUsed, lp.height);
6580
6581 child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
6582 }
6583
6584 /**
6585 * Does the hard part of measureChildren: figuring out the MeasureSpec to
6586 * pass to a particular child. This method figures out the right MeasureSpec
6587 * for one dimension (height or width) of one child view.
6588 *
6589 * The goal is to combine information from our MeasureSpec with the
6590 * LayoutParams of the child to get the best possible results. For example,
6591 * if the this view knows its size (because its MeasureSpec has a mode of
6592 * EXACTLY), and the child has indicated in its LayoutParams that it wants
6593 * to be the same size as the parent, the parent should ask the child to
6594 * layout given an exact size.
6595 *
6596 * @param spec The requirements for this view
6597 * @param padding The padding of this view for the current dimension and
6598 * margins, if applicable
6599 * @param childDimension How big the child wants to be in the current
6600 * dimension
6601 * @return a MeasureSpec integer for the child
6602 */
6603 public static int getChildMeasureSpec(int spec, int padding, int childDimension) {
6604 int specMode = MeasureSpec.getMode(spec);
6605 int specSize = MeasureSpec.getSize(spec);
6606
6607 int size = Math.max(0, specSize - padding);
6608
6609 int resultSize = 0;
6610 int resultMode = 0;
6611
6612 switch (specMode) {
6613 // Parent has imposed an exact size on us
6614 case MeasureSpec.EXACTLY:
6615 if (childDimension >= 0) {
6616 resultSize = childDimension;
6617 resultMode = MeasureSpec.EXACTLY;
Romain Guy980a9382010-01-08 15:06:28 -08006618 } else if (childDimension == LayoutParams.MATCH_PARENT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006619 // Child wants to be our size. So be it.
6620 resultSize = size;
6621 resultMode = MeasureSpec.EXACTLY;
6622 } else if (childDimension == LayoutParams.WRAP_CONTENT) {
6623 // Child wants to determine its own size. It can't be
6624 // bigger than us.
6625 resultSize = size;
6626 resultMode = MeasureSpec.AT_MOST;
6627 }
6628 break;
6629
6630 // Parent has imposed a maximum size on us
6631 case MeasureSpec.AT_MOST:
6632 if (childDimension >= 0) {
6633 // Child wants a specific size... so be it
6634 resultSize = childDimension;
6635 resultMode = MeasureSpec.EXACTLY;
Romain Guy980a9382010-01-08 15:06:28 -08006636 } else if (childDimension == LayoutParams.MATCH_PARENT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006637 // Child wants to be our size, but our size is not fixed.
6638 // Constrain child to not be bigger than us.
6639 resultSize = size;
6640 resultMode = MeasureSpec.AT_MOST;
6641 } else if (childDimension == LayoutParams.WRAP_CONTENT) {
6642 // Child wants to determine its own size. It can't be
6643 // bigger than us.
6644 resultSize = size;
6645 resultMode = MeasureSpec.AT_MOST;
6646 }
6647 break;
6648
6649 // Parent asked to see how big we want to be
6650 case MeasureSpec.UNSPECIFIED:
6651 if (childDimension >= 0) {
6652 // Child wants a specific size... let him have it
6653 resultSize = childDimension;
6654 resultMode = MeasureSpec.EXACTLY;
Romain Guy980a9382010-01-08 15:06:28 -08006655 } else if (childDimension == LayoutParams.MATCH_PARENT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006656 // Child wants to be our size... find out how big it should
6657 // be
Adam Powelld5dbf4b2015-06-11 13:19:24 -07006658 resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006659 resultMode = MeasureSpec.UNSPECIFIED;
6660 } else if (childDimension == LayoutParams.WRAP_CONTENT) {
6661 // Child wants to determine its own size.... find out how
6662 // big it should be
Adam Powelld5dbf4b2015-06-11 13:19:24 -07006663 resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006664 resultMode = MeasureSpec.UNSPECIFIED;
6665 }
6666 break;
6667 }
Tor Norbye67568642015-03-31 07:47:23 -07006668 //noinspection ResourceType
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006669 return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
6670 }
6671
6672
6673 /**
6674 * Removes any pending animations for views that have been removed. Call
6675 * this if you don't want animations for exiting views to stack up.
6676 */
6677 public void clearDisappearingChildren() {
John Reckca7a9da2014-03-05 16:29:07 -08006678 final ArrayList<View> disappearingChildren = mDisappearingChildren;
6679 if (disappearingChildren != null) {
6680 final int count = disappearingChildren.size();
6681 for (int i = 0; i < count; i++) {
6682 final View view = disappearingChildren.get(i);
6683 if (view.mAttachInfo != null) {
6684 view.dispatchDetachedFromWindow();
6685 }
6686 view.clearAnimation();
6687 }
6688 disappearingChildren.clear();
Chet Haaseb85967b2012-03-26 14:37:51 -07006689 invalidate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006690 }
6691 }
6692
6693 /**
6694 * Add a view which is removed from mChildren but still needs animation
6695 *
6696 * @param v View to add
6697 */
6698 private void addDisappearingView(View v) {
6699 ArrayList<View> disappearingChildren = mDisappearingChildren;
6700
6701 if (disappearingChildren == null) {
6702 disappearingChildren = mDisappearingChildren = new ArrayList<View>();
6703 }
6704
6705 disappearingChildren.add(v);
6706 }
6707
6708 /**
6709 * Cleanup a view when its animation is done. This may mean removing it from
6710 * the list of disappearing views.
6711 *
6712 * @param view The view whose animation has finished
6713 * @param animation The animation, cannot be null
6714 */
Chet Haase64a48c12012-02-13 16:33:29 -08006715 void finishAnimatingView(final View view, Animation animation) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006716 final ArrayList<View> disappearingChildren = mDisappearingChildren;
6717 if (disappearingChildren != null) {
6718 if (disappearingChildren.contains(view)) {
6719 disappearingChildren.remove(view);
6720
6721 if (view.mAttachInfo != null) {
6722 view.dispatchDetachedFromWindow();
6723 }
6724
6725 view.clearAnimation();
6726 mGroupFlags |= FLAG_INVALIDATE_REQUIRED;
6727 }
6728 }
6729
6730 if (animation != null && !animation.getFillAfter()) {
6731 view.clearAnimation();
6732 }
6733
Dianne Hackborn4702a852012-08-17 15:18:29 -07006734 if ((view.mPrivateFlags & PFLAG_ANIMATION_STARTED) == PFLAG_ANIMATION_STARTED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006735 view.onAnimationEnd();
6736 // Should be performed by onAnimationEnd() but this avoid an infinite loop,
6737 // so we'd rather be safe than sorry
Dianne Hackborn4702a852012-08-17 15:18:29 -07006738 view.mPrivateFlags &= ~PFLAG_ANIMATION_STARTED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006739 // Draw one more frame after the animation is done
6740 mGroupFlags |= FLAG_INVALIDATE_REQUIRED;
6741 }
6742 }
6743
Chet Haaseb20db3e2010-09-10 13:07:30 -07006744 /**
Chet Haaseaceafe62011-08-26 15:44:33 -07006745 * Utility function called by View during invalidation to determine whether a view that
6746 * is invisible or gone should still be invalidated because it is being transitioned (and
6747 * therefore still needs to be drawn).
6748 */
6749 boolean isViewTransitioning(View view) {
6750 return (mTransitioningViews != null && mTransitioningViews.contains(view));
6751 }
6752
6753 /**
Chet Haaseb20db3e2010-09-10 13:07:30 -07006754 * This method tells the ViewGroup that the given View object, which should have this
6755 * ViewGroup as its parent,
6756 * should be kept around (re-displayed when the ViewGroup draws its children) even if it
6757 * is removed from its parent. This allows animations, such as those used by
6758 * {@link android.app.Fragment} and {@link android.animation.LayoutTransition} to animate
6759 * the removal of views. A call to this method should always be accompanied by a later call
6760 * to {@link #endViewTransition(View)}, such as after an animation on the View has finished,
6761 * so that the View finally gets removed.
6762 *
6763 * @param view The View object to be kept visible even if it gets removed from its parent.
6764 */
6765 public void startViewTransition(View view) {
6766 if (view.mParent == this) {
6767 if (mTransitioningViews == null) {
6768 mTransitioningViews = new ArrayList<View>();
6769 }
6770 mTransitioningViews.add(view);
6771 }
6772 }
6773
6774 /**
6775 * This method should always be called following an earlier call to
6776 * {@link #startViewTransition(View)}. The given View is finally removed from its parent
6777 * and will no longer be displayed. Note that this method does not perform the functionality
6778 * of removing a view from its parent; it just discontinues the display of a View that
6779 * has previously been removed.
6780 *
6781 * @return view The View object that has been removed but is being kept around in the visible
6782 * hierarchy by an earlier call to {@link #startViewTransition(View)}.
6783 */
6784 public void endViewTransition(View view) {
6785 if (mTransitioningViews != null) {
6786 mTransitioningViews.remove(view);
6787 final ArrayList<View> disappearingChildren = mDisappearingChildren;
6788 if (disappearingChildren != null && disappearingChildren.contains(view)) {
6789 disappearingChildren.remove(view);
Chet Haase5e25c2c2010-09-16 11:15:56 -07006790 if (mVisibilityChangingChildren != null &&
6791 mVisibilityChangingChildren.contains(view)) {
6792 mVisibilityChangingChildren.remove(view);
6793 } else {
6794 if (view.mAttachInfo != null) {
6795 view.dispatchDetachedFromWindow();
6796 }
6797 if (view.mParent != null) {
6798 view.mParent = null;
6799 }
Chet Haaseb20db3e2010-09-10 13:07:30 -07006800 }
Chet Haaseb85967b2012-03-26 14:37:51 -07006801 invalidate();
Chet Haaseb20db3e2010-09-10 13:07:30 -07006802 }
6803 }
6804 }
6805
Chet Haase21cd1382010-09-01 17:42:29 -07006806 private LayoutTransition.TransitionListener mLayoutTransitionListener =
6807 new LayoutTransition.TransitionListener() {
6808 @Override
6809 public void startTransition(LayoutTransition transition, ViewGroup container,
6810 View view, int transitionType) {
6811 // We only care about disappearing items, since we need special logic to keep
6812 // those items visible after they've been 'removed'
6813 if (transitionType == LayoutTransition.DISAPPEARING) {
Chet Haaseb20db3e2010-09-10 13:07:30 -07006814 startViewTransition(view);
Chet Haase21cd1382010-09-01 17:42:29 -07006815 }
6816 }
6817
6818 @Override
6819 public void endTransition(LayoutTransition transition, ViewGroup container,
6820 View view, int transitionType) {
Chet Haaseb9895022013-04-02 15:10:58 -07006821 if (mLayoutCalledWhileSuppressed && !transition.isChangingLayout()) {
Chet Haase9c087442011-01-12 16:20:16 -08006822 requestLayout();
Chet Haaseb9895022013-04-02 15:10:58 -07006823 mLayoutCalledWhileSuppressed = false;
Chet Haase9c087442011-01-12 16:20:16 -08006824 }
Chet Haase21cd1382010-09-01 17:42:29 -07006825 if (transitionType == LayoutTransition.DISAPPEARING && mTransitioningViews != null) {
Chet Haaseb20db3e2010-09-10 13:07:30 -07006826 endViewTransition(view);
Chet Haase21cd1382010-09-01 17:42:29 -07006827 }
6828 }
6829 };
6830
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006831 /**
Chet Haaseb9895022013-04-02 15:10:58 -07006832 * Tells this ViewGroup to suppress all layout() calls until layout
6833 * suppression is disabled with a later call to suppressLayout(false).
6834 * When layout suppression is disabled, a requestLayout() call is sent
6835 * if layout() was attempted while layout was being suppressed.
6836 *
6837 * @hide
6838 */
6839 public void suppressLayout(boolean suppress) {
6840 mSuppressLayout = suppress;
6841 if (!suppress) {
6842 if (mLayoutCalledWhileSuppressed) {
6843 requestLayout();
6844 mLayoutCalledWhileSuppressed = false;
6845 }
6846 }
6847 }
6848
6849 /**
Chet Haase199acdf2013-07-24 18:40:55 -07006850 * Returns whether layout calls on this container are currently being
6851 * suppressed, due to an earlier call to {@link #suppressLayout(boolean)}.
6852 *
6853 * @return true if layout calls are currently suppressed, false otherwise.
6854 *
6855 * @hide
6856 */
6857 public boolean isLayoutSuppressed() {
6858 return mSuppressLayout;
6859 }
6860
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006861 @Override
6862 public boolean gatherTransparentRegion(Region region) {
6863 // If no transparent regions requested, we are always opaque.
Dianne Hackborn4702a852012-08-17 15:18:29 -07006864 final boolean meOpaque = (mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) == 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006865 if (meOpaque && region == null) {
6866 // The caller doesn't care about the region, so stop now.
6867 return true;
6868 }
6869 super.gatherTransparentRegion(region);
Teng-Hui Zhuf8da30d2016-08-15 10:28:20 -07006870 // Instead of naively traversing the view tree, we have to traverse according to the Z
6871 // order here. We need to go with the same order as dispatchDraw().
6872 // One example is that after surfaceView punch a hole, we will still allow other views drawn
6873 // on top of that hole. In this case, those other views should be able to cut the
6874 // transparent region into smaller area.
6875 final int childrenCount = mChildrenCount;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006876 boolean noneOfTheChildrenAreTransparent = true;
Teng-Hui Zhuf8da30d2016-08-15 10:28:20 -07006877 if (childrenCount > 0) {
6878 final ArrayList<View> preorderedList = buildOrderedChildList();
6879 final boolean customOrder = preorderedList == null
6880 && isChildrenDrawingOrderEnabled();
6881 final View[] children = mChildren;
6882 for (int i = 0; i < childrenCount; i++) {
6883 final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
6884 final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);
6885 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
6886 if (!child.gatherTransparentRegion(region)) {
6887 noneOfTheChildrenAreTransparent = false;
6888 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006889 }
6890 }
Teng-Hui Zhuf8da30d2016-08-15 10:28:20 -07006891 if (preorderedList != null) preorderedList.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006892 }
6893 return meOpaque || noneOfTheChildrenAreTransparent;
6894 }
6895
Alan Viverettebe463f22016-01-21 10:50:10 -05006896 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006897 public void requestTransparentRegion(View child) {
6898 if (child != null) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07006899 child.mPrivateFlags |= View.PFLAG_REQUEST_TRANSPARENT_REGIONS;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006900 if (mParent != null) {
6901 mParent.requestTransparentRegion(this);
6902 }
6903 }
6904 }
Romain Guy8506ab42009-06-11 17:35:47 -07006905
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006906 @Override
Adam Powell46e38fd2014-02-03 10:16:49 -08006907 public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) {
6908 insets = super.dispatchApplyWindowInsets(insets);
Adam Powell0d9fdba2014-06-11 15:33:08 -07006909 if (!insets.isConsumed()) {
Adam Powell46e38fd2014-02-03 10:16:49 -08006910 final int count = getChildCount();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006911 for (int i = 0; i < count; i++) {
Adam Powell46e38fd2014-02-03 10:16:49 -08006912 insets = getChildAt(i).dispatchApplyWindowInsets(insets);
Adam Powell0d9fdba2014-06-11 15:33:08 -07006913 if (insets.isConsumed()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006914 break;
6915 }
6916 }
6917 }
Adam Powell46e38fd2014-02-03 10:16:49 -08006918 return insets;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006919 }
6920
6921 /**
6922 * Returns the animation listener to which layout animation events are
6923 * sent.
6924 *
6925 * @return an {@link android.view.animation.Animation.AnimationListener}
6926 */
6927 public Animation.AnimationListener getLayoutAnimationListener() {
6928 return mAnimationListener;
6929 }
6930
6931 @Override
6932 protected void drawableStateChanged() {
6933 super.drawableStateChanged();
6934
6935 if ((mGroupFlags & FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE) != 0) {
6936 if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0) {
6937 throw new IllegalStateException("addStateFromChildren cannot be enabled if a"
6938 + " child has duplicateParentState set to true");
6939 }
6940
6941 final View[] children = mChildren;
6942 final int count = mChildrenCount;
6943
6944 for (int i = 0; i < count; i++) {
6945 final View child = children[i];
6946 if ((child.mViewFlags & DUPLICATE_PARENT_STATE) != 0) {
6947 child.refreshDrawableState();
6948 }
6949 }
6950 }
6951 }
6952
6953 @Override
Dianne Hackborne2136772010-11-04 15:08:59 -07006954 public void jumpDrawablesToCurrentState() {
6955 super.jumpDrawablesToCurrentState();
6956 final View[] children = mChildren;
6957 final int count = mChildrenCount;
6958 for (int i = 0; i < count; i++) {
6959 children[i].jumpDrawablesToCurrentState();
6960 }
6961 }
6962
6963 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006964 protected int[] onCreateDrawableState(int extraSpace) {
6965 if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) == 0) {
6966 return super.onCreateDrawableState(extraSpace);
6967 }
6968
6969 int need = 0;
6970 int n = getChildCount();
6971 for (int i = 0; i < n; i++) {
6972 int[] childState = getChildAt(i).getDrawableState();
6973
6974 if (childState != null) {
6975 need += childState.length;
6976 }
6977 }
6978
6979 int[] state = super.onCreateDrawableState(extraSpace + need);
6980
6981 for (int i = 0; i < n; i++) {
6982 int[] childState = getChildAt(i).getDrawableState();
6983
6984 if (childState != null) {
6985 state = mergeDrawableStates(state, childState);
6986 }
6987 }
6988
6989 return state;
6990 }
6991
6992 /**
6993 * Sets whether this ViewGroup's drawable states also include
6994 * its children's drawable states. This is used, for example, to
6995 * make a group appear to be focused when its child EditText or button
6996 * is focused.
6997 */
6998 public void setAddStatesFromChildren(boolean addsStates) {
6999 if (addsStates) {
7000 mGroupFlags |= FLAG_ADD_STATES_FROM_CHILDREN;
7001 } else {
7002 mGroupFlags &= ~FLAG_ADD_STATES_FROM_CHILDREN;
7003 }
7004
7005 refreshDrawableState();
7006 }
7007
7008 /**
7009 * Returns whether this ViewGroup's drawable states also include
7010 * its children's drawable states. This is used, for example, to
7011 * make a group appear to be focused when its child EditText or button
7012 * is focused.
7013 */
7014 public boolean addStatesFromChildren() {
7015 return (mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0;
7016 }
7017
7018 /**
Jeff Smitha45746e2012-07-19 14:19:24 -05007019 * If {@link #addStatesFromChildren} is true, refreshes this group's
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007020 * drawable state (to include the states from its children).
7021 */
Alan Viverettebe463f22016-01-21 10:50:10 -05007022 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007023 public void childDrawableStateChanged(View child) {
7024 if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0) {
7025 refreshDrawableState();
7026 }
7027 }
7028
7029 /**
7030 * Specifies the animation listener to which layout animation events must
7031 * be sent. Only
7032 * {@link android.view.animation.Animation.AnimationListener#onAnimationStart(Animation)}
7033 * and
7034 * {@link android.view.animation.Animation.AnimationListener#onAnimationEnd(Animation)}
7035 * are invoked.
7036 *
7037 * @param animationListener the layout animation listener
7038 */
7039 public void setLayoutAnimationListener(Animation.AnimationListener animationListener) {
7040 mAnimationListener = animationListener;
7041 }
7042
7043 /**
Chet Haasecca2c982011-05-20 14:34:18 -07007044 * This method is called by LayoutTransition when there are 'changing' animations that need
7045 * to start after the layout/setup phase. The request is forwarded to the ViewAncestor, who
7046 * starts all pending transitions prior to the drawing phase in the current traversal.
7047 *
7048 * @param transition The LayoutTransition to be started on the next traversal.
7049 *
7050 * @hide
7051 */
7052 public void requestTransitionStart(LayoutTransition transition) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07007053 ViewRootImpl viewAncestor = getViewRootImpl();
Chet Haase1abf7fa2011-08-17 18:31:56 -07007054 if (viewAncestor != null) {
7055 viewAncestor.requestTransitionStart(transition);
7056 }
Chet Haasecca2c982011-05-20 14:34:18 -07007057 }
7058
Fabrice Di Meglio4457e852012-09-18 19:23:12 -07007059 /**
7060 * @hide
7061 */
Fabrice Di Meglio80dc53d2011-06-21 18:36:33 -07007062 @Override
Fabrice Di Meglio09ecb252013-05-03 16:51:55 -07007063 public boolean resolveRtlPropertiesIfNeeded() {
7064 final boolean result = super.resolveRtlPropertiesIfNeeded();
7065 // We dont need to resolve the children RTL properties if nothing has changed for the parent
7066 if (result) {
7067 int count = getChildCount();
7068 for (int i = 0; i < count; i++) {
7069 final View child = getChildAt(i);
7070 if (child.isLayoutDirectionInherited()) {
7071 child.resolveRtlPropertiesIfNeeded();
7072 }
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07007073 }
7074 }
Fabrice Di Meglio09ecb252013-05-03 16:51:55 -07007075 return result;
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07007076 }
7077
7078 /**
7079 * @hide
7080 */
7081 @Override
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07007082 public boolean resolveLayoutDirection() {
7083 final boolean result = super.resolveLayoutDirection();
7084 if (result) {
7085 int count = getChildCount();
7086 for (int i = 0; i < count; i++) {
7087 final View child = getChildAt(i);
7088 if (child.isLayoutDirectionInherited()) {
7089 child.resolveLayoutDirection();
7090 }
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07007091 }
7092 }
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07007093 return result;
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07007094 }
7095
7096 /**
7097 * @hide
7098 */
7099 @Override
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07007100 public boolean resolveTextDirection() {
7101 final boolean result = super.resolveTextDirection();
7102 if (result) {
7103 int count = getChildCount();
7104 for (int i = 0; i < count; i++) {
7105 final View child = getChildAt(i);
7106 if (child.isTextDirectionInherited()) {
7107 child.resolveTextDirection();
7108 }
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07007109 }
7110 }
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07007111 return result;
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07007112 }
7113
7114 /**
7115 * @hide
7116 */
7117 @Override
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07007118 public boolean resolveTextAlignment() {
7119 final boolean result = super.resolveTextAlignment();
7120 if (result) {
7121 int count = getChildCount();
7122 for (int i = 0; i < count; i++) {
7123 final View child = getChildAt(i);
7124 if (child.isTextAlignmentInherited()) {
7125 child.resolveTextAlignment();
7126 }
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07007127 }
7128 }
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07007129 return result;
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07007130 }
7131
7132 /**
7133 * @hide
7134 */
7135 @Override
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07007136 public void resolvePadding() {
7137 super.resolvePadding();
7138 int count = getChildCount();
7139 for (int i = 0; i < count; i++) {
7140 final View child = getChildAt(i);
Adam Powell05f35122014-11-10 17:47:37 -08007141 if (child.isLayoutDirectionInherited() && !child.isPaddingResolved()) {
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07007142 child.resolvePadding();
7143 }
7144 }
7145 }
7146
7147 /**
7148 * @hide
7149 */
7150 @Override
7151 protected void resolveDrawables() {
7152 super.resolveDrawables();
7153 int count = getChildCount();
7154 for (int i = 0; i < count; i++) {
7155 final View child = getChildAt(i);
Adam Powell05f35122014-11-10 17:47:37 -08007156 if (child.isLayoutDirectionInherited() && !child.areDrawablesResolved()) {
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07007157 child.resolveDrawables();
7158 }
7159 }
7160 }
7161
Fabrice Di Meglio1e0ed6b2012-10-18 16:06:52 -07007162 /**
7163 * @hide
7164 */
Fabrice Di Megliofcc33482012-10-18 11:11:51 -07007165 @Override
7166 public void resolveLayoutParams() {
7167 super.resolveLayoutParams();
7168 int count = getChildCount();
7169 for (int i = 0; i < count; i++) {
7170 final View child = getChildAt(i);
7171 child.resolveLayoutParams();
7172 }
7173 }
7174
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07007175 /**
7176 * @hide
7177 */
7178 @Override
Fabrice Di Meglio4457e852012-09-18 19:23:12 -07007179 public void resetResolvedLayoutDirection() {
7180 super.resetResolvedLayoutDirection();
7181
Fabrice Di Meglio4457e852012-09-18 19:23:12 -07007182 int count = getChildCount();
Fabrice Di Meglio80dc53d2011-06-21 18:36:33 -07007183 for (int i = 0; i < count; i++) {
7184 final View child = getChildAt(i);
Fabrice Di Meglioe56ffdc2012-09-23 14:51:16 -07007185 if (child.isLayoutDirectionInherited()) {
Fabrice Di Meglio7f86c802011-07-01 15:09:24 -07007186 child.resetResolvedLayoutDirection();
Fabrice Di Meglio80dc53d2011-06-21 18:36:33 -07007187 }
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07007188 }
7189 }
7190
7191 /**
7192 * @hide
7193 */
7194 @Override
7195 public void resetResolvedTextDirection() {
7196 super.resetResolvedTextDirection();
7197
7198 int count = getChildCount();
7199 for (int i = 0; i < count; i++) {
7200 final View child = getChildAt(i);
Fabrice Di Meglio97e146c2012-09-23 15:45:16 -07007201 if (child.isTextDirectionInherited()) {
Fabrice Di Meglio22268862011-06-27 18:13:18 -07007202 child.resetResolvedTextDirection();
7203 }
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07007204 }
7205 }
7206
7207 /**
7208 * @hide
7209 */
7210 @Override
7211 public void resetResolvedTextAlignment() {
7212 super.resetResolvedTextAlignment();
7213
7214 int count = getChildCount();
7215 for (int i = 0; i < count; i++) {
7216 final View child = getChildAt(i);
Fabrice Di Meglio1a7d4872012-09-23 16:19:58 -07007217 if (child.isTextAlignmentInherited()) {
Fabrice Di Meglio9da0f8a2012-03-13 19:37:57 -07007218 child.resetResolvedTextAlignment();
7219 }
7220 }
7221 }
7222
Fabrice Di Meglio22268862011-06-27 18:13:18 -07007223 /**
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07007224 * @hide
7225 */
7226 @Override
7227 public void resetResolvedPadding() {
7228 super.resetResolvedPadding();
7229
7230 int count = getChildCount();
7231 for (int i = 0; i < count; i++) {
7232 final View child = getChildAt(i);
7233 if (child.isLayoutDirectionInherited()) {
7234 child.resetResolvedPadding();
7235 }
7236 }
7237 }
7238
7239 /**
7240 * @hide
7241 */
7242 @Override
7243 protected void resetResolvedDrawables() {
7244 super.resetResolvedDrawables();
7245
7246 int count = getChildCount();
7247 for (int i = 0; i < count; i++) {
7248 final View child = getChildAt(i);
7249 if (child.isLayoutDirectionInherited()) {
7250 child.resetResolvedDrawables();
7251 }
7252 }
7253 }
7254
7255 /**
Patrick Dubroye0a799a2011-05-04 16:19:22 -07007256 * Return true if the pressed state should be delayed for children or descendants of this
7257 * ViewGroup. Generally, this should be done for containers that can scroll, such as a List.
7258 * This prevents the pressed state from appearing when the user is actually trying to scroll
7259 * the content.
7260 *
7261 * The default implementation returns true for compatibility reasons. Subclasses that do
7262 * not scroll should generally override this method and return false.
7263 */
7264 public boolean shouldDelayChildPressedState() {
7265 return true;
7266 }
7267
Adam Powell10ba2772014-04-15 09:46:51 -07007268 /**
7269 * @inheritDoc
7270 */
7271 @Override
7272 public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
7273 return false;
7274 }
7275
7276 /**
7277 * @inheritDoc
7278 */
7279 @Override
7280 public void onNestedScrollAccepted(View child, View target, int axes) {
7281 mNestedScrollAxes = axes;
7282 }
7283
7284 /**
7285 * @inheritDoc
7286 *
7287 * <p>The default implementation of onStopNestedScroll calls
7288 * {@link #stopNestedScroll()} to halt any recursive nested scrolling in progress.</p>
7289 */
7290 @Override
7291 public void onStopNestedScroll(View child) {
7292 // Stop any recursive nested scrolling.
7293 stopNestedScroll();
Adam Powelld4a22d42015-04-16 15:44:10 -07007294 mNestedScrollAxes = 0;
Adam Powell10ba2772014-04-15 09:46:51 -07007295 }
7296
7297 /**
7298 * @inheritDoc
7299 */
7300 @Override
7301 public void onNestedScroll(View target, int dxConsumed, int dyConsumed,
7302 int dxUnconsumed, int dyUnconsumed) {
Chris Banes61d50702016-03-23 13:11:45 +00007303 // Re-dispatch up the tree by default
7304 dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, null);
Adam Powell10ba2772014-04-15 09:46:51 -07007305 }
7306
7307 /**
7308 * @inheritDoc
7309 */
7310 @Override
7311 public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
Chris Banes61d50702016-03-23 13:11:45 +00007312 // Re-dispatch up the tree by default
7313 dispatchNestedPreScroll(dx, dy, consumed, null);
Adam Powell10ba2772014-04-15 09:46:51 -07007314 }
7315
7316 /**
7317 * @inheritDoc
7318 */
7319 @Override
Adam Powellb36e4f92014-05-01 10:23:33 -07007320 public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
Chris Banes61d50702016-03-23 13:11:45 +00007321 // Re-dispatch up the tree by default
7322 return dispatchNestedFling(velocityX, velocityY, consumed);
Adam Powell10ba2772014-04-15 09:46:51 -07007323 }
7324
7325 /**
Adam Powellb72be592014-07-16 21:41:31 -07007326 * @inheritDoc
7327 */
7328 @Override
7329 public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
Chris Banes61d50702016-03-23 13:11:45 +00007330 // Re-dispatch up the tree by default
7331 return dispatchNestedPreFling(velocityX, velocityY);
Adam Powellb72be592014-07-16 21:41:31 -07007332 }
7333
7334 /**
Adam Powell10ba2772014-04-15 09:46:51 -07007335 * Return the current axes of nested scrolling for this ViewGroup.
7336 *
7337 * <p>A ViewGroup returning something other than {@link #SCROLL_AXIS_NONE} is currently
7338 * acting as a nested scrolling parent for one or more descendant views in the hierarchy.</p>
7339 *
7340 * @return Flags indicating the current axes of nested scrolling
7341 * @see #SCROLL_AXIS_HORIZONTAL
7342 * @see #SCROLL_AXIS_VERTICAL
7343 * @see #SCROLL_AXIS_NONE
7344 */
7345 public int getNestedScrollAxes() {
7346 return mNestedScrollAxes;
7347 }
7348
Philip Milned7dd8902012-01-26 16:55:30 -08007349 /** @hide */
7350 protected void onSetLayoutParams(View child, LayoutParams layoutParams) {
Robert Carr5429daa2017-04-03 19:00:26 -07007351 requestLayout();
Philip Milned7dd8902012-01-26 16:55:30 -08007352 }
7353
George Mounte1803372014-02-26 19:00:52 +00007354 /** @hide */
7355 @Override
7356 public void captureTransitioningViews(List<View> transitioningViews) {
7357 if (getVisibility() != View.VISIBLE) {
7358 return;
7359 }
7360 if (isTransitionGroup()) {
7361 transitioningViews.add(this);
7362 } else {
7363 int count = getChildCount();
7364 for (int i = 0; i < count; i++) {
7365 View child = getChildAt(i);
7366 child.captureTransitioningViews(transitioningViews);
7367 }
7368 }
7369 }
7370
7371 /** @hide */
7372 @Override
George Mountabb352a2014-05-09 10:27:20 -07007373 public void findNamedViews(Map<String, View> namedElements) {
George Mountfe361d22014-07-08 17:25:25 -07007374 if (getVisibility() != VISIBLE && mGhostView == null) {
George Mounte1803372014-02-26 19:00:52 +00007375 return;
7376 }
George Mountabb352a2014-05-09 10:27:20 -07007377 super.findNamedViews(namedElements);
George Mounte1803372014-02-26 19:00:52 +00007378 int count = getChildCount();
7379 for (int i = 0; i < count; i++) {
7380 View child = getChildAt(i);
George Mountabb352a2014-05-09 10:27:20 -07007381 child.findNamedViews(namedElements);
George Mounte1803372014-02-26 19:00:52 +00007382 }
7383 }
7384
Patrick Dubroye0a799a2011-05-04 16:19:22 -07007385 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007386 * LayoutParams are used by views to tell their parents how they want to be
7387 * laid out. See
7388 * {@link android.R.styleable#ViewGroup_Layout ViewGroup Layout Attributes}
7389 * for a list of all child view attributes that this class supports.
Romain Guy8506ab42009-06-11 17:35:47 -07007390 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007391 * <p>
7392 * The base LayoutParams class just describes how big the view wants to be
7393 * for both width and height. For each dimension, it can specify one of:
7394 * <ul>
Dirk Dougherty75c66da2010-03-25 16:33:33 -07007395 * <li>FILL_PARENT (renamed MATCH_PARENT in API Level 8 and higher), which
7396 * means that the view wants to be as big as its parent (minus padding)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007397 * <li> WRAP_CONTENT, which means that the view wants to be just big enough
7398 * to enclose its content (plus padding)
Dirk Dougherty75c66da2010-03-25 16:33:33 -07007399 * <li> an exact number
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007400 * </ul>
7401 * There are subclasses of LayoutParams for different subclasses of
7402 * ViewGroup. For example, AbsoluteLayout has its own subclass of
Joe Fernandez558459f2011-10-13 16:47:36 -07007403 * LayoutParams which adds an X and Y value.</p>
7404 *
7405 * <div class="special reference">
7406 * <h3>Developer Guides</h3>
7407 * <p>For more information about creating user interface layouts, read the
7408 * <a href="{@docRoot}guide/topics/ui/declaring-layout.html">XML Layouts</a> developer
7409 * guide.</p></div>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007410 *
7411 * @attr ref android.R.styleable#ViewGroup_Layout_layout_height
7412 * @attr ref android.R.styleable#ViewGroup_Layout_layout_width
7413 */
7414 public static class LayoutParams {
7415 /**
Dirk Dougherty75c66da2010-03-25 16:33:33 -07007416 * Special value for the height or width requested by a View.
7417 * FILL_PARENT means that the view wants to be as big as its parent,
7418 * minus the parent's padding, if any. This value is deprecated
7419 * starting in API Level 8 and replaced by {@link #MATCH_PARENT}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007420 */
Romain Guy980a9382010-01-08 15:06:28 -08007421 @SuppressWarnings({"UnusedDeclaration"})
7422 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007423 public static final int FILL_PARENT = -1;
7424
7425 /**
7426 * Special value for the height or width requested by a View.
Gilles Debunnef5c6eff2010-02-09 19:08:36 -08007427 * MATCH_PARENT means that the view wants to be as big as its parent,
Dirk Dougherty75c66da2010-03-25 16:33:33 -07007428 * minus the parent's padding, if any. Introduced in API Level 8.
Romain Guy980a9382010-01-08 15:06:28 -08007429 */
7430 public static final int MATCH_PARENT = -1;
7431
7432 /**
7433 * Special value for the height or width requested by a View.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007434 * WRAP_CONTENT means that the view wants to be just large enough to fit
7435 * its own internal content, taking its own padding into account.
7436 */
7437 public static final int WRAP_CONTENT = -2;
7438
7439 /**
Dirk Dougherty75c66da2010-03-25 16:33:33 -07007440 * Information about how wide the view wants to be. Can be one of the
Mark Dolinerd0646dc2014-08-27 16:04:02 -07007441 * constants FILL_PARENT (replaced by MATCH_PARENT
7442 * in API Level 8) or WRAP_CONTENT, or an exact size.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007443 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07007444 @ViewDebug.ExportedProperty(category = "layout", mapping = {
Romain Guy980a9382010-01-08 15:06:28 -08007445 @ViewDebug.IntToString(from = MATCH_PARENT, to = "MATCH_PARENT"),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007446 @ViewDebug.IntToString(from = WRAP_CONTENT, to = "WRAP_CONTENT")
7447 })
7448 public int width;
7449
7450 /**
Dirk Dougherty75c66da2010-03-25 16:33:33 -07007451 * Information about how tall the view wants to be. Can be one of the
Mark Dolinerd0646dc2014-08-27 16:04:02 -07007452 * constants FILL_PARENT (replaced by MATCH_PARENT
7453 * in API Level 8) or WRAP_CONTENT, or an exact size.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007454 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07007455 @ViewDebug.ExportedProperty(category = "layout", mapping = {
Romain Guy980a9382010-01-08 15:06:28 -08007456 @ViewDebug.IntToString(from = MATCH_PARENT, to = "MATCH_PARENT"),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007457 @ViewDebug.IntToString(from = WRAP_CONTENT, to = "WRAP_CONTENT")
7458 })
7459 public int height;
7460
7461 /**
7462 * Used to animate layouts.
7463 */
7464 public LayoutAnimationController.AnimationParameters layoutAnimationParameters;
7465
7466 /**
7467 * Creates a new set of layout parameters. The values are extracted from
7468 * the supplied attributes set and context. The XML attributes mapped
7469 * to this set of layout parameters are:
7470 *
7471 * <ul>
7472 * <li><code>layout_width</code>: the width, either an exact value,
Dirk Dougherty75c66da2010-03-25 16:33:33 -07007473 * {@link #WRAP_CONTENT}, or {@link #FILL_PARENT} (replaced by
7474 * {@link #MATCH_PARENT} in API Level 8)</li>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007475 * <li><code>layout_height</code>: the height, either an exact value,
Dirk Dougherty75c66da2010-03-25 16:33:33 -07007476 * {@link #WRAP_CONTENT}, or {@link #FILL_PARENT} (replaced by
7477 * {@link #MATCH_PARENT} in API Level 8)</li>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007478 * </ul>
7479 *
7480 * @param c the application environment
7481 * @param attrs the set of attributes from which to extract the layout
7482 * parameters' values
7483 */
7484 public LayoutParams(Context c, AttributeSet attrs) {
7485 TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ViewGroup_Layout);
7486 setBaseAttributes(a,
7487 R.styleable.ViewGroup_Layout_layout_width,
7488 R.styleable.ViewGroup_Layout_layout_height);
7489 a.recycle();
7490 }
7491
7492 /**
7493 * Creates a new set of layout parameters with the specified width
7494 * and height.
7495 *
Dirk Dougherty75c66da2010-03-25 16:33:33 -07007496 * @param width the width, either {@link #WRAP_CONTENT},
7497 * {@link #FILL_PARENT} (replaced by {@link #MATCH_PARENT} in
7498 * API Level 8), or a fixed size in pixels
7499 * @param height the height, either {@link #WRAP_CONTENT},
7500 * {@link #FILL_PARENT} (replaced by {@link #MATCH_PARENT} in
7501 * API Level 8), or a fixed size in pixels
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007502 */
7503 public LayoutParams(int width, int height) {
7504 this.width = width;
7505 this.height = height;
7506 }
7507
7508 /**
7509 * Copy constructor. Clones the width and height values of the source.
7510 *
7511 * @param source The layout params to copy from.
7512 */
7513 public LayoutParams(LayoutParams source) {
7514 this.width = source.width;
7515 this.height = source.height;
7516 }
7517
7518 /**
7519 * Used internally by MarginLayoutParams.
7520 * @hide
7521 */
7522 LayoutParams() {
7523 }
7524
7525 /**
Dave Burke579e1402012-10-18 20:41:55 -07007526 * Extracts the layout parameters from the supplied attributes.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007527 *
7528 * @param a the style attributes to extract the parameters from
7529 * @param widthAttr the identifier of the width attribute
7530 * @param heightAttr the identifier of the height attribute
7531 */
7532 protected void setBaseAttributes(TypedArray a, int widthAttr, int heightAttr) {
Dave Burke579e1402012-10-18 20:41:55 -07007533 width = a.getLayoutDimension(widthAttr, "layout_width");
7534 height = a.getLayoutDimension(heightAttr, "layout_height");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007535 }
7536
7537 /**
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007538 * Resolve layout parameters depending on the layout direction. Subclasses that care about
7539 * layoutDirection changes should override this method. The default implementation does
7540 * nothing.
7541 *
7542 * @param layoutDirection the direction of the layout
7543 *
7544 * {@link View#LAYOUT_DIRECTION_LTR}
7545 * {@link View#LAYOUT_DIRECTION_RTL}
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007546 */
Fabrice Di Meglio2918ab62012-10-10 16:39:25 -07007547 public void resolveLayoutDirection(int layoutDirection) {
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007548 }
7549
7550 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007551 * Returns a String representation of this set of layout parameters.
7552 *
7553 * @param output the String to prepend to the internal representation
7554 * @return a String with the following format: output +
7555 * "ViewGroup.LayoutParams={ width=WIDTH, height=HEIGHT }"
Romain Guy8506ab42009-06-11 17:35:47 -07007556 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007557 * @hide
7558 */
7559 public String debug(String output) {
7560 return output + "ViewGroup.LayoutParams={ width="
7561 + sizeToString(width) + ", height=" + sizeToString(height) + " }";
7562 }
7563
7564 /**
Philip Milne10ca24a2012-04-23 15:38:27 -07007565 * Use {@code canvas} to draw suitable debugging annotations for these LayoutParameters.
7566 *
7567 * @param view the view that contains these layout parameters
7568 * @param canvas the canvas on which to draw
7569 *
7570 * @hide
7571 */
Philip Milne7b757812012-09-19 18:13:44 -07007572 public void onDebugDraw(View view, Canvas canvas, Paint paint) {
Philip Milne10ca24a2012-04-23 15:38:27 -07007573 }
7574
7575 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007576 * Converts the specified size to a readable String.
7577 *
7578 * @param size the size to convert
7579 * @return a String instance representing the supplied size
Romain Guy8506ab42009-06-11 17:35:47 -07007580 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007581 * @hide
7582 */
7583 protected static String sizeToString(int size) {
7584 if (size == WRAP_CONTENT) {
7585 return "wrap-content";
7586 }
Romain Guy980a9382010-01-08 15:06:28 -08007587 if (size == MATCH_PARENT) {
7588 return "match-parent";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007589 }
7590 return String.valueOf(size);
7591 }
Siva Velusamy0d857b92015-04-22 10:23:56 -07007592
7593 /** @hide */
7594 void encode(@NonNull ViewHierarchyEncoder encoder) {
7595 encoder.beginObject(this);
7596 encodeProperties(encoder);
7597 encoder.endObject();
7598 }
7599
7600 /** @hide */
7601 protected void encodeProperties(@NonNull ViewHierarchyEncoder encoder) {
7602 encoder.addProperty("width", width);
7603 encoder.addProperty("height", height);
7604 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007605 }
7606
7607 /**
7608 * Per-child layout information for layouts that support margins.
7609 * See
7610 * {@link android.R.styleable#ViewGroup_MarginLayout ViewGroup Margin Layout Attributes}
7611 * for a list of all child view attributes that this class supports.
Chet Haase353d3972017-06-29 07:54:19 -07007612 *
7613 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_margin
7614 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginHorizontal
7615 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginVertical
7616 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginLeft
7617 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginTop
7618 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginRight
7619 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginBottom
7620 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
7621 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007622 */
7623 public static class MarginLayoutParams extends ViewGroup.LayoutParams {
7624 /**
Adam Powella7a735f2014-10-09 12:54:52 -07007625 * The left margin in pixels of the child. Margin values should be positive.
Philip Milned7dd8902012-01-26 16:55:30 -08007626 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
7627 * to this field.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007628 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07007629 @ViewDebug.ExportedProperty(category = "layout")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007630 public int leftMargin;
7631
7632 /**
Adam Powella7a735f2014-10-09 12:54:52 -07007633 * The top margin in pixels of the child. Margin values should be positive.
Philip Milned7dd8902012-01-26 16:55:30 -08007634 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
7635 * to this field.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007636 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07007637 @ViewDebug.ExportedProperty(category = "layout")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007638 public int topMargin;
7639
7640 /**
Adam Powella7a735f2014-10-09 12:54:52 -07007641 * The right margin in pixels of the child. Margin values should be positive.
Philip Milned7dd8902012-01-26 16:55:30 -08007642 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
7643 * to this field.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007644 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07007645 @ViewDebug.ExportedProperty(category = "layout")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007646 public int rightMargin;
7647
7648 /**
Adam Powella7a735f2014-10-09 12:54:52 -07007649 * The bottom margin in pixels of the child. Margin values should be positive.
Philip Milned7dd8902012-01-26 16:55:30 -08007650 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
7651 * to this field.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007652 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07007653 @ViewDebug.ExportedProperty(category = "layout")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007654 public int bottomMargin;
7655
7656 /**
Adam Powella7a735f2014-10-09 12:54:52 -07007657 * The start margin in pixels of the child. Margin values should be positive.
Fabrice Di Meglio54546f22012-02-14 16:26:16 -08007658 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
7659 * to this field.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007660 */
7661 @ViewDebug.ExportedProperty(category = "layout")
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07007662 private int startMargin = DEFAULT_MARGIN_RELATIVE;
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007663
7664 /**
Adam Powella7a735f2014-10-09 12:54:52 -07007665 * The end margin in pixels of the child. Margin values should be positive.
Fabrice Di Meglio54546f22012-02-14 16:26:16 -08007666 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
7667 * to this field.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007668 */
7669 @ViewDebug.ExportedProperty(category = "layout")
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07007670 private int endMargin = DEFAULT_MARGIN_RELATIVE;
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007671
7672 /**
7673 * The default start and end margin.
Fabrice Di Megliof443f982012-07-13 20:24:03 -07007674 * @hide
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007675 */
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07007676 public static final int DEFAULT_MARGIN_RELATIVE = Integer.MIN_VALUE;
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007677
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007678 /**
7679 * Bit 0: layout direction
7680 * Bit 1: layout direction
7681 * Bit 2: left margin undefined
7682 * Bit 3: right margin undefined
7683 * Bit 4: is RTL compatibility mode
7684 * Bit 5: need resolution
7685 *
7686 * Bit 6 to 7 not used
7687 *
7688 * @hide
7689 */
7690 @ViewDebug.ExportedProperty(category = "layout", flagMapping = {
7691 @ViewDebug.FlagToString(mask = LAYOUT_DIRECTION_MASK,
7692 equals = LAYOUT_DIRECTION_MASK, name = "LAYOUT_DIRECTION"),
7693 @ViewDebug.FlagToString(mask = LEFT_MARGIN_UNDEFINED_MASK,
7694 equals = LEFT_MARGIN_UNDEFINED_MASK, name = "LEFT_MARGIN_UNDEFINED_MASK"),
7695 @ViewDebug.FlagToString(mask = RIGHT_MARGIN_UNDEFINED_MASK,
7696 equals = RIGHT_MARGIN_UNDEFINED_MASK, name = "RIGHT_MARGIN_UNDEFINED_MASK"),
7697 @ViewDebug.FlagToString(mask = RTL_COMPATIBILITY_MODE_MASK,
7698 equals = RTL_COMPATIBILITY_MODE_MASK, name = "RTL_COMPATIBILITY_MODE_MASK"),
7699 @ViewDebug.FlagToString(mask = NEED_RESOLUTION_MASK,
7700 equals = NEED_RESOLUTION_MASK, name = "NEED_RESOLUTION_MASK")
Jon Miranda4597e982014-07-29 07:25:49 -07007701 }, formatToHexString = true)
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007702 byte mMarginFlags;
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07007703
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007704 private static final int LAYOUT_DIRECTION_MASK = 0x00000003;
7705 private static final int LEFT_MARGIN_UNDEFINED_MASK = 0x00000004;
7706 private static final int RIGHT_MARGIN_UNDEFINED_MASK = 0x00000008;
7707 private static final int RTL_COMPATIBILITY_MODE_MASK = 0x00000010;
7708 private static final int NEED_RESOLUTION_MASK = 0x00000020;
Fabrice Di Megliof443f982012-07-13 20:24:03 -07007709
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007710 private static final int DEFAULT_MARGIN_RESOLVED = 0;
7711 private static final int UNDEFINED_MARGIN = DEFAULT_MARGIN_RELATIVE;
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07007712
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007713 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007714 * Creates a new set of layout parameters. The values are extracted from
7715 * the supplied attributes set and context.
7716 *
7717 * @param c the application environment
7718 * @param attrs the set of attributes from which to extract the layout
7719 * parameters' values
7720 */
7721 public MarginLayoutParams(Context c, AttributeSet attrs) {
7722 super();
7723
7724 TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ViewGroup_MarginLayout);
7725 setBaseAttributes(a,
7726 R.styleable.ViewGroup_MarginLayout_layout_width,
7727 R.styleable.ViewGroup_MarginLayout_layout_height);
7728
7729 int margin = a.getDimensionPixelSize(
7730 com.android.internal.R.styleable.ViewGroup_MarginLayout_layout_margin, -1);
7731 if (margin >= 0) {
7732 leftMargin = margin;
7733 topMargin = margin;
7734 rightMargin= margin;
7735 bottomMargin = margin;
7736 } else {
Chet Haase40b2de52016-11-28 16:11:42 -08007737 int horizontalMargin = a.getDimensionPixelSize(
7738 R.styleable.ViewGroup_MarginLayout_layout_marginHorizontal, -1);
7739 int verticalMargin = a.getDimensionPixelSize(
7740 R.styleable.ViewGroup_MarginLayout_layout_marginVertical, -1);
7741
7742 if (horizontalMargin >= 0) {
7743 leftMargin = horizontalMargin;
7744 rightMargin = horizontalMargin;
7745 } else {
7746 leftMargin = a.getDimensionPixelSize(
7747 R.styleable.ViewGroup_MarginLayout_layout_marginLeft,
7748 UNDEFINED_MARGIN);
7749 if (leftMargin == UNDEFINED_MARGIN) {
7750 mMarginFlags |= LEFT_MARGIN_UNDEFINED_MASK;
7751 leftMargin = DEFAULT_MARGIN_RESOLVED;
7752 }
7753 rightMargin = a.getDimensionPixelSize(
7754 R.styleable.ViewGroup_MarginLayout_layout_marginRight,
7755 UNDEFINED_MARGIN);
7756 if (rightMargin == UNDEFINED_MARGIN) {
7757 mMarginFlags |= RIGHT_MARGIN_UNDEFINED_MASK;
7758 rightMargin = DEFAULT_MARGIN_RESOLVED;
7759 }
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07007760 }
7761
Chet Haasecb3d0232017-05-24 18:27:14 -07007762 startMargin = a.getDimensionPixelSize(
7763 R.styleable.ViewGroup_MarginLayout_layout_marginStart,
7764 DEFAULT_MARGIN_RELATIVE);
7765 endMargin = a.getDimensionPixelSize(
7766 R.styleable.ViewGroup_MarginLayout_layout_marginEnd,
7767 DEFAULT_MARGIN_RELATIVE);
7768
Chet Haase40b2de52016-11-28 16:11:42 -08007769 if (verticalMargin >= 0) {
7770 topMargin = verticalMargin;
7771 bottomMargin = verticalMargin;
7772 } else {
7773 topMargin = a.getDimensionPixelSize(
7774 R.styleable.ViewGroup_MarginLayout_layout_marginTop,
7775 DEFAULT_MARGIN_RESOLVED);
7776 bottomMargin = a.getDimensionPixelSize(
7777 R.styleable.ViewGroup_MarginLayout_layout_marginBottom,
7778 DEFAULT_MARGIN_RESOLVED);
7779 }
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07007780
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007781 if (isMarginRelative()) {
7782 mMarginFlags |= NEED_RESOLUTION_MASK;
7783 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007784 }
7785
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07007786 final boolean hasRtlSupport = c.getApplicationInfo().hasRtlSupport();
7787 final int targetSdkVersion = c.getApplicationInfo().targetSdkVersion;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007788 if (targetSdkVersion < JELLY_BEAN_MR1 || !hasRtlSupport) {
7789 mMarginFlags |= RTL_COMPATIBILITY_MODE_MASK;
7790 }
7791
7792 // Layout direction is LTR by default
7793 mMarginFlags |= LAYOUT_DIRECTION_LTR;
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07007794
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007795 a.recycle();
7796 }
7797
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007798 public MarginLayoutParams(int width, int height) {
7799 super(width, height);
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07007800
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007801 mMarginFlags |= LEFT_MARGIN_UNDEFINED_MASK;
7802 mMarginFlags |= RIGHT_MARGIN_UNDEFINED_MASK;
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07007803
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007804 mMarginFlags &= ~NEED_RESOLUTION_MASK;
7805 mMarginFlags &= ~RTL_COMPATIBILITY_MODE_MASK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007806 }
7807
7808 /**
7809 * Copy constructor. Clones the width, height and margin values of the source.
7810 *
7811 * @param source The layout params to copy from.
7812 */
7813 public MarginLayoutParams(MarginLayoutParams source) {
7814 this.width = source.width;
7815 this.height = source.height;
7816
7817 this.leftMargin = source.leftMargin;
7818 this.topMargin = source.topMargin;
7819 this.rightMargin = source.rightMargin;
7820 this.bottomMargin = source.bottomMargin;
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007821 this.startMargin = source.startMargin;
7822 this.endMargin = source.endMargin;
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07007823
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007824 this.mMarginFlags = source.mMarginFlags;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007825 }
7826
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007827 public MarginLayoutParams(LayoutParams source) {
7828 super(source);
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07007829
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007830 mMarginFlags |= LEFT_MARGIN_UNDEFINED_MASK;
7831 mMarginFlags |= RIGHT_MARGIN_UNDEFINED_MASK;
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07007832
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007833 mMarginFlags &= ~NEED_RESOLUTION_MASK;
7834 mMarginFlags &= ~RTL_COMPATIBILITY_MODE_MASK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007835 }
7836
7837 /**
Adam Powelld7600832014-07-01 15:22:50 -07007838 * @hide Used internally.
7839 */
7840 public final void copyMarginsFrom(MarginLayoutParams source) {
7841 this.leftMargin = source.leftMargin;
7842 this.topMargin = source.topMargin;
7843 this.rightMargin = source.rightMargin;
7844 this.bottomMargin = source.bottomMargin;
7845 this.startMargin = source.startMargin;
7846 this.endMargin = source.endMargin;
7847
7848 this.mMarginFlags = source.mMarginFlags;
7849 }
7850
7851 /**
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007852 * Sets the margins, in pixels. A call to {@link android.view.View#requestLayout()} needs
7853 * to be done so that the new margins are taken into account. Left and right margins may be
7854 * overriden by {@link android.view.View#requestLayout()} depending on layout direction.
Adam Powella7a735f2014-10-09 12:54:52 -07007855 * Margin values should be positive.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007856 *
7857 * @param left the left margin size
7858 * @param top the top margin size
7859 * @param right the right margin size
7860 * @param bottom the bottom margin size
7861 *
7862 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginLeft
7863 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginTop
7864 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginRight
7865 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginBottom
7866 */
7867 public void setMargins(int left, int top, int right, int bottom) {
7868 leftMargin = left;
7869 topMargin = top;
7870 rightMargin = right;
7871 bottomMargin = bottom;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007872 mMarginFlags &= ~LEFT_MARGIN_UNDEFINED_MASK;
7873 mMarginFlags &= ~RIGHT_MARGIN_UNDEFINED_MASK;
7874 if (isMarginRelative()) {
7875 mMarginFlags |= NEED_RESOLUTION_MASK;
7876 } else {
7877 mMarginFlags &= ~NEED_RESOLUTION_MASK;
7878 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007879 }
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007880
7881 /**
7882 * Sets the relative margins, in pixels. A call to {@link android.view.View#requestLayout()}
7883 * needs to be done so that the new relative margins are taken into account. Left and right
7884 * margins may be overriden by {@link android.view.View#requestLayout()} depending on layout
Adam Powella7a735f2014-10-09 12:54:52 -07007885 * direction. Margin values should be positive.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007886 *
7887 * @param start the start margin size
7888 * @param top the top margin size
7889 * @param end the right margin size
7890 * @param bottom the bottom margin size
7891 *
7892 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
7893 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginTop
7894 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
7895 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginBottom
7896 *
7897 * @hide
7898 */
7899 public void setMarginsRelative(int start, int top, int end, int bottom) {
7900 startMargin = start;
7901 topMargin = top;
7902 endMargin = end;
7903 bottomMargin = bottom;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007904 mMarginFlags |= NEED_RESOLUTION_MASK;
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007905 }
7906
7907 /**
Adam Powella7a735f2014-10-09 12:54:52 -07007908 * Sets the relative start margin. Margin values should be positive.
Fabrice Di Meglioa40627d2012-09-11 16:47:21 -07007909 *
Fabrice Di Meglio61a21772012-09-12 16:33:13 -07007910 * @param start the start margin size
Fabrice Di Meglioa40627d2012-09-11 16:47:21 -07007911 *
7912 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
7913 */
7914 public void setMarginStart(int start) {
7915 startMargin = start;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007916 mMarginFlags |= NEED_RESOLUTION_MASK;
Fabrice Di Meglioa40627d2012-09-11 16:47:21 -07007917 }
7918
7919 /**
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007920 * Returns the start margin in pixels.
7921 *
7922 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
7923 *
7924 * @return the start margin in pixels.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007925 */
7926 public int getMarginStart() {
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07007927 if (startMargin != DEFAULT_MARGIN_RELATIVE) return startMargin;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007928 if ((mMarginFlags & NEED_RESOLUTION_MASK) == NEED_RESOLUTION_MASK) {
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07007929 doResolveMargins();
7930 }
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007931 switch(mMarginFlags & LAYOUT_DIRECTION_MASK) {
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07007932 case View.LAYOUT_DIRECTION_RTL:
7933 return rightMargin;
7934 case View.LAYOUT_DIRECTION_LTR:
7935 default:
7936 return leftMargin;
7937 }
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007938 }
7939
7940 /**
Adam Powella7a735f2014-10-09 12:54:52 -07007941 * Sets the relative end margin. Margin values should be positive.
Fabrice Di Meglioa40627d2012-09-11 16:47:21 -07007942 *
Fabrice Di Meglio61a21772012-09-12 16:33:13 -07007943 * @param end the end margin size
Fabrice Di Meglioa40627d2012-09-11 16:47:21 -07007944 *
7945 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
7946 */
7947 public void setMarginEnd(int end) {
7948 endMargin = end;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007949 mMarginFlags |= NEED_RESOLUTION_MASK;
Fabrice Di Meglioa40627d2012-09-11 16:47:21 -07007950 }
7951
7952 /**
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007953 * Returns the end margin in pixels.
7954 *
7955 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
7956 *
7957 * @return the end margin in pixels.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007958 */
7959 public int getMarginEnd() {
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07007960 if (endMargin != DEFAULT_MARGIN_RELATIVE) return endMargin;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007961 if ((mMarginFlags & NEED_RESOLUTION_MASK) == NEED_RESOLUTION_MASK) {
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07007962 doResolveMargins();
7963 }
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007964 switch(mMarginFlags & LAYOUT_DIRECTION_MASK) {
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07007965 case View.LAYOUT_DIRECTION_RTL:
7966 return leftMargin;
7967 case View.LAYOUT_DIRECTION_LTR:
7968 default:
7969 return rightMargin;
7970 }
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007971 }
7972
7973 /**
7974 * Check if margins are relative.
7975 *
7976 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
7977 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
7978 *
Fabrice Di Megliof443f982012-07-13 20:24:03 -07007979 * @return true if either marginStart or marginEnd has been set.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007980 */
7981 public boolean isMarginRelative() {
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07007982 return (startMargin != DEFAULT_MARGIN_RELATIVE || endMargin != DEFAULT_MARGIN_RELATIVE);
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007983 }
7984
7985 /**
Fabrice Di Megliof443f982012-07-13 20:24:03 -07007986 * Set the layout direction
7987 * @param layoutDirection the layout direction.
7988 * Should be either {@link View#LAYOUT_DIRECTION_LTR}
7989 * or {@link View#LAYOUT_DIRECTION_RTL}.
7990 */
7991 public void setLayoutDirection(int layoutDirection) {
7992 if (layoutDirection != View.LAYOUT_DIRECTION_LTR &&
7993 layoutDirection != View.LAYOUT_DIRECTION_RTL) return;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007994 if (layoutDirection != (mMarginFlags & LAYOUT_DIRECTION_MASK)) {
7995 mMarginFlags &= ~LAYOUT_DIRECTION_MASK;
7996 mMarginFlags |= (layoutDirection & LAYOUT_DIRECTION_MASK);
7997 if (isMarginRelative()) {
7998 mMarginFlags |= NEED_RESOLUTION_MASK;
7999 } else {
8000 mMarginFlags &= ~NEED_RESOLUTION_MASK;
8001 }
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07008002 }
Fabrice Di Megliof443f982012-07-13 20:24:03 -07008003 }
8004
8005 /**
8006 * Retuns the layout direction. Can be either {@link View#LAYOUT_DIRECTION_LTR} or
8007 * {@link View#LAYOUT_DIRECTION_RTL}.
8008 *
8009 * @return the layout direction.
8010 */
8011 public int getLayoutDirection() {
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008012 return (mMarginFlags & LAYOUT_DIRECTION_MASK);
Fabrice Di Megliof443f982012-07-13 20:24:03 -07008013 }
8014
8015 /**
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07008016 * This will be called by {@link android.view.View#requestLayout()}. Left and Right margins
Fabrice Di Meglio98aec1c2012-02-13 16:54:05 -08008017 * may be overridden depending on layout direction.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07008018 */
8019 @Override
Fabrice Di Meglio2918ab62012-10-10 16:39:25 -07008020 public void resolveLayoutDirection(int layoutDirection) {
Fabrice Di Megliof443f982012-07-13 20:24:03 -07008021 setLayoutDirection(layoutDirection);
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07008022
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07008023 // No relative margin or pre JB-MR1 case or no need to resolve, just dont do anything
8024 // Will use the left and right margins if no relative margin is defined.
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008025 if (!isMarginRelative() ||
8026 (mMarginFlags & NEED_RESOLUTION_MASK) != NEED_RESOLUTION_MASK) return;
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07008027
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07008028 // Proceed with resolution
8029 doResolveMargins();
8030 }
8031
8032 private void doResolveMargins() {
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008033 if ((mMarginFlags & RTL_COMPATIBILITY_MODE_MASK) == RTL_COMPATIBILITY_MODE_MASK) {
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07008034 // if left or right margins are not defined and if we have some start or end margin
8035 // defined then use those start and end margins.
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008036 if ((mMarginFlags & LEFT_MARGIN_UNDEFINED_MASK) == LEFT_MARGIN_UNDEFINED_MASK
8037 && startMargin > DEFAULT_MARGIN_RELATIVE) {
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07008038 leftMargin = startMargin;
8039 }
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008040 if ((mMarginFlags & RIGHT_MARGIN_UNDEFINED_MASK) == RIGHT_MARGIN_UNDEFINED_MASK
8041 && endMargin > DEFAULT_MARGIN_RELATIVE) {
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07008042 rightMargin = endMargin;
8043 }
8044 } else {
8045 // We have some relative margins (either the start one or the end one or both). So use
8046 // them and override what has been defined for left and right margins. If either start
8047 // or end margin is not defined, just set it to default "0".
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008048 switch(mMarginFlags & LAYOUT_DIRECTION_MASK) {
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07008049 case View.LAYOUT_DIRECTION_RTL:
8050 leftMargin = (endMargin > DEFAULT_MARGIN_RELATIVE) ?
8051 endMargin : DEFAULT_MARGIN_RESOLVED;
8052 rightMargin = (startMargin > DEFAULT_MARGIN_RELATIVE) ?
8053 startMargin : DEFAULT_MARGIN_RESOLVED;
8054 break;
8055 case View.LAYOUT_DIRECTION_LTR:
8056 default:
8057 leftMargin = (startMargin > DEFAULT_MARGIN_RELATIVE) ?
8058 startMargin : DEFAULT_MARGIN_RESOLVED;
8059 rightMargin = (endMargin > DEFAULT_MARGIN_RELATIVE) ?
8060 endMargin : DEFAULT_MARGIN_RESOLVED;
8061 break;
8062 }
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07008063 }
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008064 mMarginFlags &= ~NEED_RESOLUTION_MASK;
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07008065 }
Philip Milne10ca24a2012-04-23 15:38:27 -07008066
Fabrice Di Meglio03b8d3a2012-09-27 17:05:27 -07008067 /**
8068 * @hide
8069 */
8070 public boolean isLayoutRtl() {
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008071 return ((mMarginFlags & LAYOUT_DIRECTION_MASK) == View.LAYOUT_DIRECTION_RTL);
Fabrice Di Megliof443f982012-07-13 20:24:03 -07008072 }
8073
Philip Milne10ca24a2012-04-23 15:38:27 -07008074 /**
8075 * @hide
8076 */
8077 @Override
Philip Milne7b757812012-09-19 18:13:44 -07008078 public void onDebugDraw(View view, Canvas canvas, Paint paint) {
8079 Insets oi = isLayoutModeOptical(view.mParent) ? view.getOpticalInsets() : Insets.NONE;
8080
8081 fillDifference(canvas,
8082 view.getLeft() + oi.left,
8083 view.getTop() + oi.top,
8084 view.getRight() - oi.right,
8085 view.getBottom() - oi.bottom,
8086 leftMargin,
8087 topMargin,
8088 rightMargin,
8089 bottomMargin,
8090 paint);
Philip Milne10ca24a2012-04-23 15:38:27 -07008091 }
Siva Velusamy0d857b92015-04-22 10:23:56 -07008092
8093 /** @hide */
8094 @Override
8095 protected void encodeProperties(@NonNull ViewHierarchyEncoder encoder) {
8096 super.encodeProperties(encoder);
8097 encoder.addProperty("leftMargin", leftMargin);
8098 encoder.addProperty("topMargin", topMargin);
8099 encoder.addProperty("rightMargin", rightMargin);
8100 encoder.addProperty("bottomMargin", bottomMargin);
8101 encoder.addProperty("startMargin", startMargin);
8102 encoder.addProperty("endMargin", endMargin);
8103 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008104 }
Adam Powell2b342f02010-08-18 18:14:13 -07008105
Jeff Brown20e987b2010-08-23 12:01:02 -07008106 /* Describes a touched view and the ids of the pointers that it has captured.
8107 *
8108 * This code assumes that pointer ids are always in the range 0..31 such that
8109 * it can use a bitfield to track which pointer ids are present.
8110 * As it happens, the lower layers of the input dispatch pipeline also use the
8111 * same trick so the assumption should be safe here...
8112 */
8113 private static final class TouchTarget {
8114 private static final int MAX_RECYCLED = 32;
Romain Guy6410c0a2013-06-17 11:21:58 -07008115 private static final Object sRecycleLock = new Object[0];
Jeff Brown20e987b2010-08-23 12:01:02 -07008116 private static TouchTarget sRecycleBin;
8117 private static int sRecycledCount;
Adam Powell2b342f02010-08-18 18:14:13 -07008118
Jeff Brown20e987b2010-08-23 12:01:02 -07008119 public static final int ALL_POINTER_IDS = -1; // all ones
Adam Powell2b342f02010-08-18 18:14:13 -07008120
Jeff Brown20e987b2010-08-23 12:01:02 -07008121 // The touched child view.
8122 public View child;
8123
8124 // The combined bit mask of pointer ids for all pointers captured by the target.
8125 public int pointerIdBits;
8126
8127 // The next target in the target list.
8128 public TouchTarget next;
8129
8130 private TouchTarget() {
Adam Powell2b342f02010-08-18 18:14:13 -07008131 }
8132
Alan Viverettea7b85e62016-01-22 10:14:02 -05008133 public static TouchTarget obtain(@NonNull View child, int pointerIdBits) {
8134 if (child == null) {
8135 throw new IllegalArgumentException("child must be non-null");
8136 }
8137
Jeff Brown20e987b2010-08-23 12:01:02 -07008138 final TouchTarget target;
8139 synchronized (sRecycleLock) {
Adam Powell816c3be2010-08-23 18:00:05 -07008140 if (sRecycleBin == null) {
Jeff Brown20e987b2010-08-23 12:01:02 -07008141 target = new TouchTarget();
Adam Powell816c3be2010-08-23 18:00:05 -07008142 } else {
Jeff Brown20e987b2010-08-23 12:01:02 -07008143 target = sRecycleBin;
8144 sRecycleBin = target.next;
8145 sRecycledCount--;
8146 target.next = null;
Adam Powell816c3be2010-08-23 18:00:05 -07008147 }
Adam Powell816c3be2010-08-23 18:00:05 -07008148 }
Jeff Brown20e987b2010-08-23 12:01:02 -07008149 target.child = child;
8150 target.pointerIdBits = pointerIdBits;
8151 return target;
8152 }
Adam Powell816c3be2010-08-23 18:00:05 -07008153
Jeff Brown20e987b2010-08-23 12:01:02 -07008154 public void recycle() {
Alan Viverettea7b85e62016-01-22 10:14:02 -05008155 if (child == null) {
8156 throw new IllegalStateException("already recycled once");
8157 }
8158
Jeff Brown20e987b2010-08-23 12:01:02 -07008159 synchronized (sRecycleLock) {
8160 if (sRecycledCount < MAX_RECYCLED) {
8161 next = sRecycleBin;
8162 sRecycleBin = this;
8163 sRecycledCount += 1;
Patrick Dubroyfb0547d22010-10-19 17:36:18 -07008164 } else {
8165 next = null;
Adam Powell816c3be2010-08-23 18:00:05 -07008166 }
Patrick Dubroyfb0547d22010-10-19 17:36:18 -07008167 child = null;
Adam Powell816c3be2010-08-23 18:00:05 -07008168 }
8169 }
Adam Powell2b342f02010-08-18 18:14:13 -07008170 }
Jeff Brown87b7f802011-06-21 18:35:45 -07008171
8172 /* Describes a hovered view. */
8173 private static final class HoverTarget {
8174 private static final int MAX_RECYCLED = 32;
Romain Guy6410c0a2013-06-17 11:21:58 -07008175 private static final Object sRecycleLock = new Object[0];
Jeff Brown87b7f802011-06-21 18:35:45 -07008176 private static HoverTarget sRecycleBin;
8177 private static int sRecycledCount;
8178
8179 // The hovered child view.
8180 public View child;
8181
8182 // The next target in the target list.
8183 public HoverTarget next;
8184
8185 private HoverTarget() {
8186 }
8187
Alan Viverettea7b85e62016-01-22 10:14:02 -05008188 public static HoverTarget obtain(@NonNull View child) {
8189 if (child == null) {
8190 throw new IllegalArgumentException("child must be non-null");
8191 }
8192
Jeff Brown87b7f802011-06-21 18:35:45 -07008193 final HoverTarget target;
8194 synchronized (sRecycleLock) {
8195 if (sRecycleBin == null) {
8196 target = new HoverTarget();
8197 } else {
8198 target = sRecycleBin;
8199 sRecycleBin = target.next;
Alan Viverettea7b85e62016-01-22 10:14:02 -05008200 sRecycledCount--;
Jeff Brown87b7f802011-06-21 18:35:45 -07008201 target.next = null;
8202 }
8203 }
8204 target.child = child;
8205 return target;
8206 }
8207
8208 public void recycle() {
Alan Viverettea7b85e62016-01-22 10:14:02 -05008209 if (child == null) {
8210 throw new IllegalStateException("already recycled once");
8211 }
8212
Jeff Brown87b7f802011-06-21 18:35:45 -07008213 synchronized (sRecycleLock) {
8214 if (sRecycledCount < MAX_RECYCLED) {
8215 next = sRecycleBin;
8216 sRecycleBin = this;
8217 sRecycledCount += 1;
8218 } else {
8219 next = null;
8220 }
8221 child = null;
8222 }
8223 }
8224 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07008225
8226 /**
Svet Ganov2f8fb1f2017-03-13 00:21:04 -07008227 * Pooled class that to hold the children for autifill.
8228 */
8229 static class ChildListForAutoFill extends ArrayList<View> {
8230 private static final int MAX_POOL_SIZE = 32;
8231
8232 private static final Pools.SimplePool<ChildListForAutoFill> sPool =
8233 new Pools.SimplePool<>(MAX_POOL_SIZE);
8234
8235 public static ChildListForAutoFill obtain() {
8236 ChildListForAutoFill list = sPool.acquire();
8237 if (list == null) {
8238 list = new ChildListForAutoFill();
8239 }
8240 return list;
8241 }
8242
8243 public void recycle() {
8244 clear();
8245 sPool.release(this);
8246 }
8247 }
8248
8249 /**
Svetoslav Ganov42138042012-03-20 11:51:39 -07008250 * Pooled class that orderes the children of a ViewGroup from start
8251 * to end based on how they are laid out and the layout direction.
8252 */
8253 static class ChildListForAccessibility {
8254
8255 private static final int MAX_POOL_SIZE = 32;
8256
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08008257 private static final SynchronizedPool<ChildListForAccessibility> sPool =
8258 new SynchronizedPool<ChildListForAccessibility>(MAX_POOL_SIZE);
Svetoslav Ganov42138042012-03-20 11:51:39 -07008259
8260 private final ArrayList<View> mChildren = new ArrayList<View>();
8261
8262 private final ArrayList<ViewLocationHolder> mHolders = new ArrayList<ViewLocationHolder>();
8263
8264 public static ChildListForAccessibility obtain(ViewGroup parent, boolean sort) {
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08008265 ChildListForAccessibility list = sPool.acquire();
8266 if (list == null) {
8267 list = new ChildListForAccessibility();
Svetoslav Ganov42138042012-03-20 11:51:39 -07008268 }
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08008269 list.init(parent, sort);
8270 return list;
Svetoslav Ganov42138042012-03-20 11:51:39 -07008271 }
8272
8273 public void recycle() {
Svetoslav Ganov42138042012-03-20 11:51:39 -07008274 clear();
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08008275 sPool.release(this);
Svetoslav Ganov42138042012-03-20 11:51:39 -07008276 }
8277
8278 public int getChildCount() {
8279 return mChildren.size();
8280 }
8281
8282 public View getChildAt(int index) {
8283 return mChildren.get(index);
8284 }
8285
Svetoslav Ganov42138042012-03-20 11:51:39 -07008286 private void init(ViewGroup parent, boolean sort) {
8287 ArrayList<View> children = mChildren;
8288 final int childCount = parent.getChildCount();
8289 for (int i = 0; i < childCount; i++) {
8290 View child = parent.getChildAt(i);
8291 children.add(child);
8292 }
8293 if (sort) {
8294 ArrayList<ViewLocationHolder> holders = mHolders;
8295 for (int i = 0; i < childCount; i++) {
8296 View child = children.get(i);
8297 ViewLocationHolder holder = ViewLocationHolder.obtain(parent, child);
8298 holders.add(holder);
8299 }
Svetoslav88e447b2014-10-09 15:49:02 -07008300 sort(holders);
Svetoslav Ganov42138042012-03-20 11:51:39 -07008301 for (int i = 0; i < childCount; i++) {
8302 ViewLocationHolder holder = holders.get(i);
8303 children.set(i, holder.mView);
8304 holder.recycle();
8305 }
8306 holders.clear();
8307 }
8308 }
8309
Svetoslav88e447b2014-10-09 15:49:02 -07008310 private void sort(ArrayList<ViewLocationHolder> holders) {
8311 // This is gross but the least risky solution. The current comparison
8312 // strategy breaks transitivity but produces very good results. Coming
8313 // up with a new strategy requires time which we do not have, so ...
8314 try {
8315 ViewLocationHolder.setComparisonStrategy(
8316 ViewLocationHolder.COMPARISON_STRATEGY_STRIPE);
8317 Collections.sort(holders);
8318 } catch (IllegalArgumentException iae) {
8319 // Note that in practice this occurs extremely rarely in a couple
8320 // of pathological cases.
8321 ViewLocationHolder.setComparisonStrategy(
8322 ViewLocationHolder.COMPARISON_STRATEGY_LOCATION);
8323 Collections.sort(holders);
8324 }
8325 }
8326
Svetoslav Ganov42138042012-03-20 11:51:39 -07008327 private void clear() {
8328 mChildren.clear();
8329 }
8330 }
8331
8332 /**
8333 * Pooled class that holds a View and its location with respect to
8334 * a specified root. This enables sorting of views based on their
8335 * coordinates without recomputing the position relative to the root
8336 * on every comparison.
8337 */
8338 static class ViewLocationHolder implements Comparable<ViewLocationHolder> {
8339
8340 private static final int MAX_POOL_SIZE = 32;
8341
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08008342 private static final SynchronizedPool<ViewLocationHolder> sPool =
8343 new SynchronizedPool<ViewLocationHolder>(MAX_POOL_SIZE);
Svetoslav Ganov42138042012-03-20 11:51:39 -07008344
Svetoslav88e447b2014-10-09 15:49:02 -07008345 public static final int COMPARISON_STRATEGY_STRIPE = 1;
8346
8347 public static final int COMPARISON_STRATEGY_LOCATION = 2;
8348
8349 private static int sComparisonStrategy = COMPARISON_STRATEGY_STRIPE;
8350
Svetoslav Ganov42138042012-03-20 11:51:39 -07008351 private final Rect mLocation = new Rect();
8352
8353 public View mView;
8354
8355 private int mLayoutDirection;
8356
8357 public static ViewLocationHolder obtain(ViewGroup root, View view) {
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08008358 ViewLocationHolder holder = sPool.acquire();
8359 if (holder == null) {
8360 holder = new ViewLocationHolder();
Svetoslav Ganov42138042012-03-20 11:51:39 -07008361 }
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08008362 holder.init(root, view);
8363 return holder;
Svetoslav Ganov42138042012-03-20 11:51:39 -07008364 }
8365
Svetoslav88e447b2014-10-09 15:49:02 -07008366 public static void setComparisonStrategy(int strategy) {
8367 sComparisonStrategy = strategy;
8368 }
8369
Svetoslav Ganov42138042012-03-20 11:51:39 -07008370 public void recycle() {
Svetoslav Ganov42138042012-03-20 11:51:39 -07008371 clear();
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08008372 sPool.release(this);
Svetoslav Ganov42138042012-03-20 11:51:39 -07008373 }
8374
8375 @Override
8376 public int compareTo(ViewLocationHolder another) {
8377 // This instance is greater than an invalid argument.
8378 if (another == null) {
8379 return 1;
8380 }
Svetoslav88e447b2014-10-09 15:49:02 -07008381
8382 if (sComparisonStrategy == COMPARISON_STRATEGY_STRIPE) {
8383 // First is above second.
8384 if (mLocation.bottom - another.mLocation.top <= 0) {
8385 return -1;
8386 }
8387 // First is below second.
8388 if (mLocation.top - another.mLocation.bottom >= 0) {
8389 return 1;
8390 }
8391 }
8392
Svetoslav04cab1b2014-08-25 18:35:57 -07008393 // We are ordering left-to-right, top-to-bottom.
Svetoslav Ganov42138042012-03-20 11:51:39 -07008394 if (mLayoutDirection == LAYOUT_DIRECTION_LTR) {
8395 final int leftDifference = mLocation.left - another.mLocation.left;
Svetoslav Ganov42138042012-03-20 11:51:39 -07008396 if (leftDifference != 0) {
8397 return leftDifference;
8398 }
8399 } else { // RTL
8400 final int rightDifference = mLocation.right - another.mLocation.right;
Svetoslav Ganov42138042012-03-20 11:51:39 -07008401 if (rightDifference != 0) {
8402 return -rightDifference;
8403 }
8404 }
Svetoslav04cab1b2014-08-25 18:35:57 -07008405 // We are ordering left-to-right, top-to-bottom.
8406 final int topDifference = mLocation.top - another.mLocation.top;
8407 if (topDifference != 0) {
8408 return topDifference;
8409 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07008410 // Break tie by height.
8411 final int heightDiference = mLocation.height() - another.mLocation.height();
8412 if (heightDiference != 0) {
8413 return -heightDiference;
8414 }
8415 // Break tie by width.
8416 final int widthDiference = mLocation.width() - another.mLocation.width();
8417 if (widthDiference != 0) {
8418 return -widthDiference;
8419 }
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07008420 // Just break the tie somehow. The accessibliity ids are unique
8421 // and stable, hence this is deterministic tie breaking.
8422 return mView.getAccessibilityViewId() - another.mView.getAccessibilityViewId();
Svetoslav Ganov42138042012-03-20 11:51:39 -07008423 }
8424
8425 private void init(ViewGroup root, View view) {
8426 Rect viewLocation = mLocation;
8427 view.getDrawingRect(viewLocation);
8428 root.offsetDescendantRectToMyCoords(view, viewLocation);
8429 mView = view;
Fabrice Di Meglioe56ffdc2012-09-23 14:51:16 -07008430 mLayoutDirection = root.getLayoutDirection();
Svetoslav Ganov42138042012-03-20 11:51:39 -07008431 }
8432
8433 private void clear() {
8434 mView = null;
8435 mLocation.set(0, 0, 0, 0);
8436 }
8437 }
Romain Guycbc67742012-04-27 16:12:57 -07008438
Romain Guy6410c0a2013-06-17 11:21:58 -07008439 private static void drawRect(Canvas canvas, Paint paint, int x1, int y1, int x2, int y2) {
Romain Guycbc67742012-04-27 16:12:57 -07008440 if (sDebugLines== null) {
Romain Guy6410c0a2013-06-17 11:21:58 -07008441 // TODO: This won't work with multiple UI threads in a single process
Romain Guycbc67742012-04-27 16:12:57 -07008442 sDebugLines = new float[16];
8443 }
8444
Romain Guycbc67742012-04-27 16:12:57 -07008445 sDebugLines[0] = x1;
8446 sDebugLines[1] = y1;
8447 sDebugLines[2] = x2;
8448 sDebugLines[3] = y1;
8449
8450 sDebugLines[4] = x2;
8451 sDebugLines[5] = y1;
8452 sDebugLines[6] = x2;
Philip Milne7b757812012-09-19 18:13:44 -07008453 sDebugLines[7] = y2;
Romain Guycbc67742012-04-27 16:12:57 -07008454
Philip Milne7b757812012-09-19 18:13:44 -07008455 sDebugLines[8] = x2;
Romain Guycbc67742012-04-27 16:12:57 -07008456 sDebugLines[9] = y2;
8457 sDebugLines[10] = x1;
8458 sDebugLines[11] = y2;
8459
Philip Milne7b757812012-09-19 18:13:44 -07008460 sDebugLines[12] = x1;
8461 sDebugLines[13] = y2;
Romain Guycbc67742012-04-27 16:12:57 -07008462 sDebugLines[14] = x1;
8463 sDebugLines[15] = y1;
8464
Philip Milne7b757812012-09-19 18:13:44 -07008465 canvas.drawLines(sDebugLines, paint);
Romain Guycbc67742012-04-27 16:12:57 -07008466 }
Siva Velusamy0d857b92015-04-22 10:23:56 -07008467
8468 /** @hide */
8469 @Override
8470 protected void encodeProperties(@NonNull ViewHierarchyEncoder encoder) {
8471 super.encodeProperties(encoder);
8472
8473 encoder.addProperty("focus:descendantFocusability", getDescendantFocusability());
8474 encoder.addProperty("drawing:clipChildren", getClipChildren());
8475 encoder.addProperty("drawing:clipToPadding", getClipToPadding());
8476 encoder.addProperty("drawing:childrenDrawingOrderEnabled", isChildrenDrawingOrderEnabled());
8477 encoder.addProperty("drawing:persistentDrawingCache", getPersistentDrawingCache());
8478
8479 int n = getChildCount();
8480 encoder.addProperty("meta:__childCount__", (short)n);
8481 for (int i = 0; i < n; i++) {
8482 encoder.addPropertyKey("meta:__child__" + i);
8483 getChildAt(i).encode(encoder);
8484 }
8485 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008486}