blob: 81ab4b6b267aa3cfbcac1e7362ea11feb3e675b7 [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;
Mathew Inwoode5ad5982018-08-17 15:07:52 +010027import android.annotation.UnsupportedAppUsage;
Vadim Trysheva61efa42016-09-28 15:15:52 -070028import android.content.ClipData;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029import android.content.Context;
Clara Bayarrid5bf3ed2015-03-27 17:32:45 +000030import android.content.Intent;
Adam Powellff0d2982014-07-10 20:34:14 -070031import android.content.pm.PackageManager;
Dianne Hackborne36d6e22010-02-17 19:46:25 -080032import android.content.res.Configuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080033import android.content.res.TypedArray;
34import android.graphics.Bitmap;
35import android.graphics.Canvas;
Philip Milne10ca24a2012-04-23 15:38:27 -070036import android.graphics.Color;
37import android.graphics.Insets;
Adam Powell6e346362010-07-23 10:18:23 -070038import android.graphics.Matrix;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import android.graphics.Paint;
Christopher Tatea53146c2010-09-07 11:57:52 -070040import android.graphics.PointF;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041import android.graphics.Rect;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042import android.graphics.RectF;
svetoslavganov75986cf2009-05-14 22:28:01 -070043import android.graphics.Region;
Jeff Brown995e7742010-12-22 16:59:36 -080044import android.os.Build;
Adam Powellb6ab0982015-01-07 17:00:12 -080045import android.os.Bundle;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046import android.os.Parcelable;
47import android.os.SystemClock;
48import android.util.AttributeSet;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049import android.util.Log;
Svet Ganov2f8fb1f2017-03-13 00:21:04 -070050import android.util.Pools;
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -080051import android.util.Pools.SynchronizedPool;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052import android.util.SparseArray;
Dianne Hackborn6ff55fc2015-08-05 18:07:31 -070053import android.util.SparseBooleanArray;
svetoslavganov75986cf2009-05-14 22:28:01 -070054import android.view.accessibility.AccessibilityEvent;
Phil Weaver4d3eec412016-09-01 16:28:34 -070055import android.view.accessibility.AccessibilityManager;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070056import android.view.accessibility.AccessibilityNodeInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080057import android.view.animation.Animation;
58import android.view.animation.AnimationUtils;
59import android.view.animation.LayoutAnimationController;
60import android.view.animation.Transformation;
Felipe Lemefe05a522018-01-23 15:57:49 -080061import android.view.autofill.Helper;
Chet Haasecb3d0232017-05-24 18:27:14 -070062
Romain Guy0211a0a2011-02-14 16:34:59 -080063import com.android.internal.R;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080064
65import java.util.ArrayList;
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -080066import java.util.Collection;
Svetoslav Ganov42138042012-03-20 11:51:39 -070067import java.util.Collections;
Christopher Tate86cab1b2011-01-13 20:28:55 -080068import java.util.HashSet;
George Mounte1803372014-02-26 19:00:52 +000069import java.util.List;
70import java.util.Map;
Paul Duffinca4964c2017-02-07 15:04:10 +000071import java.util.function.Predicate;
Keisuke Kuroyanagid85bc502016-01-21 14:50:38 +090072
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080073/**
74 * <p>
75 * A <code>ViewGroup</code> is a special view that can contain other views
76 * (called children.) The view group is the base class for layouts and views
77 * containers. This class also defines the
78 * {@link android.view.ViewGroup.LayoutParams} class which serves as the base
79 * class for layouts parameters.
80 * </p>
81 *
82 * <p>
83 * Also see {@link LayoutParams} for layout attributes.
84 * </p>
Romain Guyd6a463a2009-05-21 23:10:10 -070085 *
Joe Fernandez558459f2011-10-13 16:47:36 -070086 * <div class="special reference">
87 * <h3>Developer Guides</h3>
88 * <p>For more information about creating user interface layouts, read the
89 * <a href="{@docRoot}guide/topics/ui/declaring-layout.html">XML Layouts</a> developer
90 * guide.</p></div>
91 *
Dianne Hackborn7caab0f2013-03-06 13:47:04 -080092 * <p>Here is a complete implementation of a custom ViewGroup that implements
93 * a simple {@link android.widget.FrameLayout} along with the ability to stack
94 * children in left and right gutters.</p>
95 *
96 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/CustomLayout.java
97 * Complete}
98 *
99 * <p>If you are implementing XML layout attributes as shown in the example, this is the
100 * corresponding definition for them that would go in <code>res/values/attrs.xml</code>:</p>
101 *
102 * {@sample development/samples/ApiDemos/res/values/attrs.xml CustomLayout}
103 *
104 * <p>Finally the layout manager can be used in an XML layout like so:</p>
105 *
106 * {@sample development/samples/ApiDemos/res/layout/custom_layout.xml Complete}
107 *
Romain Guyd6a463a2009-05-21 23:10:10 -0700108 * @attr ref android.R.styleable#ViewGroup_clipChildren
109 * @attr ref android.R.styleable#ViewGroup_clipToPadding
110 * @attr ref android.R.styleable#ViewGroup_layoutAnimation
111 * @attr ref android.R.styleable#ViewGroup_animationCache
112 * @attr ref android.R.styleable#ViewGroup_persistentDrawingCache
113 * @attr ref android.R.styleable#ViewGroup_alwaysDrawnWithCache
114 * @attr ref android.R.styleable#ViewGroup_addStatesFromChildren
115 * @attr ref android.R.styleable#ViewGroup_descendantFocusability
Chet Haase13cc1202010-09-03 15:39:20 -0700116 * @attr ref android.R.styleable#ViewGroup_animateLayoutChanges
Scott Main27a85082013-06-10 10:39:48 -0700117 * @attr ref android.R.styleable#ViewGroup_splitMotionEvents
118 * @attr ref android.R.styleable#ViewGroup_layoutMode
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800119 */
Tor Norbye83c68962015-03-10 20:55:31 -0700120@UiThread
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800121public abstract class ViewGroup extends View implements ViewParent, ViewManager {
Adam Powell539ee872012-02-03 19:00:49 -0800122 private static final String TAG = "ViewGroup";
Chet Haase21cd1382010-09-01 17:42:29 -0700123
Mathew Inwoode5ad5982018-08-17 15:07:52 +0100124 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800125 private static final boolean DBG = false;
Gilles Debunnecea45132011-11-24 02:19:27 +0100126
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800127 /**
128 * Views which have been hidden or removed which need to be animated on
129 * their way out.
130 * This field should be made private, so it is hidden from the SDK.
131 * {@hide}
132 */
Mathew Inwoode5ad5982018-08-17 15:07:52 +0100133 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800134 protected ArrayList<View> mDisappearingChildren;
135
136 /**
137 * Listener used to propagate events indicating when children are added
138 * and/or removed from a view group.
139 * This field should be made private, so it is hidden from the SDK.
140 * {@hide}
141 */
Mathew Inwoode5ad5982018-08-17 15:07:52 +0100142 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800143 protected OnHierarchyChangeListener mOnHierarchyChangeListener;
144
145 // The view contained within this ViewGroup that has or contains focus.
Mathew Inwood55418ea2018-12-20 15:30:45 +0000146 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800147 private View mFocused;
Vadim Tryshev5ca73982017-01-04 17:24:43 -0800148 // The view contained within this ViewGroup (excluding nested keyboard navigation clusters)
149 // that is or contains a default-focus view.
150 private View mDefaultFocus;
Evan Rosky53fcf112017-01-26 14:37:55 -0800151 // The last child of this ViewGroup which held focus within the current cluster
Evan Rosky6c286be2017-04-19 17:23:32 -0700152 View mFocusedInCluster;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800153
Chet Haase48460322010-06-11 14:22:25 -0700154 /**
155 * A Transformation used when drawing children, to
156 * apply on the child being drawn.
157 */
Romain Guyf6991302013-06-05 17:19:01 -0700158 private Transformation mChildTransformation;
Chet Haase48460322010-06-11 14:22:25 -0700159
160 /**
161 * Used to track the current invalidation region.
162 */
Chet Haase64a48c12012-02-13 16:33:29 -0800163 RectF mInvalidateRegion;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800164
Chet Haase48460322010-06-11 14:22:25 -0700165 /**
166 * A Transformation used to calculate a correct
167 * invalidation area when the application is autoscaled.
168 */
Chet Haase64a48c12012-02-13 16:33:29 -0800169 Transformation mInvalidationTransformation;
Chet Haase48460322010-06-11 14:22:25 -0700170
Vadim Tryshevef128112016-09-16 14:05:53 -0700171 // Current frontmost child that can accept drag and lies under the drag location.
172 // Used only to generate ENTER/EXIT events for pre-Nougat aps.
173 private View mCurrentDragChild;
174
Christopher Tate86cab1b2011-01-13 20:28:55 -0800175 // Metadata about the ongoing drag
Vadim Tryshev1a68dc92015-07-20 17:01:50 -0700176 private DragEvent mCurrentDragStartEvent;
177 private boolean mIsInterestedInDrag;
178 private HashSet<View> mChildrenInterestedInDrag;
Christopher Tatea53146c2010-09-07 11:57:52 -0700179
180 // Used during drag dispatch
Romain Guy6410c0a2013-06-17 11:21:58 -0700181 private PointF mLocalPoint;
Christopher Tatea53146c2010-09-07 11:57:52 -0700182
Alan Viveretteb942b6f2014-12-08 10:37:39 -0800183 // Lazily-created holder for point computations.
184 private float[] mTempPoint;
185
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800186 // Layout animation
187 private LayoutAnimationController mLayoutAnimationController;
188 private Animation.AnimationListener mAnimationListener;
189
Jeff Brown20e987b2010-08-23 12:01:02 -0700190 // First touch target in the linked list of touch targets.
Mathew Inwoode5ad5982018-08-17 15:07:52 +0100191 @UnsupportedAppUsage
Jeff Brown20e987b2010-08-23 12:01:02 -0700192 private TouchTarget mFirstTouchTarget;
193
Joe Onorato03ab0c72011-01-06 15:46:27 -0800194 // For debugging only. You can see these in hierarchyviewer.
Romain Guye95003e2011-01-09 13:53:06 -0800195 @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
Joe Onorato03ab0c72011-01-06 15:46:27 -0800196 @ViewDebug.ExportedProperty(category = "events")
197 private long mLastTouchDownTime;
198 @ViewDebug.ExportedProperty(category = "events")
199 private int mLastTouchDownIndex = -1;
Romain Guye95003e2011-01-09 13:53:06 -0800200 @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
Joe Onorato03ab0c72011-01-06 15:46:27 -0800201 @ViewDebug.ExportedProperty(category = "events")
202 private float mLastTouchDownX;
Romain Guye95003e2011-01-09 13:53:06 -0800203 @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
Joe Onorato03ab0c72011-01-06 15:46:27 -0800204 @ViewDebug.ExportedProperty(category = "events")
205 private float mLastTouchDownY;
206
Jeff Brown87b7f802011-06-21 18:35:45 -0700207 // First hover target in the linked list of hover targets.
208 // The hover targets are children which have received ACTION_HOVER_ENTER.
209 // They might not have actually handled the hover event, but we will
210 // continue sending hover events to them as long as the pointer remains over
211 // their bounds and the view group does not intercept hover.
212 private HoverTarget mFirstHoverTarget;
Jeff Browna032cc02011-03-07 16:56:21 -0800213
Jeff Brown10b62902011-06-20 16:40:37 -0700214 // True if the view group itself received a hover event.
215 // It might not have actually handled the hover event.
216 private boolean mHoveredSelf;
217
Vladislav Kaznacheevf847ee32016-11-21 14:11:00 -0800218 // The child capable of showing a tooltip and currently under the pointer.
219 private View mTooltipHoverTarget;
220
221 // True if the view group is capable of showing a tooltip and the pointer is directly
222 // over the view group but not one of its child views.
223 private boolean mTooltipHoveredSelf;
224
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800225 /**
226 * Internal flags.
Romain Guy8506ab42009-06-11 17:35:47 -0700227 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800228 * This field should be made private, so it is hidden from the SDK.
229 * {@hide}
230 */
Romain Guy2440e672012-08-07 14:43:43 -0700231 @ViewDebug.ExportedProperty(flagMapping = {
232 @ViewDebug.FlagToString(mask = FLAG_CLIP_CHILDREN, equals = FLAG_CLIP_CHILDREN,
233 name = "CLIP_CHILDREN"),
234 @ViewDebug.FlagToString(mask = FLAG_CLIP_TO_PADDING, equals = FLAG_CLIP_TO_PADDING,
235 name = "CLIP_TO_PADDING"),
236 @ViewDebug.FlagToString(mask = FLAG_PADDING_NOT_NULL, equals = FLAG_PADDING_NOT_NULL,
237 name = "PADDING_NOT_NULL")
Jon Miranda4597e982014-07-29 07:25:49 -0700238 }, formatToHexString = true)
Mathew Inwoode5ad5982018-08-17 15:07:52 +0100239 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800240 protected int mGroupFlags;
241
Philip Milne7b757812012-09-19 18:13:44 -0700242 /**
243 * Either {@link #LAYOUT_MODE_CLIP_BOUNDS} or {@link #LAYOUT_MODE_OPTICAL_BOUNDS}.
Philip Milne1557fd72012-04-04 23:41:34 -0700244 */
Philip Milnecfb631b2012-10-26 10:51:46 -0700245 private int mLayoutMode = LAYOUT_MODE_UNDEFINED;
Philip Milne1557fd72012-04-04 23:41:34 -0700246
Romain Guy33f6beb2012-02-16 19:24:51 -0800247 /**
248 * NOTE: If you change the flags below make sure to reflect the changes
249 * the DisplayList class
250 */
Filip Gruszczynskia33bdf32015-11-19 18:22:16 -0800251
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800252 // When set, ViewGroup invalidates only the child's rectangle
253 // Set by default
Chet Haase64a48c12012-02-13 16:33:29 -0800254 static final int FLAG_CLIP_CHILDREN = 0x1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800255
256 // When set, ViewGroup excludes the padding area from the invalidate rectangle
257 // Set by default
258 private static final int FLAG_CLIP_TO_PADDING = 0x2;
259
260 // When set, dispatchDraw() will invoke invalidate(); this is set by drawChild() when
261 // a child needs to be invalidated and FLAG_OPTIMIZE_INVALIDATE is set
Chet Haase64a48c12012-02-13 16:33:29 -0800262 static final int FLAG_INVALIDATE_REQUIRED = 0x4;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800263
264 // When set, dispatchDraw() will run the layout animation and unset the flag
265 private static final int FLAG_RUN_ANIMATION = 0x8;
266
267 // When set, there is either no layout animation on the ViewGroup or the layout
268 // animation is over
269 // Set by default
Chet Haase64a48c12012-02-13 16:33:29 -0800270 static final int FLAG_ANIMATION_DONE = 0x10;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800271
272 // If set, this ViewGroup has padding; if unset there is no padding and we don't need
273 // to clip it, even if FLAG_CLIP_TO_PADDING is set
274 private static final int FLAG_PADDING_NOT_NULL = 0x20;
275
Chris Craik5a6bbae2015-04-10 17:41:34 -0700276 /** @deprecated - functionality removed */
Aurimas Liutikas514c5ef2016-05-24 15:22:55 -0700277 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800278 private static final int FLAG_ANIMATION_CACHE = 0x40;
279
280 // When set, this ViewGroup converts calls to invalidate(Rect) to invalidate() during a
281 // layout animation; this avoid clobbering the hierarchy
282 // Automatically set when the layout animation starts, depending on the animation's
283 // characteristics
Chet Haase64a48c12012-02-13 16:33:29 -0800284 static final int FLAG_OPTIMIZE_INVALIDATE = 0x80;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800285
286 // When set, the next call to drawChild() will clear mChildTransformation's matrix
Chet Haase64a48c12012-02-13 16:33:29 -0800287 static final int FLAG_CLEAR_TRANSFORMATION = 0x100;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800288
289 // When set, this ViewGroup invokes mAnimationListener.onAnimationEnd() and removes
290 // the children's Bitmap caches if necessary
291 // This flag is set when the layout animation is over (after FLAG_ANIMATION_DONE is set)
292 private static final int FLAG_NOTIFY_ANIMATION_LISTENER = 0x200;
293
294 /**
295 * When set, the drawing method will call {@link #getChildDrawingOrder(int, int)}
296 * to get the index of the child to draw for that iteration.
Filip Gruszczynskia33bdf32015-11-19 18:22:16 -0800297 *
Romain Guy293451e2009-11-04 13:59:48 -0800298 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800299 */
Mathew Inwoode5ad5982018-08-17 15:07:52 +0100300 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800301 protected static final int FLAG_USE_CHILD_DRAWING_ORDER = 0x400;
Romain Guy8506ab42009-06-11 17:35:47 -0700302
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800303 /**
304 * When set, this ViewGroup supports static transformations on children; this causes
305 * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} to be
306 * invoked when a child is drawn.
307 *
308 * Any subclass overriding
309 * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} should
310 * set this flags in {@link #mGroupFlags}.
Romain Guy8506ab42009-06-11 17:35:47 -0700311 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800312 * {@hide}
313 */
Mathew Inwoode5ad5982018-08-17 15:07:52 +0100314 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800315 protected static final int FLAG_SUPPORT_STATIC_TRANSFORMATIONS = 0x800;
316
John Reckfb5899d2014-08-15 18:51:27 -0700317 // UNUSED FLAG VALUE: 0x1000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800318
319 /**
320 * When set, this ViewGroup's drawable states also include those
321 * of its children.
322 */
323 private static final int FLAG_ADD_STATES_FROM_CHILDREN = 0x2000;
324
Chris Craik5a6bbae2015-04-10 17:41:34 -0700325 /** @deprecated functionality removed */
Aurimas Liutikas514c5ef2016-05-24 15:22:55 -0700326 @Deprecated
Chris Craik5a6bbae2015-04-10 17:41:34 -0700327 private static final int FLAG_ALWAYS_DRAWN_WITH_CACHE = 0x4000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800328
Chris Craik5a6bbae2015-04-10 17:41:34 -0700329 /** @deprecated functionality removed */
Aurimas Liutikas514c5ef2016-05-24 15:22:55 -0700330 @Deprecated
Chris Craik5a6bbae2015-04-10 17:41:34 -0700331 private static final int FLAG_CHILDREN_DRAWN_WITH_CACHE = 0x8000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800332
333 /**
334 * When set, this group will go through its list of children to notify them of
335 * any drawable state change.
336 */
337 private static final int FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE = 0x10000;
338
339 private static final int FLAG_MASK_FOCUSABILITY = 0x60000;
340
341 /**
342 * This view will get focus before any of its descendants.
343 */
344 public static final int FOCUS_BEFORE_DESCENDANTS = 0x20000;
345
346 /**
347 * This view will get focus only if none of its descendants want it.
348 */
349 public static final int FOCUS_AFTER_DESCENDANTS = 0x40000;
350
351 /**
352 * This view will block any of its descendants from getting focus, even
353 * if they are focusable.
354 */
355 public static final int FOCUS_BLOCK_DESCENDANTS = 0x60000;
356
357 /**
358 * Used to map between enum in attrubutes and flag values.
359 */
360 private static final int[] DESCENDANT_FOCUSABILITY_FLAGS =
361 {FOCUS_BEFORE_DESCENDANTS, FOCUS_AFTER_DESCENDANTS,
362 FOCUS_BLOCK_DESCENDANTS};
363
364 /**
365 * When set, this ViewGroup should not intercept touch events.
Adam Powell110486f2010-06-22 17:14:44 -0700366 * {@hide}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800367 */
Mathew Inwoode5ad5982018-08-17 15:07:52 +0100368 @UnsupportedAppUsage
Adam Powell110486f2010-06-22 17:14:44 -0700369 protected static final int FLAG_DISALLOW_INTERCEPT = 0x80000;
Romain Guy8506ab42009-06-11 17:35:47 -0700370
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800371 /**
Adam Powell2b342f02010-08-18 18:14:13 -0700372 * When set, this ViewGroup will split MotionEvents to multiple child Views when appropriate.
373 */
Adam Powellf37df072010-09-17 16:22:49 -0700374 private static final int FLAG_SPLIT_MOTION_EVENTS = 0x200000;
Adam Powell2b342f02010-08-18 18:14:13 -0700375
376 /**
Adam Powell4b867882011-09-16 12:59:46 -0700377 * When set, this ViewGroup will not dispatch onAttachedToWindow calls
378 * to children when adding new views. This is used to prevent multiple
379 * onAttached calls when a ViewGroup adds children in its own onAttached method.
380 */
381 private static final int FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW = 0x400000;
382
383 /**
Philip Milnecfb631b2012-10-26 10:51:46 -0700384 * When true, indicates that a layoutMode has been explicitly set, either with
385 * an explicit call to {@link #setLayoutMode(int)} in code or from an XML resource.
386 * This distinguishes the situation in which a layout mode was inherited from
387 * one of the ViewGroup's ancestors and cached locally.
388 */
389 private static final int FLAG_LAYOUT_MODE_WAS_EXPLICITLY_SET = 0x800000;
390
Chris Craikb49f4462014-03-20 12:44:20 -0700391 static final int FLAG_IS_TRANSITION_GROUP = 0x1000000;
Chris Craikd863a102013-12-19 13:31:15 -0800392
Chris Craikb49f4462014-03-20 12:44:20 -0700393 static final int FLAG_IS_TRANSITION_GROUP_SET = 0x2000000;
George Mount0a778ed2013-12-13 13:35:36 -0800394
Chris Craikd863a102013-12-19 13:31:15 -0800395 /**
Adam Powellff0d2982014-07-10 20:34:14 -0700396 * When set, focus will not be permitted to enter this group if a touchscreen is present.
397 */
398 static final int FLAG_TOUCHSCREEN_BLOCKS_FOCUS = 0x4000000;
399
400 /**
Clara Bayarri4423d912015-03-02 19:42:48 +0000401 * When true, indicates that a call to startActionModeForChild was made with the type parameter
402 * and should not be ignored. This helps in backwards compatibility with the existing method
403 * without a type.
404 *
405 * @see #startActionModeForChild(View, android.view.ActionMode.Callback)
406 * @see #startActionModeForChild(View, android.view.ActionMode.Callback, int)
407 */
408 private static final int FLAG_START_ACTION_MODE_FOR_CHILD_IS_TYPED = 0x8000000;
409
410 /**
411 * When true, indicates that a call to startActionModeForChild was made without the type
412 * parameter. This helps in backwards compatibility with the existing method
413 * without a type.
414 *
415 * @see #startActionModeForChild(View, android.view.ActionMode.Callback)
416 * @see #startActionModeForChild(View, android.view.ActionMode.Callback, int)
417 */
418 private static final int FLAG_START_ACTION_MODE_FOR_CHILD_IS_NOT_TYPED = 0x10000000;
419
420 /**
Adam Powell2af189a2016-02-05 15:52:02 -0800421 * When set, indicates that a call to showContextMenuForChild was made with explicit
422 * coordinates within the initiating child view.
423 */
424 private static final int FLAG_SHOW_CONTEXT_MENU_WITH_COORDS = 0x20000000;
425
426 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800427 * Indicates which types of drawing caches are to be kept in memory.
428 * This field should be made private, so it is hidden from the SDK.
429 * {@hide}
430 */
Mathew Inwoode5ad5982018-08-17 15:07:52 +0100431 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800432 protected int mPersistentDrawingCache;
433
434 /**
435 * Used to indicate that no drawing cache should be kept in memory.
John Reck949cfe12017-10-09 13:27:03 -0700436 *
437 * @deprecated The view drawing cache was largely made obsolete with the introduction of
438 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache
439 * layers are largely unnecessary and can easily result in a net loss in performance due to the
440 * cost of creating and updating the layer. In the rare cases where caching layers are useful,
441 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware
442 * rendering. For software-rendered snapshots of a small part of the View hierarchy or
443 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or
444 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these
445 * software-rendered usages are discouraged and have compatibility issues with hardware-only
446 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE}
447 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback
448 * reports or unit testing the {@link PixelCopy} API is recommended.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800449 */
John Reck949cfe12017-10-09 13:27:03 -0700450 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800451 public static final int PERSISTENT_NO_CACHE = 0x0;
452
453 /**
454 * Used to indicate that the animation drawing cache should be kept in memory.
John Reck949cfe12017-10-09 13:27:03 -0700455 *
456 * @deprecated The view drawing cache was largely made obsolete with the introduction of
457 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache
458 * layers are largely unnecessary and can easily result in a net loss in performance due to the
459 * cost of creating and updating the layer. In the rare cases where caching layers are useful,
460 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware
461 * rendering. For software-rendered snapshots of a small part of the View hierarchy or
462 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or
463 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these
464 * software-rendered usages are discouraged and have compatibility issues with hardware-only
465 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE}
466 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback
467 * reports or unit testing the {@link PixelCopy} API is recommended.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800468 */
John Reck949cfe12017-10-09 13:27:03 -0700469 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800470 public static final int PERSISTENT_ANIMATION_CACHE = 0x1;
471
472 /**
473 * Used to indicate that the scrolling drawing cache should be kept in memory.
John Reck949cfe12017-10-09 13:27:03 -0700474 *
475 * @deprecated The view drawing cache was largely made obsolete with the introduction of
476 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache
477 * layers are largely unnecessary and can easily result in a net loss in performance due to the
478 * cost of creating and updating the layer. In the rare cases where caching layers are useful,
479 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware
480 * rendering. For software-rendered snapshots of a small part of the View hierarchy or
481 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or
482 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these
483 * software-rendered usages are discouraged and have compatibility issues with hardware-only
484 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE}
485 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback
486 * reports or unit testing the {@link PixelCopy} API is recommended.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800487 */
John Reck949cfe12017-10-09 13:27:03 -0700488 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800489 public static final int PERSISTENT_SCROLLING_CACHE = 0x2;
490
491 /**
492 * Used to indicate that all drawing caches should be kept in memory.
John Reck949cfe12017-10-09 13:27:03 -0700493 *
494 * @deprecated The view drawing cache was largely made obsolete with the introduction of
495 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache
496 * layers are largely unnecessary and can easily result in a net loss in performance due to the
497 * cost of creating and updating the layer. In the rare cases where caching layers are useful,
498 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware
499 * rendering. For software-rendered snapshots of a small part of the View hierarchy or
500 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or
501 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these
502 * software-rendered usages are discouraged and have compatibility issues with hardware-only
503 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE}
504 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback
505 * reports or unit testing the {@link PixelCopy} API is recommended.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800506 */
John Reck949cfe12017-10-09 13:27:03 -0700507 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800508 public static final int PERSISTENT_ALL_CACHES = 0x3;
509
Philip Milne1557fd72012-04-04 23:41:34 -0700510 // Layout Modes
511
Philip Milnecfb631b2012-10-26 10:51:46 -0700512 private static final int LAYOUT_MODE_UNDEFINED = -1;
513
Philip Milne1557fd72012-04-04 23:41:34 -0700514 /**
515 * This constant is a {@link #setLayoutMode(int) layoutMode}.
Philip Milne7a23b492012-04-24 22:12:36 -0700516 * Clip bounds are the raw values of {@link #getLeft() left}, {@link #getTop() top},
Philip Milne1557fd72012-04-04 23:41:34 -0700517 * {@link #getRight() right} and {@link #getBottom() bottom}.
518 */
Philip Milne7b757812012-09-19 18:13:44 -0700519 public static final int LAYOUT_MODE_CLIP_BOUNDS = 0;
Philip Milne1557fd72012-04-04 23:41:34 -0700520
521 /**
522 * This constant is a {@link #setLayoutMode(int) layoutMode}.
Philip Milne7a23b492012-04-24 22:12:36 -0700523 * Optical bounds describe where a widget appears to be. They sit inside the clip
524 * bounds which need to cover a larger area to allow other effects,
525 * such as shadows and glows, to be drawn.
Philip Milne1557fd72012-04-04 23:41:34 -0700526 */
Philip Milne7b757812012-09-19 18:13:44 -0700527 public static final int LAYOUT_MODE_OPTICAL_BOUNDS = 1;
528
529 /** @hide */
Philip Milnecfb631b2012-10-26 10:51:46 -0700530 public static int LAYOUT_MODE_DEFAULT = LAYOUT_MODE_CLIP_BOUNDS;
Philip Milne1557fd72012-04-04 23:41:34 -0700531
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800532 /**
533 * We clip to padding when FLAG_CLIP_TO_PADDING and FLAG_PADDING_NOT_NULL
534 * are set at the same time.
535 */
536 protected static final int CLIP_TO_PADDING_MASK = FLAG_CLIP_TO_PADDING | FLAG_PADDING_NOT_NULL;
537
538 // Index of the child's left position in the mLocation array
539 private static final int CHILD_LEFT_INDEX = 0;
540 // Index of the child's top position in the mLocation array
541 private static final int CHILD_TOP_INDEX = 1;
542
543 // Child views of this ViewGroup
Mathew Inwoode5ad5982018-08-17 15:07:52 +0100544 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800545 private View[] mChildren;
546 // Number of valid children in the mChildren array, the rest should be null or not
547 // considered as children
Mathew Inwoode5ad5982018-08-17 15:07:52 +0100548 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800549 private int mChildrenCount;
550
Chet Haaseb9895022013-04-02 15:10:58 -0700551 // Whether layout calls are currently being suppressed, controlled by calls to
552 // suppressLayout()
553 boolean mSuppressLayout = false;
554
555 // Whether any layout calls have actually been suppressed while mSuppressLayout
556 // has been true. This tracks whether we need to issue a requestLayout() when
557 // layout is later re-enabled.
558 private boolean mLayoutCalledWhileSuppressed = false;
559
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800560 private static final int ARRAY_INITIAL_CAPACITY = 12;
561 private static final int ARRAY_CAPACITY_INCREMENT = 12;
562
Romain Guycbc67742012-04-27 16:12:57 -0700563 private static float[] sDebugLines;
Philip Milne604f4402012-04-24 19:27:11 -0700564
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800565 // Used to draw cached views
Chet Haase64a48c12012-02-13 16:33:29 -0800566 Paint mCachePaint;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800567
Chet Haase21cd1382010-09-01 17:42:29 -0700568 // Used to animate add/remove changes in layout
569 private LayoutTransition mTransition;
570
571 // The set of views that are currently being transitioned. This list is used to track views
572 // being removed that should not actually be removed from the parent yet because they are
573 // being animated.
574 private ArrayList<View> mTransitioningViews;
575
Chet Haase5e25c2c2010-09-16 11:15:56 -0700576 // List of children changing visibility. This is used to potentially keep rendering
577 // views during a transition when they otherwise would have become gone/invisible
578 private ArrayList<View> mVisibilityChangingChildren;
579
Chris Craikab008f02014-05-23 17:55:03 -0700580 // Temporary holder of presorted children, only used for
581 // input/software draw dispatch for correctly Z ordering.
582 private ArrayList<View> mPreSortedChildren;
583
Adam Powell539ee872012-02-03 19:00:49 -0800584 // Indicates how many of this container's child subtrees contain transient state
585 @ViewDebug.ExportedProperty(category = "layout")
586 private int mChildCountWithTransientState = 0;
587
Adam Powell10ba2772014-04-15 09:46:51 -0700588 /**
589 * Currently registered axes for nested scrolling. Flag set consisting of
590 * {@link #SCROLL_AXIS_HORIZONTAL} {@link #SCROLL_AXIS_VERTICAL} or {@link #SCROLL_AXIS_NONE}
591 * for null.
592 */
593 private int mNestedScrollAxes;
594
Chet Haasec633d2f2015-04-07 10:29:39 -0700595 // Used to manage the list of transient views, added by addTransientView()
596 private List<Integer> mTransientIndices = null;
597 private List<View> mTransientViews = null;
598
Evan Rosky4807ae22018-03-22 16:04:15 -0700599 /**
600 * Keeps track of how many child views have UnhandledKeyEventListeners. This should only be
601 * updated on the UI thread so shouldn't require explicit synchronization.
602 */
603 int mChildUnhandledKeyListeners = 0;
Chet Haasec633d2f2015-04-07 10:29:39 -0700604
Clara Bayarri4423d912015-03-02 19:42:48 +0000605 /**
606 * Empty ActionMode used as a sentinel in recursive entries to startActionModeForChild.
607 *
608 * @see #startActionModeForChild(View, android.view.ActionMode.Callback)
609 * @see #startActionModeForChild(View, android.view.ActionMode.Callback, int)
610 */
611 private static final ActionMode SENTINEL_ACTION_MODE = new ActionMode() {
612 @Override
613 public void setTitle(CharSequence title) {}
614
615 @Override
616 public void setTitle(int resId) {}
617
618 @Override
619 public void setSubtitle(CharSequence subtitle) {}
620
621 @Override
622 public void setSubtitle(int resId) {}
623
624 @Override
625 public void setCustomView(View view) {}
626
627 @Override
628 public void invalidate() {}
629
630 @Override
631 public void finish() {}
632
633 @Override
634 public Menu getMenu() {
635 return null;
636 }
637
638 @Override
639 public CharSequence getTitle() {
640 return null;
641 }
642
643 @Override
644 public CharSequence getSubtitle() {
645 return null;
646 }
647
648 @Override
649 public View getCustomView() {
650 return null;
651 }
652
653 @Override
654 public MenuInflater getMenuInflater() {
655 return null;
656 }
657 };
658
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800659 public ViewGroup(Context context) {
Alan Viveretted6479ec2013-09-10 17:03:02 -0700660 this(context, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800661 }
662
663 public ViewGroup(Context context, AttributeSet attrs) {
Alan Viveretted6479ec2013-09-10 17:03:02 -0700664 this(context, attrs, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800665 }
666
Alan Viverette617feb92013-09-09 18:09:13 -0700667 public ViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {
Alan Viveretted6479ec2013-09-10 17:03:02 -0700668 this(context, attrs, defStyleAttr, 0);
Alan Viverette617feb92013-09-09 18:09:13 -0700669 }
670
671 public ViewGroup(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
672 super(context, attrs, defStyleAttr, defStyleRes);
Felipe Lemed04a6972017-03-02 12:56:18 -0800673
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800674 initViewGroup();
Alan Viveretted6479ec2013-09-10 17:03:02 -0700675 initFromAttributes(context, attrs, defStyleAttr, defStyleRes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800676 }
677
678 private void initViewGroup() {
679 // ViewGroup doesn't draw by default
Philip Milne10ca24a2012-04-23 15:38:27 -0700680 if (!debugDraw()) {
681 setFlags(WILL_NOT_DRAW, DRAW_MASK);
682 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800683 mGroupFlags |= FLAG_CLIP_CHILDREN;
684 mGroupFlags |= FLAG_CLIP_TO_PADDING;
685 mGroupFlags |= FLAG_ANIMATION_DONE;
Chris Craikf6ce8fd2015-05-11 15:33:11 -0700686 mGroupFlags |= FLAG_ANIMATION_CACHE;
687 mGroupFlags |= FLAG_ALWAYS_DRAWN_WITH_CACHE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800688
Jeff Brown995e7742010-12-22 16:59:36 -0800689 if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB) {
690 mGroupFlags |= FLAG_SPLIT_MOTION_EVENTS;
691 }
692
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800693 setDescendantFocusability(FOCUS_BEFORE_DESCENDANTS);
694
695 mChildren = new View[ARRAY_INITIAL_CAPACITY];
696 mChildrenCount = 0;
697
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800698 mPersistentDrawingCache = PERSISTENT_SCROLLING_CACHE;
699 }
700
Alan Viveretted6479ec2013-09-10 17:03:02 -0700701 private void initFromAttributes(
702 Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
Filip Gruszczyńskib50cea02014-03-05 17:54:58 -0800703 final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ViewGroup, defStyleAttr,
704 defStyleRes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800705
706 final int N = a.getIndexCount();
707 for (int i = 0; i < N; i++) {
708 int attr = a.getIndex(i);
709 switch (attr) {
710 case R.styleable.ViewGroup_clipChildren:
711 setClipChildren(a.getBoolean(attr, true));
712 break;
713 case R.styleable.ViewGroup_clipToPadding:
714 setClipToPadding(a.getBoolean(attr, true));
715 break;
716 case R.styleable.ViewGroup_animationCache:
717 setAnimationCacheEnabled(a.getBoolean(attr, true));
718 break;
719 case R.styleable.ViewGroup_persistentDrawingCache:
720 setPersistentDrawingCache(a.getInt(attr, PERSISTENT_SCROLLING_CACHE));
721 break;
722 case R.styleable.ViewGroup_addStatesFromChildren:
723 setAddStatesFromChildren(a.getBoolean(attr, false));
724 break;
725 case R.styleable.ViewGroup_alwaysDrawnWithCache:
726 setAlwaysDrawnWithCacheEnabled(a.getBoolean(attr, true));
727 break;
728 case R.styleable.ViewGroup_layoutAnimation:
729 int id = a.getResourceId(attr, -1);
730 if (id > 0) {
731 setLayoutAnimation(AnimationUtils.loadLayoutAnimation(mContext, id));
732 }
733 break;
734 case R.styleable.ViewGroup_descendantFocusability:
735 setDescendantFocusability(DESCENDANT_FOCUSABILITY_FLAGS[a.getInt(attr, 0)]);
736 break;
Adam Powell2b342f02010-08-18 18:14:13 -0700737 case R.styleable.ViewGroup_splitMotionEvents:
738 setMotionEventSplittingEnabled(a.getBoolean(attr, false));
739 break;
Chet Haase13cc1202010-09-03 15:39:20 -0700740 case R.styleable.ViewGroup_animateLayoutChanges:
741 boolean animateLayoutChanges = a.getBoolean(attr, false);
742 if (animateLayoutChanges) {
743 setLayoutTransition(new LayoutTransition());
744 }
745 break;
Philip Milne7b757812012-09-19 18:13:44 -0700746 case R.styleable.ViewGroup_layoutMode:
Philip Milnecfb631b2012-10-26 10:51:46 -0700747 setLayoutMode(a.getInt(attr, LAYOUT_MODE_UNDEFINED));
Philip Milne7b757812012-09-19 18:13:44 -0700748 break;
George Mount0a778ed2013-12-13 13:35:36 -0800749 case R.styleable.ViewGroup_transitionGroup:
750 setTransitionGroup(a.getBoolean(attr, false));
751 break;
Adam Powellff0d2982014-07-10 20:34:14 -0700752 case R.styleable.ViewGroup_touchscreenBlocksFocus:
753 setTouchscreenBlocksFocus(a.getBoolean(attr, false));
754 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800755 }
756 }
757
758 a.recycle();
759 }
760
761 /**
762 * Gets the descendant focusability of this view group. The descendant
763 * focusability defines the relationship between this view group and its
764 * descendants when looking for a view to take focus in
765 * {@link #requestFocus(int, android.graphics.Rect)}.
766 *
767 * @return one of {@link #FOCUS_BEFORE_DESCENDANTS}, {@link #FOCUS_AFTER_DESCENDANTS},
768 * {@link #FOCUS_BLOCK_DESCENDANTS}.
769 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -0700770 @ViewDebug.ExportedProperty(category = "focus", mapping = {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800771 @ViewDebug.IntToString(from = FOCUS_BEFORE_DESCENDANTS, to = "FOCUS_BEFORE_DESCENDANTS"),
772 @ViewDebug.IntToString(from = FOCUS_AFTER_DESCENDANTS, to = "FOCUS_AFTER_DESCENDANTS"),
773 @ViewDebug.IntToString(from = FOCUS_BLOCK_DESCENDANTS, to = "FOCUS_BLOCK_DESCENDANTS")
774 })
775 public int getDescendantFocusability() {
776 return mGroupFlags & FLAG_MASK_FOCUSABILITY;
777 }
778
779 /**
780 * Set the descendant focusability of this view group. This defines the relationship
781 * between this view group and its descendants when looking for a view to
782 * take focus in {@link #requestFocus(int, android.graphics.Rect)}.
783 *
784 * @param focusability one of {@link #FOCUS_BEFORE_DESCENDANTS}, {@link #FOCUS_AFTER_DESCENDANTS},
785 * {@link #FOCUS_BLOCK_DESCENDANTS}.
786 */
787 public void setDescendantFocusability(int focusability) {
788 switch (focusability) {
789 case FOCUS_BEFORE_DESCENDANTS:
790 case FOCUS_AFTER_DESCENDANTS:
791 case FOCUS_BLOCK_DESCENDANTS:
792 break;
793 default:
794 throw new IllegalArgumentException("must be one of FOCUS_BEFORE_DESCENDANTS, "
795 + "FOCUS_AFTER_DESCENDANTS, FOCUS_BLOCK_DESCENDANTS");
796 }
797 mGroupFlags &= ~FLAG_MASK_FOCUSABILITY;
798 mGroupFlags |= (focusability & FLAG_MASK_FOCUSABILITY);
799 }
800
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800801 @Override
802 void handleFocusGainInternal(int direction, Rect previouslyFocusedRect) {
803 if (mFocused != null) {
Alan Viverette223622a2013-12-17 13:29:02 -0800804 mFocused.unFocus(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800805 mFocused = null;
Evan Rosky53fcf112017-01-26 14:37:55 -0800806 mFocusedInCluster = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800807 }
808 super.handleFocusGainInternal(direction, previouslyFocusedRect);
809 }
810
Alan Viverettebe463f22016-01-21 10:50:10 -0500811 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800812 public void requestChildFocus(View child, View focused) {
813 if (DBG) {
814 System.out.println(this + " requestChildFocus()");
815 }
816 if (getDescendantFocusability() == FOCUS_BLOCK_DESCENDANTS) {
817 return;
818 }
819
820 // Unfocus us, if necessary
Alan Viverette223622a2013-12-17 13:29:02 -0800821 super.unFocus(focused);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800822
823 // We had a previous notion of who had focus. Clear it.
824 if (mFocused != child) {
825 if (mFocused != null) {
Alan Viverette223622a2013-12-17 13:29:02 -0800826 mFocused.unFocus(focused);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800827 }
828
829 mFocused = child;
830 }
831 if (mParent != null) {
832 mParent.requestChildFocus(this, focused);
833 }
834 }
835
Vadim Tryshev5ca73982017-01-04 17:24:43 -0800836 void setDefaultFocus(View child) {
Evan Rosky53fcf112017-01-26 14:37:55 -0800837 // Stop at any higher view which is explicitly focused-by-default
838 if (mDefaultFocus != null && mDefaultFocus.isFocusedByDefault()) {
Vadim Tryshev5ca73982017-01-04 17:24:43 -0800839 return;
Vadim Tryshev01d8c492016-12-15 11:33:15 -0800840 }
Vadim Tryshev5ca73982017-01-04 17:24:43 -0800841
842 mDefaultFocus = child;
843
844 if (mParent instanceof ViewGroup) {
845 ((ViewGroup) mParent).setDefaultFocus(this);
846 }
847 }
848
849 /**
Evan Rosky53fcf112017-01-26 14:37:55 -0800850 * Clears the default-focus chain from {@param child} up to the first parent which has another
851 * default-focusable branch below it or until there is no default-focus chain.
852 *
853 * @param child
Vadim Tryshev5ca73982017-01-04 17:24:43 -0800854 */
Evan Rosky53fcf112017-01-26 14:37:55 -0800855 void clearDefaultFocus(View child) {
856 // Stop at any higher view which is explicitly focused-by-default
857 if (mDefaultFocus != child && mDefaultFocus != null
858 && mDefaultFocus.isFocusedByDefault()) {
859 return;
860 }
861
862 mDefaultFocus = null;
863
864 // Search child siblings for default focusables.
865 for (int i = 0; i < mChildrenCount; ++i) {
866 View sibling = mChildren[i];
867 if (sibling.isFocusedByDefault()) {
868 mDefaultFocus = sibling;
869 return;
870 } else if (mDefaultFocus == null && sibling.hasDefaultFocus()) {
871 mDefaultFocus = sibling;
872 }
873 }
874
875 if (mParent instanceof ViewGroup) {
876 ((ViewGroup) mParent).clearDefaultFocus(this);
877 }
878 }
879
880 @Override
881 boolean hasDefaultFocus() {
882 return mDefaultFocus != null || super.hasDefaultFocus();
883 }
884
Evan Rosky0e8a6832017-04-10 12:35:15 -0700885 /**
886 * Removes {@code child} (and associated focusedInCluster chain) from the cluster containing
887 * it.
888 * <br>
889 * This is intended to be run on {@code child}'s immediate parent. This is necessary because
890 * the chain is sometimes cleared after {@code child} has been detached.
891 */
892 void clearFocusedInCluster(View child) {
Evan Rosky53fcf112017-01-26 14:37:55 -0800893 if (mFocusedInCluster != child) {
Vadim Tryshev5ca73982017-01-04 17:24:43 -0800894 return;
895 }
Evan Rosky5b20e092017-07-13 18:04:39 -0700896 clearFocusedInCluster();
897 }
898
899 /**
900 * Removes the focusedInCluster chain from this up to the cluster containing it.
901 */
902 void clearFocusedInCluster() {
Evan Rosky0e8a6832017-04-10 12:35:15 -0700903 View top = findKeyboardNavigationCluster();
904 ViewParent parent = this;
905 do {
906 ((ViewGroup) parent).mFocusedInCluster = null;
Evan Rosky6c286be2017-04-19 17:23:32 -0700907 if (parent == top) {
908 break;
909 }
Evan Rosky0e8a6832017-04-10 12:35:15 -0700910 parent = parent.getParent();
Evan Rosky6c286be2017-04-19 17:23:32 -0700911 } while (parent instanceof ViewGroup);
Vadim Tryshev5ca73982017-01-04 17:24:43 -0800912 }
913
914 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800915 public void focusableViewAvailable(View v) {
916 if (mParent != null
917 // shortcut: don't report a new focusable view if we block our descendants from
Evan Rosky2ae1bf52017-05-11 11:18:45 -0700918 // getting focus or if we're not visible
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800919 && (getDescendantFocusability() != FOCUS_BLOCK_DESCENDANTS)
Evan Rosky2ae1bf52017-05-11 11:18:45 -0700920 && ((mViewFlags & VISIBILITY_MASK) == VISIBLE)
Adam Powell88c11752014-07-21 17:19:16 -0700921 && (isFocusableInTouchMode() || !shouldBlockFocusForTouchscreen())
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800922 // shortcut: don't report a new focusable view if we already are focused
923 // (and we don't prefer our descendants)
924 //
925 // note: knowing that mFocused is non-null is not a good enough reason
926 // to break the traversal since in that case we'd actually have to find
927 // the focused view and make sure it wasn't FOCUS_AFTER_DESCENDANTS and
Joe Onoratoc6cc0f82011-04-12 11:53:13 -0700928 // an ancestor of v; this will get checked for at ViewAncestor
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800929 && !(isFocused() && getDescendantFocusability() != FOCUS_AFTER_DESCENDANTS)) {
930 mParent.focusableViewAvailable(v);
931 }
932 }
933
Alan Viverettebe463f22016-01-21 10:50:10 -0500934 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800935 public boolean showContextMenuForChild(View originalView) {
Adam Powell2af189a2016-02-05 15:52:02 -0800936 if (isShowingContextMenuWithCoords()) {
937 // We're being called for compatibility. Return false and let the version
938 // with coordinates recurse up.
939 return false;
940 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800941 return mParent != null && mParent.showContextMenuForChild(originalView);
942 }
943
Adam Powell2af189a2016-02-05 15:52:02 -0800944 /**
945 * @hide used internally for compatibility with existing app code only
946 */
947 public final boolean isShowingContextMenuWithCoords() {
948 return (mGroupFlags & FLAG_SHOW_CONTEXT_MENU_WITH_COORDS) != 0;
949 }
950
Oren Blasberged391262015-09-01 12:12:51 -0700951 @Override
952 public boolean showContextMenuForChild(View originalView, float x, float y) {
Adam Powell2af189a2016-02-05 15:52:02 -0800953 try {
954 mGroupFlags |= FLAG_SHOW_CONTEXT_MENU_WITH_COORDS;
955 if (showContextMenuForChild(originalView)) {
956 return true;
957 }
958 } finally {
959 mGroupFlags &= ~FLAG_SHOW_CONTEXT_MENU_WITH_COORDS;
960 }
Oren Blasberged391262015-09-01 12:12:51 -0700961 return mParent != null && mParent.showContextMenuForChild(originalView, x, y);
962 }
963
Clara Bayarri4423d912015-03-02 19:42:48 +0000964 @Override
Adam Powell6e346362010-07-23 10:18:23 -0700965 public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback) {
Clara Bayarri4423d912015-03-02 19:42:48 +0000966 if ((mGroupFlags & FLAG_START_ACTION_MODE_FOR_CHILD_IS_TYPED) == 0) {
967 // This is the original call.
968 try {
969 mGroupFlags |= FLAG_START_ACTION_MODE_FOR_CHILD_IS_NOT_TYPED;
970 return startActionModeForChild(originalView, callback, ActionMode.TYPE_PRIMARY);
971 } finally {
972 mGroupFlags &= ~FLAG_START_ACTION_MODE_FOR_CHILD_IS_NOT_TYPED;
973 }
974 } else {
975 // We are being called from the new method with type.
976 return SENTINEL_ACTION_MODE;
977 }
978 }
979
Clara Bayarri4423d912015-03-02 19:42:48 +0000980 @Override
981 public ActionMode startActionModeForChild(
982 View originalView, ActionMode.Callback callback, int type) {
Adam Powelle9fd6d22015-06-01 11:26:32 -0700983 if ((mGroupFlags & FLAG_START_ACTION_MODE_FOR_CHILD_IS_NOT_TYPED) == 0
984 && type == ActionMode.TYPE_PRIMARY) {
Clara Bayarri4423d912015-03-02 19:42:48 +0000985 ActionMode mode;
986 try {
987 mGroupFlags |= FLAG_START_ACTION_MODE_FOR_CHILD_IS_TYPED;
988 mode = startActionModeForChild(originalView, callback);
989 } finally {
990 mGroupFlags &= ~FLAG_START_ACTION_MODE_FOR_CHILD_IS_TYPED;
991 }
992 if (mode != SENTINEL_ACTION_MODE) {
993 return mode;
994 }
995 }
996 if (mParent != null) {
997 try {
998 return mParent.startActionModeForChild(originalView, callback, type);
999 } catch (AbstractMethodError ame) {
1000 // Custom view parents might not implement this method.
1001 return mParent.startActionModeForChild(originalView, callback);
1002 }
1003 }
1004 return null;
Adam Powell6e346362010-07-23 10:18:23 -07001005 }
1006
1007 /**
Clara Bayarrid5bf3ed2015-03-27 17:32:45 +00001008 * @hide
1009 */
1010 @Override
1011 public boolean dispatchActivityResult(
1012 String who, int requestCode, int resultCode, Intent data) {
1013 if (super.dispatchActivityResult(who, requestCode, resultCode, data)) {
1014 return true;
1015 }
1016 int childCount = getChildCount();
1017 for (int i = 0; i < childCount; i++) {
1018 View child = getChildAt(i);
1019 if (child.dispatchActivityResult(who, requestCode, resultCode, data)) {
1020 return true;
1021 }
1022 }
1023 return false;
1024 }
1025
1026 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001027 * Find the nearest view in the specified direction that wants to take
1028 * focus.
1029 *
1030 * @param focused The view that currently has focus
1031 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and
1032 * FOCUS_RIGHT, or 0 for not applicable.
1033 */
Alan Viverettebe463f22016-01-21 10:50:10 -05001034 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001035 public View focusSearch(View focused, int direction) {
Vadim Tryshevb5ced222017-01-17 19:31:35 -08001036 if (isRootNamespace()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001037 // root namespace means we should consider ourselves the top of the
1038 // tree for focus searching; otherwise we could be focus searching
Vadim Tryshev418b1fc2016-11-28 18:26:24 -08001039 // into other tabs. see LocalActivityManager and TabHost for more info.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001040 return FocusFinder.getInstance().findNextFocus(this, focused, direction);
1041 } else if (mParent != null) {
1042 return mParent.focusSearch(focused, direction);
1043 }
1044 return null;
1045 }
1046
Alan Viverettebe463f22016-01-21 10:50:10 -05001047 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001048 public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
1049 return false;
1050 }
1051
Svetoslav Ganov42138042012-03-20 11:51:39 -07001052 @Override
Svetoslav Ganov736c2752011-04-22 18:30:36 -07001053 public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07001054 ViewParent parent = mParent;
Svetoslav Ganov736c2752011-04-22 18:30:36 -07001055 if (parent == null) {
1056 return false;
1057 }
1058 final boolean propagate = onRequestSendAccessibilityEvent(child, event);
1059 if (!propagate) {
1060 return false;
1061 }
1062 return parent.requestSendAccessibilityEvent(this, event);
1063 }
1064
1065 /**
1066 * Called when a child has requested sending an {@link AccessibilityEvent} and
1067 * gives an opportunity to its parent to augment the event.
Svetoslav Ganov031d9c12011-09-09 16:41:13 -07001068 * <p>
Adam Powell2fcbbd02011-09-28 18:56:43 -07001069 * If an {@link android.view.View.AccessibilityDelegate} has been specified via calling
1070 * {@link android.view.View#setAccessibilityDelegate(android.view.View.AccessibilityDelegate)} its
1071 * {@link android.view.View.AccessibilityDelegate#onRequestSendAccessibilityEvent(ViewGroup, View, AccessibilityEvent)}
Svetoslav Ganov031d9c12011-09-09 16:41:13 -07001072 * is responsible for handling this call.
1073 * </p>
Svetoslav Ganov736c2752011-04-22 18:30:36 -07001074 *
1075 * @param child The child which requests sending the event.
1076 * @param event The event to be sent.
1077 * @return True if the event should be sent.
1078 *
1079 * @see #requestSendAccessibilityEvent(View, AccessibilityEvent)
1080 */
1081 public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
Svetoslav Ganov031d9c12011-09-09 16:41:13 -07001082 if (mAccessibilityDelegate != null) {
1083 return mAccessibilityDelegate.onRequestSendAccessibilityEvent(this, child, event);
1084 } else {
1085 return onRequestSendAccessibilityEventInternal(child, event);
1086 }
1087 }
1088
1089 /**
1090 * @see #onRequestSendAccessibilityEvent(View, AccessibilityEvent)
1091 *
1092 * Note: Called from the default {@link View.AccessibilityDelegate}.
Alan Viverettea54956a2015-01-07 16:05:02 -08001093 *
1094 * @hide
Svetoslav Ganov031d9c12011-09-09 16:41:13 -07001095 */
Alan Viverettea54956a2015-01-07 16:05:02 -08001096 public boolean onRequestSendAccessibilityEventInternal(View child, AccessibilityEvent event) {
Svetoslav Ganov736c2752011-04-22 18:30:36 -07001097 return true;
1098 }
1099
1100 /**
Adam Powell539ee872012-02-03 19:00:49 -08001101 * Called when a child view has changed whether or not it is tracking transient state.
Adam Powell539ee872012-02-03 19:00:49 -08001102 */
Alan Viverettebe463f22016-01-21 10:50:10 -05001103 @Override
Adam Powell539ee872012-02-03 19:00:49 -08001104 public void childHasTransientStateChanged(View child, boolean childHasTransientState) {
1105 final boolean oldHasTransientState = hasTransientState();
1106 if (childHasTransientState) {
1107 mChildCountWithTransientState++;
1108 } else {
1109 mChildCountWithTransientState--;
1110 }
1111
1112 final boolean newHasTransientState = hasTransientState();
1113 if (mParent != null && oldHasTransientState != newHasTransientState) {
1114 try {
1115 mParent.childHasTransientStateChanged(this, newHasTransientState);
1116 } catch (AbstractMethodError e) {
1117 Log.e(TAG, mParent.getClass().getSimpleName() +
1118 " does not fully implement ViewParent", e);
1119 }
1120 }
1121 }
1122
Adam Powell539ee872012-02-03 19:00:49 -08001123 @Override
1124 public boolean hasTransientState() {
1125 return mChildCountWithTransientState > 0 || super.hasTransientState();
1126 }
1127
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001128 @Override
1129 public boolean dispatchUnhandledMove(View focused, int direction) {
1130 return mFocused != null &&
1131 mFocused.dispatchUnhandledMove(focused, direction);
1132 }
1133
Alan Viverettebe463f22016-01-21 10:50:10 -05001134 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001135 public void clearChildFocus(View child) {
1136 if (DBG) {
1137 System.out.println(this + " clearChildFocus()");
1138 }
1139
1140 mFocused = null;
1141 if (mParent != null) {
1142 mParent.clearChildFocus(this);
1143 }
1144 }
1145
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001146 @Override
1147 public void clearFocus() {
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08001148 if (DBG) {
1149 System.out.println(this + " clearFocus()");
1150 }
1151 if (mFocused == null) {
1152 super.clearFocus();
1153 } else {
Svetoslav Ganovb552d892012-06-02 14:35:02 -07001154 View focused = mFocused;
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08001155 mFocused = null;
Svetoslav Ganovb552d892012-06-02 14:35:02 -07001156 focused.clearFocus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001157 }
1158 }
1159
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001160 @Override
Alan Viverette223622a2013-12-17 13:29:02 -08001161 void unFocus(View focused) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001162 if (DBG) {
1163 System.out.println(this + " unFocus()");
1164 }
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08001165 if (mFocused == null) {
Alan Viverette223622a2013-12-17 13:29:02 -08001166 super.unFocus(focused);
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08001167 } else {
Alan Viverette223622a2013-12-17 13:29:02 -08001168 mFocused.unFocus(focused);
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08001169 mFocused = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001170 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001171 }
1172
1173 /**
1174 * Returns the focused child of this view, if any. The child may have focus
1175 * or contain focus.
1176 *
1177 * @return the focused child or null.
1178 */
1179 public View getFocusedChild() {
1180 return mFocused;
1181 }
1182
Adam Powell88c11752014-07-21 17:19:16 -07001183 View getDeepestFocusedChild() {
1184 View v = this;
1185 while (v != null) {
1186 if (v.isFocused()) {
1187 return v;
1188 }
1189 v = v instanceof ViewGroup ? ((ViewGroup) v).getFocusedChild() : null;
1190 }
1191 return null;
1192 }
1193
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001194 /**
1195 * Returns true if this view has or contains focus
1196 *
1197 * @return true if this view has or contains focus
1198 */
1199 @Override
1200 public boolean hasFocus() {
Dianne Hackborn4702a852012-08-17 15:18:29 -07001201 return (mPrivateFlags & PFLAG_FOCUSED) != 0 || mFocused != null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001202 }
1203
1204 /*
1205 * (non-Javadoc)
1206 *
1207 * @see android.view.View#findFocus()
1208 */
1209 @Override
1210 public View findFocus() {
1211 if (DBG) {
1212 System.out.println("Find focus in " + this + ": flags="
1213 + isFocused() + ", child=" + mFocused);
1214 }
1215
1216 if (isFocused()) {
1217 return this;
1218 }
1219
1220 if (mFocused != null) {
1221 return mFocused.findFocus();
1222 }
1223 return null;
1224 }
1225
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001226 @Override
Adam Powell0f552f42017-02-03 11:50:42 -08001227 boolean hasFocusable(boolean allowAutoFocus, boolean dispatchExplicit) {
Alan Viverette7485a9b2017-02-27 11:55:53 -05001228 // This should probably be super.hasFocusable, but that would change
1229 // behavior. Historically, we have not checked the ancestor views for
1230 // shouldBlockFocusForTouchscreen() in ViewGroup.hasFocusable.
1231
1232 // Invisible and gone views are never focusable.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001233 if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) {
1234 return false;
1235 }
1236
Alan Viverette7485a9b2017-02-27 11:55:53 -05001237 // Only use effective focusable value when allowed.
1238 if ((allowAutoFocus || getFocusable() != FOCUSABLE_AUTO) && isFocusable()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001239 return true;
1240 }
1241
Alan Viverette7485a9b2017-02-27 11:55:53 -05001242 // Determine whether we have a focused descendant.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001243 final int descendantFocusability = getDescendantFocusability();
Adam Powell88c11752014-07-21 17:19:16 -07001244 if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) {
Evan Rosky2ae1bf52017-05-11 11:18:45 -07001245 return hasFocusableChild(dispatchExplicit);
1246 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001247
Evan Rosky2ae1bf52017-05-11 11:18:45 -07001248 return false;
1249 }
Adam Powell0f552f42017-02-03 11:50:42 -08001250
Evan Rosky2ae1bf52017-05-11 11:18:45 -07001251 boolean hasFocusableChild(boolean dispatchExplicit) {
1252 // Determine whether we have a focusable descendant.
1253 final int count = mChildrenCount;
1254 final View[] children = mChildren;
1255
1256 for (int i = 0; i < count; i++) {
1257 final View child = children[i];
1258
1259 // In case the subclass has overridden has[Explicit]Focusable, dispatch
1260 // to the expected one for each child even though we share logic here.
1261 if ((dispatchExplicit && child.hasExplicitFocusable())
1262 || (!dispatchExplicit && child.hasFocusable())) {
1263 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001264 }
1265 }
1266
1267 return false;
1268 }
1269
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001270 @Override
svetoslavganov75986cf2009-05-14 22:28:01 -07001271 public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001272 final int focusableCount = views.size();
1273
1274 final int descendantFocusability = getDescendantFocusability();
Evan Rosky18b886e2017-02-15 13:26:51 -08001275 final boolean blockFocusForTouchscreen = shouldBlockFocusForTouchscreen();
1276 final boolean focusSelf = (isFocusableInTouchMode() || !blockFocusForTouchscreen);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001277
Evan Rosky3b94bf52017-01-10 17:05:28 -08001278 if (descendantFocusability == FOCUS_BLOCK_DESCENDANTS) {
1279 if (focusSelf) {
1280 super.addFocusables(views, direction, focusableMode);
Adam Powell88c11752014-07-21 17:19:16 -07001281 }
Evan Rosky3b94bf52017-01-10 17:05:28 -08001282 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001283 }
1284
Evan Rosky18b886e2017-02-15 13:26:51 -08001285 if (blockFocusForTouchscreen) {
Evan Rosky3b94bf52017-01-10 17:05:28 -08001286 focusableMode |= FOCUSABLES_TOUCH_MODE;
1287 }
1288
1289 if ((descendantFocusability == FOCUS_BEFORE_DESCENDANTS) && focusSelf) {
1290 super.addFocusables(views, direction, focusableMode);
1291 }
1292
1293 int count = 0;
1294 final View[] children = new View[mChildrenCount];
1295 for (int i = 0; i < mChildrenCount; ++i) {
1296 View child = mChildren[i];
1297 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
1298 children[count++] = child;
1299 }
1300 }
Evan Roskyd114e0f2017-03-23 11:20:04 -07001301 FocusFinder.sort(children, 0, count, this, isLayoutRtl());
Evan Rosky3b94bf52017-01-10 17:05:28 -08001302 for (int i = 0; i < count; ++i) {
1303 children[i].addFocusables(views, direction, focusableMode);
1304 }
1305
1306 // When set to FOCUS_AFTER_DESCENDANTS, we only add ourselves if
1307 // there aren't any focusable descendants. this is
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001308 // to avoid the focus search finding layouts when a more precise search
1309 // among the focusable children would be more interesting.
Evan Rosky3b94bf52017-01-10 17:05:28 -08001310 if ((descendantFocusability == FOCUS_AFTER_DESCENDANTS) && focusSelf
1311 && focusableCount == views.size()) {
svetoslavganov75986cf2009-05-14 22:28:01 -07001312 super.addFocusables(views, direction, focusableMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001313 }
1314 }
1315
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08001316 @Override
Vadim Tryshevb5ced222017-01-17 19:31:35 -08001317 public void addKeyboardNavigationClusters(Collection<View> views, int direction) {
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08001318 final int focusableCount = views.size();
1319
Evan Rosky18b886e2017-02-15 13:26:51 -08001320 if (isKeyboardNavigationCluster()) {
1321 // Cluster-navigation can enter a touchscreenBlocksFocus cluster, so temporarily
1322 // disable touchscreenBlocksFocus to evaluate whether it contains focusables.
1323 final boolean blockedFocus = getTouchscreenBlocksFocus();
1324 try {
1325 setTouchscreenBlocksFocusNoRefocus(false);
1326 super.addKeyboardNavigationClusters(views, direction);
1327 } finally {
1328 setTouchscreenBlocksFocusNoRefocus(blockedFocus);
1329 }
1330 } else {
1331 super.addKeyboardNavigationClusters(views, direction);
1332 }
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08001333
1334 if (focusableCount != views.size()) {
Vadim Tryshev311a5b52017-01-05 18:54:11 -08001335 // No need to look for groups inside a group.
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08001336 return;
1337 }
1338
1339 if (getDescendantFocusability() == FOCUS_BLOCK_DESCENDANTS) {
1340 return;
1341 }
1342
Evan Roskybd10c522017-03-27 15:50:38 -07001343 int count = 0;
1344 final View[] visibleChildren = new View[mChildrenCount];
1345 for (int i = 0; i < mChildrenCount; ++i) {
1346 final View child = mChildren[i];
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08001347 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
Evan Roskybd10c522017-03-27 15:50:38 -07001348 visibleChildren[count++] = child;
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08001349 }
1350 }
Evan Roskyd114e0f2017-03-23 11:20:04 -07001351 FocusFinder.sort(visibleChildren, 0, count, this, isLayoutRtl());
Evan Roskybd10c522017-03-27 15:50:38 -07001352 for (int i = 0; i < count; ++i) {
1353 visibleChildren[i].addKeyboardNavigationClusters(views, direction);
1354 }
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08001355 }
1356
Adam Powellff0d2982014-07-10 20:34:14 -07001357 /**
1358 * Set whether this ViewGroup should ignore focus requests for itself and its children.
1359 * If this option is enabled and the ViewGroup or a descendant currently has focus, focus
1360 * will proceed forward.
1361 *
1362 * @param touchscreenBlocksFocus true to enable blocking focus in the presence of a touchscreen
1363 */
1364 public void setTouchscreenBlocksFocus(boolean touchscreenBlocksFocus) {
1365 if (touchscreenBlocksFocus) {
1366 mGroupFlags |= FLAG_TOUCHSCREEN_BLOCKS_FOCUS;
Evan Rosky0e8a6832017-04-10 12:35:15 -07001367 if (hasFocus() && !isKeyboardNavigationCluster()) {
Adam Powell88c11752014-07-21 17:19:16 -07001368 final View focusedChild = getDeepestFocusedChild();
1369 if (!focusedChild.isFocusableInTouchMode()) {
1370 final View newFocus = focusSearch(FOCUS_FORWARD);
1371 if (newFocus != null) {
1372 newFocus.requestFocus();
1373 }
Adam Powellff0d2982014-07-10 20:34:14 -07001374 }
1375 }
1376 } else {
1377 mGroupFlags &= ~FLAG_TOUCHSCREEN_BLOCKS_FOCUS;
1378 }
1379 }
1380
Evan Rosky18b886e2017-02-15 13:26:51 -08001381 private void setTouchscreenBlocksFocusNoRefocus(boolean touchscreenBlocksFocus) {
1382 if (touchscreenBlocksFocus) {
1383 mGroupFlags |= FLAG_TOUCHSCREEN_BLOCKS_FOCUS;
1384 } else {
1385 mGroupFlags &= ~FLAG_TOUCHSCREEN_BLOCKS_FOCUS;
1386 }
1387 }
1388
Adam Powellff0d2982014-07-10 20:34:14 -07001389 /**
1390 * Check whether this ViewGroup should ignore focus requests for itself and its children.
1391 */
Evan Roskyecb63fc2017-04-13 16:57:18 -07001392 @ViewDebug.ExportedProperty(category = "focus")
Adam Powellff0d2982014-07-10 20:34:14 -07001393 public boolean getTouchscreenBlocksFocus() {
1394 return (mGroupFlags & FLAG_TOUCHSCREEN_BLOCKS_FOCUS) != 0;
1395 }
1396
1397 boolean shouldBlockFocusForTouchscreen() {
Evan Rosky18b886e2017-02-15 13:26:51 -08001398 // There is a special case for keyboard-navigation clusters. We allow cluster navigation
1399 // to jump into blockFocusForTouchscreen ViewGroups which are clusters. Once in the
1400 // cluster, focus is free to move around within it.
Adam Powellff0d2982014-07-10 20:34:14 -07001401 return getTouchscreenBlocksFocus() &&
Evan Rosky18b886e2017-02-15 13:26:51 -08001402 mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN)
Evan Rosky0e8a6832017-04-10 12:35:15 -07001403 && !(isKeyboardNavigationCluster()
1404 && (hasFocus() || (findKeyboardNavigationCluster() != this)));
Adam Powellff0d2982014-07-10 20:34:14 -07001405 }
1406
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001407 @Override
Svetoslav Ganovea515ae2011-09-14 18:15:32 -07001408 public void findViewsWithText(ArrayList<View> outViews, CharSequence text, int flags) {
1409 super.findViewsWithText(outViews, text, flags);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001410 final int childrenCount = mChildrenCount;
1411 final View[] children = mChildren;
1412 for (int i = 0; i < childrenCount; i++) {
1413 View child = children[i];
Svetoslav Ganovea515ae2011-09-14 18:15:32 -07001414 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE
Dianne Hackborn4702a852012-08-17 15:18:29 -07001415 && (child.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
Svetoslav Ganovea515ae2011-09-14 18:15:32 -07001416 child.findViewsWithText(outViews, text, flags);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001417 }
1418 }
1419 }
1420
Svetoslav5b578da2013-05-08 14:23:32 -07001421 /** @hide */
Svetoslav Ganov2cdedff2011-10-03 14:18:42 -07001422 @Override
Svetoslav5b578da2013-05-08 14:23:32 -07001423 public View findViewByAccessibilityIdTraversal(int accessibilityId) {
Svetoslav Ganov2cdedff2011-10-03 14:18:42 -07001424 View foundView = super.findViewByAccessibilityIdTraversal(accessibilityId);
1425 if (foundView != null) {
1426 return foundView;
1427 }
Svetoslav6cc46272015-06-03 11:38:30 -07001428
1429 if (getAccessibilityNodeProvider() != null) {
1430 return null;
1431 }
1432
Svetoslav Ganov2cdedff2011-10-03 14:18:42 -07001433 final int childrenCount = mChildrenCount;
1434 final View[] children = mChildren;
1435 for (int i = 0; i < childrenCount; i++) {
1436 View child = children[i];
1437 foundView = child.findViewByAccessibilityIdTraversal(accessibilityId);
1438 if (foundView != null) {
1439 return foundView;
1440 }
1441 }
Svetoslav6cc46272015-06-03 11:38:30 -07001442
Svetoslav Ganov2cdedff2011-10-03 14:18:42 -07001443 return null;
1444 }
1445
Phil Weaver846cda932017-06-15 10:10:06 -07001446 /** @hide */
1447 @Override
1448 public View findViewByAutofillIdTraversal(int autofillId) {
1449 View foundView = super.findViewByAutofillIdTraversal(autofillId);
1450 if (foundView != null) {
1451 return foundView;
1452 }
1453
1454 final int childrenCount = mChildrenCount;
1455 final View[] children = mChildren;
1456 for (int i = 0; i < childrenCount; i++) {
1457 View child = children[i];
1458 foundView = child.findViewByAutofillIdTraversal(autofillId);
1459 if (foundView != null) {
1460 return foundView;
1461 }
1462 }
1463
1464 return null;
1465 }
1466
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001467 @Override
1468 public void dispatchWindowFocusChanged(boolean hasFocus) {
1469 super.dispatchWindowFocusChanged(hasFocus);
1470 final int count = mChildrenCount;
1471 final View[] children = mChildren;
1472 for (int i = 0; i < count; i++) {
1473 children[i].dispatchWindowFocusChanged(hasFocus);
1474 }
1475 }
1476
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001477 @Override
1478 public void addTouchables(ArrayList<View> views) {
1479 super.addTouchables(views);
1480
1481 final int count = mChildrenCount;
1482 final View[] children = mChildren;
1483
1484 for (int i = 0; i < count; i++) {
1485 final View child = children[i];
1486 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
1487 child.addTouchables(views);
1488 }
1489 }
1490 }
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001491
1492 /**
1493 * @hide
1494 */
1495 @Override
Mathew Inwoode5ad5982018-08-17 15:07:52 +01001496 @UnsupportedAppUsage
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001497 public void makeOptionalFitsSystemWindows() {
1498 super.makeOptionalFitsSystemWindows();
1499 final int count = mChildrenCount;
1500 final View[] children = mChildren;
1501 for (int i = 0; i < count; i++) {
1502 children[i].makeOptionalFitsSystemWindows();
1503 }
1504 }
1505
Romain Guy43c9cdf2010-01-27 13:53:55 -08001506 @Override
1507 public void dispatchDisplayHint(int hint) {
1508 super.dispatchDisplayHint(hint);
1509 final int count = mChildrenCount;
1510 final View[] children = mChildren;
1511 for (int i = 0; i < count; i++) {
1512 children[i].dispatchDisplayHint(hint);
1513 }
1514 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001515
1516 /**
Chet Haase0d299362012-01-26 10:51:48 -08001517 * Called when a view's visibility has changed. Notify the parent to take any appropriate
1518 * action.
1519 *
1520 * @param child The view whose visibility has changed
1521 * @param oldVisibility The previous visibility value (GONE, INVISIBLE, or VISIBLE).
1522 * @param newVisibility The new visibility value (GONE, INVISIBLE, or VISIBLE).
Chet Haase5e25c2c2010-09-16 11:15:56 -07001523 * @hide
Chet Haase5e25c2c2010-09-16 11:15:56 -07001524 */
Mathew Inwoode5ad5982018-08-17 15:07:52 +01001525 @UnsupportedAppUsage
Chet Haase0d299362012-01-26 10:51:48 -08001526 protected void onChildVisibilityChanged(View child, int oldVisibility, int newVisibility) {
Chet Haase5e25c2c2010-09-16 11:15:56 -07001527 if (mTransition != null) {
Chet Haase0d299362012-01-26 10:51:48 -08001528 if (newVisibility == VISIBLE) {
1529 mTransition.showChild(this, child, oldVisibility);
Chet Haase5e25c2c2010-09-16 11:15:56 -07001530 } else {
Chet Haase0d299362012-01-26 10:51:48 -08001531 mTransition.hideChild(this, child, newVisibility);
Chet Haase5e25c2c2010-09-16 11:15:56 -07001532 if (mTransitioningViews != null && mTransitioningViews.contains(child)) {
Chet Haaseddbb3462012-06-19 13:54:29 -07001533 // Only track this on disappearing views - appearing views are already visible
1534 // and don't need special handling during drawChild()
1535 if (mVisibilityChangingChildren == null) {
1536 mVisibilityChangingChildren = new ArrayList<View>();
1537 }
1538 mVisibilityChangingChildren.add(child);
Chet Haase5e25c2c2010-09-16 11:15:56 -07001539 addDisappearingView(child);
1540 }
1541 }
1542 }
Christopher Tate86cab1b2011-01-13 20:28:55 -08001543
1544 // in all cases, for drags
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001545 if (newVisibility == VISIBLE && mCurrentDragStartEvent != null) {
1546 if (!mChildrenInterestedInDrag.contains(child)) {
1547 notifyChildOfDragStart(child);
Christopher Tate86cab1b2011-01-13 20:28:55 -08001548 }
1549 }
Chet Haase5e25c2c2010-09-16 11:15:56 -07001550 }
1551
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001552 @Override
Adam Powell326d8082009-12-09 15:10:07 -08001553 protected void dispatchVisibilityChanged(View changedView, int visibility) {
1554 super.dispatchVisibilityChanged(changedView, visibility);
1555 final int count = mChildrenCount;
1556 final View[] children = mChildren;
1557 for (int i = 0; i < count; i++) {
1558 children[i].dispatchVisibilityChanged(changedView, visibility);
1559 }
1560 }
1561
Adam Powell326d8082009-12-09 15:10:07 -08001562 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001563 public void dispatchWindowVisibilityChanged(int visibility) {
1564 super.dispatchWindowVisibilityChanged(visibility);
1565 final int count = mChildrenCount;
1566 final View[] children = mChildren;
1567 for (int i = 0; i < count; i++) {
1568 children[i].dispatchWindowVisibilityChanged(visibility);
1569 }
1570 }
1571
Dianne Hackborne36d6e22010-02-17 19:46:25 -08001572 @Override
Adam Powell9c146bf2016-03-15 17:35:00 -07001573 boolean dispatchVisibilityAggregated(boolean isVisible) {
1574 isVisible = super.dispatchVisibilityAggregated(isVisible);
Adam Powell41d96902016-03-15 14:43:19 -07001575 final int count = mChildrenCount;
1576 final View[] children = mChildren;
1577 for (int i = 0; i < count; i++) {
Adam Powell9c146bf2016-03-15 17:35:00 -07001578 // Only dispatch to visible children. Not visible children and their subtrees already
1579 // know that they aren't visible and that's not going to change as a result of
1580 // whatever triggered this dispatch.
1581 if (children[i].getVisibility() == VISIBLE) {
1582 children[i].dispatchVisibilityAggregated(isVisible);
Adam Powell41d96902016-03-15 14:43:19 -07001583 }
1584 }
Adam Powell9c146bf2016-03-15 17:35:00 -07001585 return isVisible;
Adam Powell41d96902016-03-15 14:43:19 -07001586 }
1587
1588 @Override
Dianne Hackborne36d6e22010-02-17 19:46:25 -08001589 public void dispatchConfigurationChanged(Configuration newConfig) {
1590 super.dispatchConfigurationChanged(newConfig);
1591 final int count = mChildrenCount;
1592 final View[] children = mChildren;
1593 for (int i = 0; i < count; i++) {
1594 children[i].dispatchConfigurationChanged(newConfig);
1595 }
1596 }
Filip Gruszczynskia33bdf32015-11-19 18:22:16 -08001597
Alan Viverettebe463f22016-01-21 10:50:10 -05001598 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001599 public void recomputeViewAttributes(View child) {
Joe Onorato664644d2011-01-23 17:53:23 -08001600 if (mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) {
1601 ViewParent parent = mParent;
1602 if (parent != null) parent.recomputeViewAttributes(this);
1603 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001604 }
Romain Guy8506ab42009-06-11 17:35:47 -07001605
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001606 @Override
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001607 void dispatchCollectViewAttributes(AttachInfo attachInfo, int visibility) {
1608 if ((visibility & VISIBILITY_MASK) == VISIBLE) {
1609 super.dispatchCollectViewAttributes(attachInfo, visibility);
1610 final int count = mChildrenCount;
1611 final View[] children = mChildren;
1612 for (int i = 0; i < count; i++) {
1613 final View child = children[i];
1614 child.dispatchCollectViewAttributes(attachInfo,
1615 visibility | (child.mViewFlags&VISIBILITY_MASK));
1616 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001617 }
1618 }
1619
Alan Viverettebe463f22016-01-21 10:50:10 -05001620 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001621 public void bringChildToFront(View child) {
Alan Viverette77bb6f12015-02-11 17:24:33 -08001622 final int index = indexOfChild(child);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001623 if (index >= 0) {
1624 removeFromArray(index);
1625 addInArray(child, mChildrenCount);
1626 child.mParent = this;
Chet Haasecb96db82013-09-04 10:21:46 -07001627 requestLayout();
1628 invalidate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001629 }
1630 }
1631
Romain Guy6410c0a2013-06-17 11:21:58 -07001632 private PointF getLocalPoint() {
1633 if (mLocalPoint == null) mLocalPoint = new PointF();
1634 return mLocalPoint;
1635 }
1636
Vadim Tryshevef128112016-09-16 14:05:53 -07001637 @Override
1638 boolean dispatchDragEnterExitInPreN(DragEvent event) {
1639 if (event.mAction == DragEvent.ACTION_DRAG_EXITED && mCurrentDragChild != null) {
1640 // The drag exited a sub-tree of views; notify of the exit all descendants that are in
1641 // entered state.
1642 // We don't need this recursive delivery for ENTERED events because they get generated
1643 // from the recursive delivery of LOCATION/DROP events, and hence, don't need their own
1644 // recursion.
1645 mCurrentDragChild.dispatchDragEnterExitInPreN(event);
1646 mCurrentDragChild = null;
1647 }
1648 return mIsInterestedInDrag && super.dispatchDragEnterExitInPreN(event);
1649 }
1650
Steve Block8a7259b2012-03-01 11:24:41 +00001651 // TODO: Write real docs
Christopher Tatea53146c2010-09-07 11:57:52 -07001652 @Override
1653 public boolean dispatchDragEvent(DragEvent event) {
1654 boolean retval = false;
1655 final float tx = event.mX;
1656 final float ty = event.mY;
Vadim Trysheva61efa42016-09-28 15:15:52 -07001657 final ClipData td = event.mClipData;
Christopher Tatea53146c2010-09-07 11:57:52 -07001658
Christopher Tatea53146c2010-09-07 11:57:52 -07001659 // Dispatch down the view hierarchy
Romain Guy6410c0a2013-06-17 11:21:58 -07001660 final PointF localPoint = getLocalPoint();
1661
Christopher Tatea53146c2010-09-07 11:57:52 -07001662 switch (event.mAction) {
1663 case DragEvent.ACTION_DRAG_STARTED: {
Vadim Tryshevef128112016-09-16 14:05:53 -07001664 // Clear the state to recalculate which views we drag over.
1665 mCurrentDragChild = null;
1666
Christopher Tate86cab1b2011-01-13 20:28:55 -08001667 // Set up our tracking of drag-started notifications
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001668 mCurrentDragStartEvent = DragEvent.obtain(event);
1669 if (mChildrenInterestedInDrag == null) {
1670 mChildrenInterestedInDrag = new HashSet<View>();
Christopher Tate86cab1b2011-01-13 20:28:55 -08001671 } else {
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001672 mChildrenInterestedInDrag.clear();
Christopher Tate86cab1b2011-01-13 20:28:55 -08001673 }
1674
Christopher Tatea53146c2010-09-07 11:57:52 -07001675 // Now dispatch down to our children, caching the responses
Christopher Tatea53146c2010-09-07 11:57:52 -07001676 final int count = mChildrenCount;
1677 final View[] children = mChildren;
1678 for (int i = 0; i < count; i++) {
Christopher Tate2c095f32010-10-04 14:13:40 -07001679 final View child = children[i];
Christopher Tate3d4bf172011-03-28 16:16:46 -07001680 child.mPrivateFlags2 &= ~View.DRAG_MASK;
Christopher Tate2c095f32010-10-04 14:13:40 -07001681 if (child.getVisibility() == VISIBLE) {
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001682 if (notifyChildOfDragStart(children[i])) {
1683 retval = true;
Christopher Tate2c095f32010-10-04 14:13:40 -07001684 }
Christopher Tatea53146c2010-09-07 11:57:52 -07001685 }
1686 }
1687
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001688 // Notify itself of the drag start.
1689 mIsInterestedInDrag = super.dispatchDragEvent(event);
1690 if (mIsInterestedInDrag) {
Christopher Tatea53146c2010-09-07 11:57:52 -07001691 retval = true;
1692 }
Yorke Lee0394b212016-03-10 18:20:04 -08001693
1694 if (!retval) {
1695 // Neither us nor any of our children are interested in this drag, so stop tracking
1696 // the current drag event.
1697 mCurrentDragStartEvent.recycle();
1698 mCurrentDragStartEvent = null;
1699 }
Christopher Tatea53146c2010-09-07 11:57:52 -07001700 } break;
1701
1702 case DragEvent.ACTION_DRAG_ENDED: {
Christopher Tate86cab1b2011-01-13 20:28:55 -08001703 // Release the bookkeeping now that the drag lifecycle has ended
Vadim Tryshev15177892015-12-18 08:01:00 -08001704 final HashSet<View> childrenInterestedInDrag = mChildrenInterestedInDrag;
1705 if (childrenInterestedInDrag != null) {
1706 for (View child : childrenInterestedInDrag) {
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001707 // If a child was interested in the ongoing drag, it's told that it's over
1708 if (child.dispatchDragEvent(event)) {
1709 retval = true;
1710 }
Christopher Tate1fc014f2011-01-19 12:56:26 -08001711 }
Vadim Tryshev15177892015-12-18 08:01:00 -08001712 childrenInterestedInDrag.clear();
1713 }
1714 if (mCurrentDragStartEvent != null) {
1715 mCurrentDragStartEvent.recycle();
1716 mCurrentDragStartEvent = null;
Christopher Tate1fc014f2011-01-19 12:56:26 -08001717 }
Christopher Tate86cab1b2011-01-13 20:28:55 -08001718
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001719 if (mIsInterestedInDrag) {
1720 if (super.dispatchDragEvent(event)) {
1721 retval = true;
1722 }
1723 mIsInterestedInDrag = false;
Christopher Tatea53146c2010-09-07 11:57:52 -07001724 }
1725 } break;
1726
Vadim Tryshev1edc6daf2016-09-15 16:19:15 -07001727 case DragEvent.ACTION_DRAG_LOCATION:
1728 case DragEvent.ACTION_DROP: {
Christopher Tatea53146c2010-09-07 11:57:52 -07001729 // Find the [possibly new] drag target
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001730 View target = findFrontmostDroppableChildAt(event.mX, event.mY, localPoint);
Vadim Tryshevef128112016-09-16 14:05:53 -07001731
1732 if (target != mCurrentDragChild) {
Vadim Tryshev45bee6b2016-09-19 11:00:37 -07001733 if (sCascadedDragDrop) {
Vadim Tryshevef128112016-09-16 14:05:53 -07001734 // For pre-Nougat apps, make sure that the whole hierarchy of views that contain
1735 // the drag location is kept in the state between ENTERED and EXITED events.
1736 // (Starting with N, only the innermost view will be in that state).
1737
1738 final int action = event.mAction;
1739 // Position should not be available for ACTION_DRAG_ENTERED and
1740 // ACTION_DRAG_EXITED.
1741 event.mX = 0;
1742 event.mY = 0;
Vadim Trysheva61efa42016-09-28 15:15:52 -07001743 event.mClipData = null;
Vadim Tryshevef128112016-09-16 14:05:53 -07001744
1745 if (mCurrentDragChild != null) {
1746 event.mAction = DragEvent.ACTION_DRAG_EXITED;
1747 mCurrentDragChild.dispatchDragEnterExitInPreN(event);
1748 }
1749
1750 if (target != null) {
1751 event.mAction = DragEvent.ACTION_DRAG_ENTERED;
1752 target.dispatchDragEnterExitInPreN(event);
1753 }
1754
1755 event.mAction = action;
1756 event.mX = tx;
1757 event.mY = ty;
Vadim Trysheva61efa42016-09-28 15:15:52 -07001758 event.mClipData = td;
Vadim Tryshevef128112016-09-16 14:05:53 -07001759 }
1760 mCurrentDragChild = target;
1761 }
1762
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001763 if (target == null && mIsInterestedInDrag) {
1764 target = this;
1765 }
Christopher Tatea53146c2010-09-07 11:57:52 -07001766
Vadim Tryshev1edc6daf2016-09-15 16:19:15 -07001767 // Dispatch the actual drag notice, localized into the target coordinates.
Christopher Tatea53146c2010-09-07 11:57:52 -07001768 if (target != null) {
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001769 if (target != this) {
1770 event.mX = localPoint.x;
1771 event.mY = localPoint.y;
Christopher Tatea53146c2010-09-07 11:57:52 -07001772
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001773 retval = target.dispatchDragEvent(event);
Christopher Tatea53146c2010-09-07 11:57:52 -07001774
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001775 event.mX = tx;
1776 event.mY = ty;
Vadim Tryshev1edc6daf2016-09-15 16:19:15 -07001777
Vadim Tryshev45bee6b2016-09-19 11:00:37 -07001778 if (mIsInterestedInDrag) {
1779 final boolean eventWasConsumed;
1780 if (sCascadedDragDrop) {
1781 eventWasConsumed = retval;
1782 } else {
1783 eventWasConsumed = event.mEventHandlerWasCalled;
1784 }
1785
1786 if (!eventWasConsumed) {
1787 retval = super.dispatchDragEvent(event);
1788 }
Vadim Tryshev1edc6daf2016-09-15 16:19:15 -07001789 }
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001790 } else {
1791 retval = super.dispatchDragEvent(event);
1792 }
Christopher Tatea53146c2010-09-07 11:57:52 -07001793 }
1794 } break;
Christopher Tatea53146c2010-09-07 11:57:52 -07001795 }
1796
Christopher Tatea53146c2010-09-07 11:57:52 -07001797 return retval;
1798 }
1799
1800 // Find the frontmost child view that lies under the given point, and calculate
1801 // the position within its own local coordinate system.
1802 View findFrontmostDroppableChildAt(float x, float y, PointF outLocalPoint) {
Christopher Tatea53146c2010-09-07 11:57:52 -07001803 final int count = mChildrenCount;
1804 final View[] children = mChildren;
1805 for (int i = count - 1; i >= 0; i--) {
1806 final View child = children[i];
Christopher Tate3d4bf172011-03-28 16:16:46 -07001807 if (!child.canAcceptDrag()) {
Christopher Tatea53146c2010-09-07 11:57:52 -07001808 continue;
1809 }
1810
Christopher Tate2c095f32010-10-04 14:13:40 -07001811 if (isTransformedTouchPointInView(x, y, child, outLocalPoint)) {
Christopher Tatea53146c2010-09-07 11:57:52 -07001812 return child;
1813 }
1814 }
1815 return null;
1816 }
1817
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001818 boolean notifyChildOfDragStart(View child) {
1819 // The caller guarantees that the child is not in mChildrenInterestedInDrag yet.
1820
Christopher Tate86cab1b2011-01-13 20:28:55 -08001821 if (ViewDebug.DEBUG_DRAG) {
1822 Log.d(View.VIEW_LOG_TAG, "Sending drag-started to view: " + child);
1823 }
1824
Vladislav Kaznacheevc2449702016-05-16 12:57:15 -07001825 final float tx = mCurrentDragStartEvent.mX;
1826 final float ty = mCurrentDragStartEvent.mY;
1827
1828 final float[] point = getTempPoint();
1829 point[0] = tx;
1830 point[1] = ty;
1831 transformPointToViewLocal(point, child);
1832
1833 mCurrentDragStartEvent.mX = point[0];
1834 mCurrentDragStartEvent.mY = point[1];
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001835 final boolean canAccept = child.dispatchDragEvent(mCurrentDragStartEvent);
Vladislav Kaznacheevc2449702016-05-16 12:57:15 -07001836 mCurrentDragStartEvent.mX = tx;
1837 mCurrentDragStartEvent.mY = ty;
Vadim Tryshev1edc6daf2016-09-15 16:19:15 -07001838 mCurrentDragStartEvent.mEventHandlerWasCalled = false;
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001839 if (canAccept) {
1840 mChildrenInterestedInDrag.add(child);
1841 if (!child.canAcceptDrag()) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07001842 child.mPrivateFlags2 |= View.PFLAG2_DRAG_CAN_ACCEPT;
Christopher Tate3d4bf172011-03-28 16:16:46 -07001843 child.refreshDrawableState();
1844 }
Christopher Tate86cab1b2011-01-13 20:28:55 -08001845 }
Christopher Tate3d4bf172011-03-28 16:16:46 -07001846 return canAccept;
Christopher Tate86cab1b2011-01-13 20:28:55 -08001847 }
1848
Joe Onorato664644d2011-01-23 17:53:23 -08001849 @Override
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001850 public void dispatchWindowSystemUiVisiblityChanged(int visible) {
1851 super.dispatchWindowSystemUiVisiblityChanged(visible);
1852
1853 final int count = mChildrenCount;
1854 final View[] children = mChildren;
1855 for (int i=0; i <count; i++) {
1856 final View child = children[i];
1857 child.dispatchWindowSystemUiVisiblityChanged(visible);
1858 }
1859 }
1860
1861 @Override
Joe Onorato664644d2011-01-23 17:53:23 -08001862 public void dispatchSystemUiVisibilityChanged(int visible) {
1863 super.dispatchSystemUiVisibilityChanged(visible);
1864
1865 final int count = mChildrenCount;
1866 final View[] children = mChildren;
1867 for (int i=0; i <count; i++) {
1868 final View child = children[i];
1869 child.dispatchSystemUiVisibilityChanged(visible);
1870 }
1871 }
1872
Dianne Hackborn9a230e02011-10-06 11:51:27 -07001873 @Override
Dianne Hackborncf675782012-05-10 15:07:24 -07001874 boolean updateLocalSystemUiVisibility(int localValue, int localChanges) {
1875 boolean changed = super.updateLocalSystemUiVisibility(localValue, localChanges);
Dianne Hackborn9a230e02011-10-06 11:51:27 -07001876
1877 final int count = mChildrenCount;
1878 final View[] children = mChildren;
1879 for (int i=0; i <count; i++) {
1880 final View child = children[i];
Dianne Hackborncf675782012-05-10 15:07:24 -07001881 changed |= child.updateLocalSystemUiVisibility(localValue, localChanges);
Dianne Hackborn9a230e02011-10-06 11:51:27 -07001882 }
Dianne Hackborncf675782012-05-10 15:07:24 -07001883 return changed;
Dianne Hackborn9a230e02011-10-06 11:51:27 -07001884 }
1885
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001886 @Override
1887 public boolean dispatchKeyEventPreIme(KeyEvent event) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07001888 if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
1889 == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001890 return super.dispatchKeyEventPreIme(event);
Dianne Hackborn4702a852012-08-17 15:18:29 -07001891 } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
1892 == PFLAG_HAS_BOUNDS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001893 return mFocused.dispatchKeyEventPreIme(event);
1894 }
1895 return false;
1896 }
1897
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001898 @Override
1899 public boolean dispatchKeyEvent(KeyEvent event) {
Jeff Brown21bc5c92011-02-28 18:27:14 -08001900 if (mInputEventConsistencyVerifier != null) {
1901 mInputEventConsistencyVerifier.onKeyEvent(event, 1);
1902 }
1903
Dianne Hackborn4702a852012-08-17 15:18:29 -07001904 if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
1905 == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001906 if (super.dispatchKeyEvent(event)) {
1907 return true;
1908 }
Dianne Hackborn4702a852012-08-17 15:18:29 -07001909 } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
1910 == PFLAG_HAS_BOUNDS) {
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001911 if (mFocused.dispatchKeyEvent(event)) {
1912 return true;
1913 }
1914 }
1915
1916 if (mInputEventConsistencyVerifier != null) {
1917 mInputEventConsistencyVerifier.onUnhandledEvent(event, 1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001918 }
1919 return false;
1920 }
1921
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001922 @Override
1923 public boolean dispatchKeyShortcutEvent(KeyEvent event) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07001924 if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
1925 == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001926 return super.dispatchKeyShortcutEvent(event);
Dianne Hackborn4702a852012-08-17 15:18:29 -07001927 } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
1928 == PFLAG_HAS_BOUNDS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001929 return mFocused.dispatchKeyShortcutEvent(event);
1930 }
1931 return false;
1932 }
1933
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001934 @Override
1935 public boolean dispatchTrackballEvent(MotionEvent event) {
Jeff Brown21bc5c92011-02-28 18:27:14 -08001936 if (mInputEventConsistencyVerifier != null) {
1937 mInputEventConsistencyVerifier.onTrackballEvent(event, 1);
1938 }
1939
Dianne Hackborn4702a852012-08-17 15:18:29 -07001940 if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
1941 == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001942 if (super.dispatchTrackballEvent(event)) {
1943 return true;
1944 }
Dianne Hackborn4702a852012-08-17 15:18:29 -07001945 } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
1946 == PFLAG_HAS_BOUNDS) {
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001947 if (mFocused.dispatchTrackballEvent(event)) {
1948 return true;
1949 }
1950 }
1951
1952 if (mInputEventConsistencyVerifier != null) {
1953 mInputEventConsistencyVerifier.onUnhandledEvent(event, 1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001954 }
1955 return false;
1956 }
1957
Jun Mukai1db53972015-09-11 18:08:31 -07001958 @Override
Vladislav Kaznacheev3787de12016-12-21 10:36:35 -08001959 public boolean dispatchCapturedPointerEvent(MotionEvent event) {
1960 if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
1961 == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
1962 if (super.dispatchCapturedPointerEvent(event)) {
1963 return true;
1964 }
1965 } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
1966 == PFLAG_HAS_BOUNDS) {
1967 if (mFocused.dispatchCapturedPointerEvent(event)) {
1968 return true;
1969 }
1970 }
1971 return false;
1972 }
1973
1974 @Override
1975 public void dispatchPointerCaptureChanged(boolean hasCapture) {
1976 exitHoverTargets();
1977
1978 super.dispatchPointerCaptureChanged(hasCapture);
1979 final int count = mChildrenCount;
1980 final View[] children = mChildren;
1981 for (int i = 0; i < count; i++) {
1982 children[i].dispatchPointerCaptureChanged(hasCapture);
1983 }
1984 }
1985
1986 @Override
Michael Wrighte051f6f2016-05-13 17:44:16 +01001987 public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) {
1988 final float x = event.getX(pointerIndex);
1989 final float y = event.getY(pointerIndex);
Keisuke Kuroyanagid85bc502016-01-21 14:50:38 +09001990 if (isOnScrollbarThumb(x, y) || isDraggingScrollBar()) {
Michael Wrighte051f6f2016-05-13 17:44:16 +01001991 return PointerIcon.getSystemIcon(mContext, PointerIcon.TYPE_ARROW);
Keisuke Kuroyanagid85bc502016-01-21 14:50:38 +09001992 }
Jun Mukai1db53972015-09-11 18:08:31 -07001993 // Check what the child under the pointer says about the pointer.
1994 final int childrenCount = mChildrenCount;
1995 if (childrenCount != 0) {
1996 final ArrayList<View> preorderedList = buildOrderedChildList();
1997 final boolean customOrder = preorderedList == null
1998 && isChildrenDrawingOrderEnabled();
1999 final View[] children = mChildren;
2000 for (int i = childrenCount - 1; i >= 0; i--) {
Alan Viverettea7b85e62016-01-22 10:14:02 -05002001 final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
2002 final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);
Vladislav Kaznacheev3d5cfc02017-01-05 17:50:38 -08002003 if (!canViewReceivePointerEvents(child)
2004 || !isTransformedTouchPointInView(x, y, child, null)) {
2005 continue;
2006 }
2007 final PointerIcon pointerIcon =
2008 dispatchResolvePointerIcon(event, pointerIndex, child);
2009 if (pointerIcon != null) {
2010 if (preorderedList != null) preorderedList.clear();
2011 return pointerIcon;
Jun Mukai1db53972015-09-11 18:08:31 -07002012 }
2013 }
Chris Craikfc563772016-05-04 13:34:30 -07002014 if (preorderedList != null) preorderedList.clear();
Jun Mukai1db53972015-09-11 18:08:31 -07002015 }
2016
2017 // The pointer is not a child or the child has no preferences, returning the default
2018 // implementation.
Michael Wrighte051f6f2016-05-13 17:44:16 +01002019 return super.onResolvePointerIcon(event, pointerIndex);
2020 }
2021
2022 private PointerIcon dispatchResolvePointerIcon(MotionEvent event, int pointerIndex,
2023 View child) {
2024 final PointerIcon pointerIcon;
2025 if (!child.hasIdentityMatrix()) {
2026 MotionEvent transformedEvent = getTransformedMotionEvent(event, child);
2027 pointerIcon = child.onResolvePointerIcon(transformedEvent, pointerIndex);
2028 transformedEvent.recycle();
2029 } else {
2030 final float offsetX = mScrollX - child.mLeft;
2031 final float offsetY = mScrollY - child.mTop;
2032 event.offsetLocation(offsetX, offsetY);
2033 pointerIcon = child.onResolvePointerIcon(event, pointerIndex);
2034 event.offsetLocation(-offsetX, -offsetY);
2035 }
2036 return pointerIcon;
Jun Mukai1db53972015-09-11 18:08:31 -07002037 }
2038
Alan Viverettea7b85e62016-01-22 10:14:02 -05002039 private int getAndVerifyPreorderedIndex(int childrenCount, int i, boolean customOrder) {
2040 final int childIndex;
2041 if (customOrder) {
2042 final int childIndex1 = getChildDrawingOrder(childrenCount, i);
2043 if (childIndex1 >= childrenCount) {
2044 throw new IndexOutOfBoundsException("getChildDrawingOrder() "
2045 + "returned invalid index " + childIndex1
2046 + " (child count is " + childrenCount + ")");
2047 }
2048 childIndex = childIndex1;
2049 } else {
2050 childIndex = i;
2051 }
2052 return childIndex;
2053 }
2054
Romain Guya9489272011-06-22 20:58:11 -07002055 @SuppressWarnings({"ConstantConditions"})
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002056 @Override
Jeff Browna032cc02011-03-07 16:56:21 -08002057 protected boolean dispatchHoverEvent(MotionEvent event) {
Jeff Browna032cc02011-03-07 16:56:21 -08002058 final int action = event.getAction();
Jeff Browna032cc02011-03-07 16:56:21 -08002059
Jeff Brown10b62902011-06-20 16:40:37 -07002060 // First check whether the view group wants to intercept the hover event.
2061 final boolean interceptHover = onInterceptHoverEvent(event);
2062 event.setAction(action); // restore action in case it was changed
2063
Jeff Brown87b7f802011-06-21 18:35:45 -07002064 MotionEvent eventNoHistory = event;
2065 boolean handled = false;
2066
2067 // Send events to the hovered children and build a new list of hover targets until
2068 // one is found that handles the event.
2069 HoverTarget firstOldHoverTarget = mFirstHoverTarget;
2070 mFirstHoverTarget = null;
Jeff Brown10b62902011-06-20 16:40:37 -07002071 if (!interceptHover && action != MotionEvent.ACTION_HOVER_EXIT) {
Jeff Browna032cc02011-03-07 16:56:21 -08002072 final float x = event.getX();
2073 final float y = event.getY();
Jeff Brown33bbfd22011-02-24 20:55:35 -08002074 final int childrenCount = mChildrenCount;
2075 if (childrenCount != 0) {
Chris Craikab008f02014-05-23 17:55:03 -07002076 final ArrayList<View> preorderedList = buildOrderedChildList();
2077 final boolean customOrder = preorderedList == null
2078 && isChildrenDrawingOrderEnabled();
Jeff Brown33bbfd22011-02-24 20:55:35 -08002079 final View[] children = mChildren;
Jeff Brown87b7f802011-06-21 18:35:45 -07002080 HoverTarget lastHoverTarget = null;
Jeff Brown33bbfd22011-02-24 20:55:35 -08002081 for (int i = childrenCount - 1; i >= 0; i--) {
Alan Viverettea7b85e62016-01-22 10:14:02 -05002082 final int childIndex = getAndVerifyPreorderedIndex(
2083 childrenCount, i, customOrder);
2084 final View child = getAndVerifyPreorderedView(
2085 preorderedList, children, childIndex);
Jeff Brown87b7f802011-06-21 18:35:45 -07002086 if (!canViewReceivePointerEvents(child)
2087 || !isTransformedTouchPointInView(x, y, child, null)) {
2088 continue;
2089 }
2090
2091 // Obtain a hover target for this child. Dequeue it from the
2092 // old hover target list if the child was previously hovered.
2093 HoverTarget hoverTarget = firstOldHoverTarget;
2094 final boolean wasHovered;
2095 for (HoverTarget predecessor = null; ;) {
2096 if (hoverTarget == null) {
2097 hoverTarget = HoverTarget.obtain(child);
2098 wasHovered = false;
2099 break;
2100 }
2101
2102 if (hoverTarget.child == child) {
2103 if (predecessor != null) {
2104 predecessor.next = hoverTarget.next;
2105 } else {
2106 firstOldHoverTarget = hoverTarget.next;
2107 }
2108 hoverTarget.next = null;
2109 wasHovered = true;
2110 break;
2111 }
2112
2113 predecessor = hoverTarget;
2114 hoverTarget = hoverTarget.next;
2115 }
2116
2117 // Enqueue the hover target onto the new hover target list.
2118 if (lastHoverTarget != null) {
2119 lastHoverTarget.next = hoverTarget;
2120 } else {
Jeff Brown87b7f802011-06-21 18:35:45 -07002121 mFirstHoverTarget = hoverTarget;
2122 }
Sangkyu Lee8725f362013-03-13 09:38:45 +09002123 lastHoverTarget = hoverTarget;
Jeff Brown87b7f802011-06-21 18:35:45 -07002124
2125 // Dispatch the event to the child.
2126 if (action == MotionEvent.ACTION_HOVER_ENTER) {
2127 if (!wasHovered) {
2128 // Send the enter as is.
2129 handled |= dispatchTransformedGenericPointerEvent(
2130 event, child); // enter
2131 }
2132 } else if (action == MotionEvent.ACTION_HOVER_MOVE) {
2133 if (!wasHovered) {
2134 // Synthesize an enter from a move.
2135 eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory);
2136 eventNoHistory.setAction(MotionEvent.ACTION_HOVER_ENTER);
2137 handled |= dispatchTransformedGenericPointerEvent(
2138 eventNoHistory, child); // enter
2139 eventNoHistory.setAction(action);
2140
2141 handled |= dispatchTransformedGenericPointerEvent(
2142 eventNoHistory, child); // move
2143 } else {
2144 // Send the move as is.
2145 handled |= dispatchTransformedGenericPointerEvent(event, child);
2146 }
2147 }
2148 if (handled) {
Jeff Brown10b62902011-06-20 16:40:37 -07002149 break;
Jeff Brown33bbfd22011-02-24 20:55:35 -08002150 }
Jeff Brown10b62902011-06-20 16:40:37 -07002151 }
Chris Craikab008f02014-05-23 17:55:03 -07002152 if (preorderedList != null) preorderedList.clear();
Jeff Brown10b62902011-06-20 16:40:37 -07002153 }
2154 }
Jeff Brown33bbfd22011-02-24 20:55:35 -08002155
Jeff Brown87b7f802011-06-21 18:35:45 -07002156 // Send exit events to all previously hovered children that are no longer hovered.
2157 while (firstOldHoverTarget != null) {
2158 final View child = firstOldHoverTarget.child;
Jeff Brown10b62902011-06-20 16:40:37 -07002159
Jeff Brown87b7f802011-06-21 18:35:45 -07002160 // Exit the old hovered child.
2161 if (action == MotionEvent.ACTION_HOVER_EXIT) {
2162 // Send the exit as is.
2163 handled |= dispatchTransformedGenericPointerEvent(
2164 event, child); // exit
2165 } else {
2166 // Synthesize an exit from a move or enter.
2167 // Ignore the result because hover focus has moved to a different view.
2168 if (action == MotionEvent.ACTION_HOVER_MOVE) {
Vladislav Kaznacheev5a77c372016-10-10 16:11:15 -07002169 final boolean hoverExitPending = event.isHoverExitPending();
2170 event.setHoverExitPending(true);
Jeff Brown10b62902011-06-20 16:40:37 -07002171 dispatchTransformedGenericPointerEvent(
Jeff Brown87b7f802011-06-21 18:35:45 -07002172 event, child); // move
Vladislav Kaznacheev5a77c372016-10-10 16:11:15 -07002173 event.setHoverExitPending(hoverExitPending);
Jeff Brown10b62902011-06-20 16:40:37 -07002174 }
Jeff Brown87b7f802011-06-21 18:35:45 -07002175 eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory);
2176 eventNoHistory.setAction(MotionEvent.ACTION_HOVER_EXIT);
2177 dispatchTransformedGenericPointerEvent(
2178 eventNoHistory, child); // exit
2179 eventNoHistory.setAction(action);
Jeff Brown10b62902011-06-20 16:40:37 -07002180 }
2181
Jeff Brown87b7f802011-06-21 18:35:45 -07002182 final HoverTarget nextOldHoverTarget = firstOldHoverTarget.next;
2183 firstOldHoverTarget.recycle();
2184 firstOldHoverTarget = nextOldHoverTarget;
Jeff Brown10b62902011-06-20 16:40:37 -07002185 }
2186
Vladislav Kaznacheev5a77c372016-10-10 16:11:15 -07002187 // Send events to the view group itself if no children have handled it and the view group
2188 // itself is not currently being hover-exited.
2189 boolean newHoveredSelf = !handled &&
2190 (action != MotionEvent.ACTION_HOVER_EXIT) && !event.isHoverExitPending();
Jeff Brown10b62902011-06-20 16:40:37 -07002191 if (newHoveredSelf == mHoveredSelf) {
2192 if (newHoveredSelf) {
2193 // Send event to the view group as before.
2194 handled |= super.dispatchHoverEvent(event);
2195 }
2196 } else {
2197 if (mHoveredSelf) {
2198 // Exit the view group.
2199 if (action == MotionEvent.ACTION_HOVER_EXIT) {
2200 // Send the exit as is.
2201 handled |= super.dispatchHoverEvent(event); // exit
2202 } else {
2203 // Synthesize an exit from a move or enter.
2204 // Ignore the result because hover focus is moving to a different view.
2205 if (action == MotionEvent.ACTION_HOVER_MOVE) {
2206 super.dispatchHoverEvent(event); // move
2207 }
2208 eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory);
2209 eventNoHistory.setAction(MotionEvent.ACTION_HOVER_EXIT);
2210 super.dispatchHoverEvent(eventNoHistory); // exit
2211 eventNoHistory.setAction(action);
2212 }
2213 mHoveredSelf = false;
2214 }
2215
2216 if (newHoveredSelf) {
2217 // Enter the view group.
2218 if (action == MotionEvent.ACTION_HOVER_ENTER) {
2219 // Send the enter as is.
2220 handled |= super.dispatchHoverEvent(event); // enter
2221 mHoveredSelf = true;
2222 } else if (action == MotionEvent.ACTION_HOVER_MOVE) {
2223 // Synthesize an enter from a move.
2224 eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory);
2225 eventNoHistory.setAction(MotionEvent.ACTION_HOVER_ENTER);
2226 handled |= super.dispatchHoverEvent(eventNoHistory); // enter
2227 eventNoHistory.setAction(action);
2228
2229 handled |= super.dispatchHoverEvent(eventNoHistory); // move
2230 mHoveredSelf = true;
Jeff Brown33bbfd22011-02-24 20:55:35 -08002231 }
2232 }
Jeff Brown33bbfd22011-02-24 20:55:35 -08002233 }
2234
Jeff Browna032cc02011-03-07 16:56:21 -08002235 // Recycle the copy of the event that we made.
2236 if (eventNoHistory != event) {
2237 eventNoHistory.recycle();
2238 }
2239
Jeff Browna032cc02011-03-07 16:56:21 -08002240 // Done.
2241 return handled;
2242 }
2243
Jeff Brown59a422e2012-04-19 15:19:19 -07002244 private void exitHoverTargets() {
2245 if (mHoveredSelf || mFirstHoverTarget != null) {
2246 final long now = SystemClock.uptimeMillis();
2247 MotionEvent event = MotionEvent.obtain(now, now,
2248 MotionEvent.ACTION_HOVER_EXIT, 0.0f, 0.0f, 0);
2249 event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
2250 dispatchHoverEvent(event);
2251 event.recycle();
2252 }
2253 }
2254
2255 private void cancelHoverTarget(View view) {
2256 HoverTarget predecessor = null;
2257 HoverTarget target = mFirstHoverTarget;
2258 while (target != null) {
2259 final HoverTarget next = target.next;
2260 if (target.child == view) {
2261 if (predecessor == null) {
2262 mFirstHoverTarget = next;
2263 } else {
2264 predecessor.next = next;
2265 }
2266 target.recycle();
2267
2268 final long now = SystemClock.uptimeMillis();
2269 MotionEvent event = MotionEvent.obtain(now, now,
2270 MotionEvent.ACTION_HOVER_EXIT, 0.0f, 0.0f, 0);
2271 event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
2272 view.dispatchHoverEvent(event);
2273 event.recycle();
2274 return;
2275 }
2276 predecessor = target;
2277 target = next;
2278 }
2279 }
2280
Vladislav Kaznacheevf847ee32016-11-21 14:11:00 -08002281 @Override
2282 boolean dispatchTooltipHoverEvent(MotionEvent event) {
2283 final int action = event.getAction();
2284 switch (action) {
2285 case MotionEvent.ACTION_HOVER_ENTER:
2286 break;
2287
2288 case MotionEvent.ACTION_HOVER_MOVE:
2289 View newTarget = null;
2290
2291 // Check what the child under the pointer says about the tooltip.
2292 final int childrenCount = mChildrenCount;
2293 if (childrenCount != 0) {
2294 final float x = event.getX();
2295 final float y = event.getY();
2296
2297 final ArrayList<View> preorderedList = buildOrderedChildList();
2298 final boolean customOrder = preorderedList == null
2299 && isChildrenDrawingOrderEnabled();
2300 final View[] children = mChildren;
2301 for (int i = childrenCount - 1; i >= 0; i--) {
2302 final int childIndex =
2303 getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
2304 final View child =
2305 getAndVerifyPreorderedView(preorderedList, children, childIndex);
Vladislav Kaznacheev943cf0e2017-01-06 09:52:51 -08002306 if (!canViewReceivePointerEvents(child)
2307 || !isTransformedTouchPointInView(x, y, child, null)) {
2308 continue;
2309 }
2310 if (dispatchTooltipHoverEvent(event, child)) {
2311 newTarget = child;
Vladislav Kaznacheevf847ee32016-11-21 14:11:00 -08002312 break;
2313 }
2314 }
2315 if (preorderedList != null) preorderedList.clear();
2316 }
2317
2318 if (mTooltipHoverTarget != newTarget) {
2319 if (mTooltipHoverTarget != null) {
2320 event.setAction(MotionEvent.ACTION_HOVER_EXIT);
2321 mTooltipHoverTarget.dispatchTooltipHoverEvent(event);
2322 event.setAction(action);
2323 }
2324 mTooltipHoverTarget = newTarget;
2325 }
2326
2327 if (mTooltipHoverTarget != null) {
2328 if (mTooltipHoveredSelf) {
2329 mTooltipHoveredSelf = false;
2330 event.setAction(MotionEvent.ACTION_HOVER_EXIT);
2331 super.dispatchTooltipHoverEvent(event);
2332 event.setAction(action);
2333 }
2334 return true;
2335 }
2336
2337 mTooltipHoveredSelf = super.dispatchTooltipHoverEvent(event);
2338 return mTooltipHoveredSelf;
2339
2340 case MotionEvent.ACTION_HOVER_EXIT:
2341 if (mTooltipHoverTarget != null) {
2342 mTooltipHoverTarget.dispatchTooltipHoverEvent(event);
2343 mTooltipHoverTarget = null;
2344 } else if (mTooltipHoveredSelf) {
2345 super.dispatchTooltipHoverEvent(event);
2346 mTooltipHoveredSelf = false;
2347 }
2348 break;
2349 }
2350 return false;
2351 }
2352
2353 private boolean dispatchTooltipHoverEvent(MotionEvent event, View child) {
2354 final boolean result;
2355 if (!child.hasIdentityMatrix()) {
2356 MotionEvent transformedEvent = getTransformedMotionEvent(event, child);
2357 result = child.dispatchTooltipHoverEvent(transformedEvent);
2358 transformedEvent.recycle();
2359 } else {
2360 final float offsetX = mScrollX - child.mLeft;
2361 final float offsetY = mScrollY - child.mTop;
2362 event.offsetLocation(offsetX, offsetY);
2363 result = child.dispatchTooltipHoverEvent(event);
2364 event.offsetLocation(-offsetX, -offsetY);
2365 }
2366 return result;
2367 }
2368
2369 private void exitTooltipHoverTargets() {
2370 if (mTooltipHoveredSelf || mTooltipHoverTarget != null) {
2371 final long now = SystemClock.uptimeMillis();
2372 MotionEvent event = MotionEvent.obtain(now, now,
2373 MotionEvent.ACTION_HOVER_EXIT, 0.0f, 0.0f, 0);
2374 event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
2375 dispatchTooltipHoverEvent(event);
2376 event.recycle();
2377 }
2378 }
2379
Jeff Brown87b7f802011-06-21 18:35:45 -07002380 /** @hide */
2381 @Override
2382 protected boolean hasHoveredChild() {
2383 return mFirstHoverTarget != null;
2384 }
2385
Svetoslav Ganov42138042012-03-20 11:51:39 -07002386 @Override
Adam Powellcf392d12015-06-25 14:48:45 -07002387 public void addChildrenForAccessibility(ArrayList<View> outChildren) {
Svetoslav762621c2015-06-01 17:21:59 -07002388 if (getAccessibilityNodeProvider() != null) {
2389 return;
2390 }
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07002391 ChildListForAccessibility children = ChildListForAccessibility.obtain(this, true);
2392 try {
2393 final int childrenCount = children.getChildCount();
2394 for (int i = 0; i < childrenCount; i++) {
2395 View child = children.getChildAt(i);
Svetoslav Ganovc406be92012-05-11 16:12:32 -07002396 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07002397 if (child.includeForAccessibility()) {
Adam Powellcf392d12015-06-25 14:48:45 -07002398 outChildren.add(child);
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07002399 } else {
Adam Powellcf392d12015-06-25 14:48:45 -07002400 child.addChildrenForAccessibility(outChildren);
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07002401 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07002402 }
2403 }
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07002404 } finally {
2405 children.recycle();
Svetoslav Ganov42138042012-03-20 11:51:39 -07002406 }
2407 }
2408
2409 /**
Jeff Brown10b62902011-06-20 16:40:37 -07002410 * Implement this method to intercept hover events before they are handled
2411 * by child views.
2412 * <p>
2413 * This method is called before dispatching a hover event to a child of
2414 * the view group or to the view group's own {@link #onHoverEvent} to allow
2415 * the view group a chance to intercept the hover event.
2416 * This method can also be used to watch all pointer motions that occur within
2417 * the bounds of the view group even when the pointer is hovering over
2418 * a child of the view group rather than over the view group itself.
2419 * </p><p>
2420 * The view group can prevent its children from receiving hover events by
2421 * implementing this method and returning <code>true</code> to indicate
2422 * that it would like to intercept hover events. The view group must
2423 * continuously return <code>true</code> from {@link #onInterceptHoverEvent}
2424 * for as long as it wishes to continue intercepting hover events from
2425 * its children.
2426 * </p><p>
2427 * Interception preserves the invariant that at most one view can be
2428 * hovered at a time by transferring hover focus from the currently hovered
2429 * child to the view group or vice-versa as needed.
2430 * </p><p>
2431 * If this method returns <code>true</code> and a child is already hovered, then the
2432 * child view will first receive a hover exit event and then the view group
2433 * itself will receive a hover enter event in {@link #onHoverEvent}.
2434 * Likewise, if this method had previously returned <code>true</code> to intercept hover
2435 * events and instead returns <code>false</code> while the pointer is hovering
2436 * within the bounds of one of a child, then the view group will first receive a
2437 * hover exit event in {@link #onHoverEvent} and then the hovered child will
2438 * receive a hover enter event.
2439 * </p><p>
Keisuke Kuroyanagid85bc502016-01-21 14:50:38 +09002440 * The default implementation handles mouse hover on the scroll bars.
Jeff Brown10b62902011-06-20 16:40:37 -07002441 * </p>
2442 *
2443 * @param event The motion event that describes the hover.
2444 * @return True if the view group would like to intercept the hover event
2445 * and prevent its children from receiving it.
2446 */
2447 public boolean onInterceptHoverEvent(MotionEvent event) {
Keisuke Kuroyanagid85bc502016-01-21 14:50:38 +09002448 if (event.isFromSource(InputDevice.SOURCE_MOUSE)) {
2449 final int action = event.getAction();
2450 final float x = event.getX();
2451 final float y = event.getY();
2452 if ((action == MotionEvent.ACTION_HOVER_MOVE
2453 || action == MotionEvent.ACTION_HOVER_ENTER) && isOnScrollbar(x, y)) {
2454 return true;
2455 }
2456 }
Svetoslav Ganov736c2752011-04-22 18:30:36 -07002457 return false;
2458 }
2459
Jeff Browna032cc02011-03-07 16:56:21 -08002460 private static MotionEvent obtainMotionEventNoHistoryOrSelf(MotionEvent event) {
2461 if (event.getHistorySize() == 0) {
2462 return event;
2463 }
2464 return MotionEvent.obtainNoHistory(event);
2465 }
2466
Jeff Browna032cc02011-03-07 16:56:21 -08002467 @Override
2468 protected boolean dispatchGenericPointerEvent(MotionEvent event) {
2469 // Send the event to the child under the pointer.
2470 final int childrenCount = mChildrenCount;
2471 if (childrenCount != 0) {
Jeff Browna032cc02011-03-07 16:56:21 -08002472 final float x = event.getX();
2473 final float y = event.getY();
2474
Chris Craikab008f02014-05-23 17:55:03 -07002475 final ArrayList<View> preorderedList = buildOrderedChildList();
2476 final boolean customOrder = preorderedList == null
2477 && isChildrenDrawingOrderEnabled();
2478 final View[] children = mChildren;
Jeff Browna032cc02011-03-07 16:56:21 -08002479 for (int i = childrenCount - 1; i >= 0; i--) {
Alan Viverettea7b85e62016-01-22 10:14:02 -05002480 final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
2481 final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);
Jeff Browna032cc02011-03-07 16:56:21 -08002482 if (!canViewReceivePointerEvents(child)
2483 || !isTransformedTouchPointInView(x, y, child, null)) {
2484 continue;
2485 }
2486
2487 if (dispatchTransformedGenericPointerEvent(event, child)) {
Chris Craikab008f02014-05-23 17:55:03 -07002488 if (preorderedList != null) preorderedList.clear();
Jeff Browna032cc02011-03-07 16:56:21 -08002489 return true;
2490 }
2491 }
Chris Craikab008f02014-05-23 17:55:03 -07002492 if (preorderedList != null) preorderedList.clear();
Jeff Browna032cc02011-03-07 16:56:21 -08002493 }
2494
2495 // No child handled the event. Send it to this view group.
2496 return super.dispatchGenericPointerEvent(event);
2497 }
2498
Jeff Browna032cc02011-03-07 16:56:21 -08002499 @Override
2500 protected boolean dispatchGenericFocusedEvent(MotionEvent event) {
Jeff Brown33bbfd22011-02-24 20:55:35 -08002501 // Send the event to the focused child or to this view group if it has focus.
Dianne Hackborn4702a852012-08-17 15:18:29 -07002502 if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
2503 == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
Jeff Browna032cc02011-03-07 16:56:21 -08002504 return super.dispatchGenericFocusedEvent(event);
Dianne Hackborn4702a852012-08-17 15:18:29 -07002505 } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
2506 == PFLAG_HAS_BOUNDS) {
Jeff Browncb1404e2011-01-15 18:14:15 -08002507 return mFocused.dispatchGenericMotionEvent(event);
2508 }
2509 return false;
2510 }
2511
2512 /**
Jeff Browna032cc02011-03-07 16:56:21 -08002513 * Dispatches a generic pointer event to a child, taking into account
2514 * transformations that apply to the child.
2515 *
2516 * @param event The event to send.
2517 * @param child The view to send the event to.
2518 * @return {@code true} if the child handled the event.
2519 */
2520 private boolean dispatchTransformedGenericPointerEvent(MotionEvent event, View child) {
Jeff Browna032cc02011-03-07 16:56:21 -08002521 boolean handled;
2522 if (!child.hasIdentityMatrix()) {
Michael Wrighte051f6f2016-05-13 17:44:16 +01002523 MotionEvent transformedEvent = getTransformedMotionEvent(event, child);
Jeff Browna032cc02011-03-07 16:56:21 -08002524 handled = child.dispatchGenericMotionEvent(transformedEvent);
2525 transformedEvent.recycle();
2526 } else {
Michael Wrighte051f6f2016-05-13 17:44:16 +01002527 final float offsetX = mScrollX - child.mLeft;
2528 final float offsetY = mScrollY - child.mTop;
Jeff Browna032cc02011-03-07 16:56:21 -08002529 event.offsetLocation(offsetX, offsetY);
2530 handled = child.dispatchGenericMotionEvent(event);
2531 event.offsetLocation(-offsetX, -offsetY);
2532 }
2533 return handled;
2534 }
2535
Michael Wrighte051f6f2016-05-13 17:44:16 +01002536 /**
2537 * Returns a MotionEvent that's been transformed into the child's local coordinates.
2538 *
2539 * It's the responsibility of the caller to recycle it once they're finished with it.
2540 * @param event The event to transform.
2541 * @param child The view whose coordinate space is to be used.
2542 * @return A copy of the the given MotionEvent, transformed into the given View's coordinate
2543 * space.
2544 */
2545 private MotionEvent getTransformedMotionEvent(MotionEvent event, View child) {
2546 final float offsetX = mScrollX - child.mLeft;
2547 final float offsetY = mScrollY - child.mTop;
2548 final MotionEvent transformedEvent = MotionEvent.obtain(event);
2549 transformedEvent.offsetLocation(offsetX, offsetY);
2550 if (!child.hasIdentityMatrix()) {
2551 transformedEvent.transform(child.getInverseMatrix());
2552 }
2553 return transformedEvent;
2554 }
2555
Jeff Browncb1404e2011-01-15 18:14:15 -08002556 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002557 public boolean dispatchTouchEvent(MotionEvent ev) {
Jeff Brown21bc5c92011-02-28 18:27:14 -08002558 if (mInputEventConsistencyVerifier != null) {
2559 mInputEventConsistencyVerifier.onTouchEvent(ev, 1);
2560 }
2561
Svet Ganov0a2ccee2015-02-06 10:12:32 -08002562 // If the event targets the accessibility focused view and this is it, start
2563 // normal event dispatch. Maybe a descendant is what will handle the click.
Svet Ganovf33fe1f2015-02-06 19:23:31 -08002564 if (ev.isTargetAccessibilityFocus() && isAccessibilityFocusedViewOrHost()) {
Svet Ganov0a2ccee2015-02-06 10:12:32 -08002565 ev.setTargetAccessibilityFocus(false);
2566 }
2567
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002568 boolean handled = false;
2569 if (onFilterTouchEventForSecurity(ev)) {
2570 final int action = ev.getAction();
2571 final int actionMasked = action & MotionEvent.ACTION_MASK;
Jeff Brown85a31762010-09-01 17:01:00 -07002572
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002573 // Handle an initial down.
2574 if (actionMasked == MotionEvent.ACTION_DOWN) {
2575 // Throw away all previous state when starting a new touch gesture.
2576 // The framework may have dropped the up or cancel event for the previous gesture
2577 // due to an app switch, ANR, or some other state change.
2578 cancelAndClearTouchTargets(ev);
2579 resetTouchState();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002580 }
Adam Powellb08013c2010-09-16 16:28:11 -07002581
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002582 // Check for interception.
2583 final boolean intercepted;
Svet Ganovf33fe1f2015-02-06 19:23:31 -08002584 if (actionMasked == MotionEvent.ACTION_DOWN
2585 || mFirstTouchTarget != null) {
2586 final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
2587 if (!disallowIntercept) {
2588 intercepted = onInterceptTouchEvent(ev);
2589 ev.setAction(action); // restore action in case it was changed
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002590 } else {
Svet Ganovf33fe1f2015-02-06 19:23:31 -08002591 intercepted = false;
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002592 }
2593 } else {
Svet Ganovf33fe1f2015-02-06 19:23:31 -08002594 // There are no touch targets and this action is not an initial down
2595 // so this view group continues to intercept touches.
2596 intercepted = true;
2597 }
2598
2599 // If intercepted, start normal event dispatch. Also if there is already
2600 // a view that is handling the gesture, do normal event dispatch.
2601 if (intercepted || mFirstTouchTarget != null) {
2602 ev.setTargetAccessibilityFocus(false);
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002603 }
Jeff Brown20e987b2010-08-23 12:01:02 -07002604
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002605 // Check for cancelation.
2606 final boolean canceled = resetCancelNextUpFlag(this)
2607 || actionMasked == MotionEvent.ACTION_CANCEL;
Jeff Brown20e987b2010-08-23 12:01:02 -07002608
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002609 // Update list of touch targets for pointer down, if needed.
2610 final boolean split = (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) != 0;
2611 TouchTarget newTouchTarget = null;
2612 boolean alreadyDispatchedToNewTouchTarget = false;
2613 if (!canceled && !intercepted) {
Svetoslavc73cfa02015-02-09 17:14:28 -08002614
Phil Weaver1e6ecc62017-11-07 15:28:21 -08002615 // If the event is targeting accessibility focus we give it to the
Svetoslavc73cfa02015-02-09 17:14:28 -08002616 // view that has accessibility focus and if it does not handle it
2617 // we clear the flag and dispatch the event to all children as usual.
2618 // We are looking up the accessibility focused host to avoid keeping
2619 // state since these events are very rare.
2620 View childWithAccessibilityFocus = ev.isTargetAccessibilityFocus()
2621 ? findChildWithAccessibilityFocus() : null;
2622
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002623 if (actionMasked == MotionEvent.ACTION_DOWN
2624 || (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN)
Svet Ganovf33fe1f2015-02-06 19:23:31 -08002625 || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002626 final int actionIndex = ev.getActionIndex(); // always 0 for down
2627 final int idBitsToAssign = split ? 1 << ev.getPointerId(actionIndex)
2628 : TouchTarget.ALL_POINTER_IDS;
Jeff Brown20e987b2010-08-23 12:01:02 -07002629
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002630 // Clean up earlier touch targets for this pointer id in case they
2631 // have become out of sync.
2632 removePointersFromTouchTargets(idBitsToAssign);
2633
2634 final int childrenCount = mChildrenCount;
Chet Haase9c17fe62013-03-22 17:05:55 -07002635 if (newTouchTarget == null && childrenCount != 0) {
Chet Haaseedf6f4b2013-03-26 07:55:30 -07002636 final float x = ev.getX(actionIndex);
2637 final float y = ev.getY(actionIndex);
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002638 // Find a child that can receive the event.
2639 // Scan children from front to back.
Filip Gruszczynskia33bdf32015-11-19 18:22:16 -08002640 final ArrayList<View> preorderedList = buildTouchDispatchChildList();
Chris Craikab008f02014-05-23 17:55:03 -07002641 final boolean customOrder = preorderedList == null
2642 && isChildrenDrawingOrderEnabled();
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002643 final View[] children = mChildren;
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002644 for (int i = childrenCount - 1; i >= 0; i--) {
Alan Viverettea7b85e62016-01-22 10:14:02 -05002645 final int childIndex = getAndVerifyPreorderedIndex(
2646 childrenCount, i, customOrder);
2647 final View child = getAndVerifyPreorderedView(
2648 preorderedList, children, childIndex);
Svetoslavc73cfa02015-02-09 17:14:28 -08002649
2650 // If there is a view that has accessibility focus we want it
2651 // to get the event first and if not handled we will perform a
2652 // normal dispatch. We may do a double iteration but this is
2653 // safer given the timeframe.
2654 if (childWithAccessibilityFocus != null) {
2655 if (childWithAccessibilityFocus != child) {
2656 continue;
2657 }
2658 childWithAccessibilityFocus = null;
2659 i = childrenCount - 1;
2660 }
2661
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002662 if (!canViewReceivePointerEvents(child)
2663 || !isTransformedTouchPointInView(x, y, child, null)) {
Svetoslavc73cfa02015-02-09 17:14:28 -08002664 ev.setTargetAccessibilityFocus(false);
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002665 continue;
2666 }
2667
2668 newTouchTarget = getTouchTarget(child);
2669 if (newTouchTarget != null) {
2670 // Child is already receiving touch within its bounds.
2671 // Give it the new pointer in addition to the ones it is handling.
2672 newTouchTarget.pointerIdBits |= idBitsToAssign;
2673 break;
2674 }
2675
2676 resetCancelNextUpFlag(child);
2677 if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
2678 // Child wants to receive touch within its bounds.
2679 mLastTouchDownTime = ev.getDownTime();
Chris Craikab008f02014-05-23 17:55:03 -07002680 if (preorderedList != null) {
2681 // childIndex points into presorted list, find original index
2682 for (int j = 0; j < childrenCount; j++) {
2683 if (children[childIndex] == mChildren[j]) {
2684 mLastTouchDownIndex = j;
2685 break;
2686 }
2687 }
2688 } else {
2689 mLastTouchDownIndex = childIndex;
2690 }
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002691 mLastTouchDownX = ev.getX();
2692 mLastTouchDownY = ev.getY();
2693 newTouchTarget = addTouchTarget(child, idBitsToAssign);
2694 alreadyDispatchedToNewTouchTarget = true;
2695 break;
2696 }
Svetoslavc73cfa02015-02-09 17:14:28 -08002697
2698 // The accessibility focus didn't handle the event, so clear
2699 // the flag and do a normal dispatch to all children.
2700 ev.setTargetAccessibilityFocus(false);
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002701 }
Chris Craikab008f02014-05-23 17:55:03 -07002702 if (preorderedList != null) preorderedList.clear();
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002703 }
2704
2705 if (newTouchTarget == null && mFirstTouchTarget != null) {
2706 // Did not find a child to receive the event.
2707 // Assign the pointer to the least recently added target.
2708 newTouchTarget = mFirstTouchTarget;
2709 while (newTouchTarget.next != null) {
2710 newTouchTarget = newTouchTarget.next;
2711 }
2712 newTouchTarget.pointerIdBits |= idBitsToAssign;
2713 }
2714 }
2715 }
2716
2717 // Dispatch to touch targets.
2718 if (mFirstTouchTarget == null) {
2719 // No touch targets so treat this as an ordinary view.
2720 handled = dispatchTransformedTouchEvent(ev, canceled, null,
2721 TouchTarget.ALL_POINTER_IDS);
2722 } else {
2723 // Dispatch to touch targets, excluding the new touch target if we already
2724 // dispatched to it. Cancel touch targets if necessary.
2725 TouchTarget predecessor = null;
2726 TouchTarget target = mFirstTouchTarget;
2727 while (target != null) {
2728 final TouchTarget next = target.next;
2729 if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {
2730 handled = true;
2731 } else {
2732 final boolean cancelChild = resetCancelNextUpFlag(target.child)
Chet Haase9c17fe62013-03-22 17:05:55 -07002733 || intercepted;
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002734 if (dispatchTransformedTouchEvent(ev, cancelChild,
2735 target.child, target.pointerIdBits)) {
2736 handled = true;
2737 }
2738 if (cancelChild) {
2739 if (predecessor == null) {
2740 mFirstTouchTarget = next;
2741 } else {
2742 predecessor.next = next;
2743 }
2744 target.recycle();
2745 target = next;
Jeff Brown20e987b2010-08-23 12:01:02 -07002746 continue;
2747 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002748 }
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002749 predecessor = target;
2750 target = next;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002751 }
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002752 }
Jeff Brown20e987b2010-08-23 12:01:02 -07002753
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002754 // Update list of touch targets for pointer up or cancel, if needed.
2755 if (canceled
2756 || actionMasked == MotionEvent.ACTION_UP
2757 || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
2758 resetTouchState();
2759 } else if (split && actionMasked == MotionEvent.ACTION_POINTER_UP) {
2760 final int actionIndex = ev.getActionIndex();
2761 final int idBitsToRemove = 1 << ev.getPointerId(actionIndex);
2762 removePointersFromTouchTargets(idBitsToRemove);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002763 }
2764 }
Romain Guy8506ab42009-06-11 17:35:47 -07002765
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002766 if (!handled && mInputEventConsistencyVerifier != null) {
2767 mInputEventConsistencyVerifier.onUnhandledEvent(ev, 1);
Jeff Brown20e987b2010-08-23 12:01:02 -07002768 }
Jeff Brown20e987b2010-08-23 12:01:02 -07002769 return handled;
2770 }
2771
Romain Guy469b1db2010-10-05 11:49:57 -07002772 /**
Filip Gruszczynskia33bdf32015-11-19 18:22:16 -08002773 * Provide custom ordering of views in which the touch will be dispatched.
2774 *
2775 * This is called within a tight loop, so you are not allowed to allocate objects, including
2776 * the return array. Instead, you should return a pre-allocated list that will be cleared
2777 * after the dispatch is finished.
2778 * @hide
2779 */
2780 public ArrayList<View> buildTouchDispatchChildList() {
2781 return buildOrderedChildList();
2782 }
2783
2784 /**
Svetoslavc73cfa02015-02-09 17:14:28 -08002785 * Finds the child which has accessibility focus.
2786 *
2787 * @return The child that has focus.
2788 */
2789 private View findChildWithAccessibilityFocus() {
2790 ViewRootImpl viewRoot = getViewRootImpl();
2791 if (viewRoot == null) {
2792 return null;
2793 }
2794
2795 View current = viewRoot.getAccessibilityFocusedHost();
2796 if (current == null) {
2797 return null;
2798 }
2799
2800 ViewParent parent = current.getParent();
2801 while (parent instanceof View) {
2802 if (parent == this) {
2803 return current;
2804 }
2805 current = (View) parent;
2806 parent = current.getParent();
2807 }
2808
2809 return null;
2810 }
2811
2812 /**
Romain Guy469b1db2010-10-05 11:49:57 -07002813 * Resets all touch state in preparation for a new cycle.
2814 */
2815 private void resetTouchState() {
Jeff Brown20e987b2010-08-23 12:01:02 -07002816 clearTouchTargets();
2817 resetCancelNextUpFlag(this);
2818 mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
Adam Powell10ba2772014-04-15 09:46:51 -07002819 mNestedScrollAxes = SCROLL_AXIS_NONE;
Jeff Brown20e987b2010-08-23 12:01:02 -07002820 }
2821
Romain Guy469b1db2010-10-05 11:49:57 -07002822 /**
2823 * Resets the cancel next up flag.
2824 * Returns true if the flag was previously set.
2825 */
Alan Viverettea7b85e62016-01-22 10:14:02 -05002826 private static boolean resetCancelNextUpFlag(@NonNull View view) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07002827 if ((view.mPrivateFlags & PFLAG_CANCEL_NEXT_UP_EVENT) != 0) {
2828 view.mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT;
Jeff Brown20e987b2010-08-23 12:01:02 -07002829 return true;
Adam Cohen9b073942010-08-19 16:49:52 -07002830 }
2831 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002832 }
2833
Romain Guy469b1db2010-10-05 11:49:57 -07002834 /**
2835 * Clears all touch targets.
2836 */
2837 private void clearTouchTargets() {
Jeff Brown20e987b2010-08-23 12:01:02 -07002838 TouchTarget target = mFirstTouchTarget;
2839 if (target != null) {
2840 do {
2841 TouchTarget next = target.next;
2842 target.recycle();
2843 target = next;
2844 } while (target != null);
2845 mFirstTouchTarget = null;
2846 }
2847 }
2848
Romain Guy469b1db2010-10-05 11:49:57 -07002849 /**
2850 * Cancels and clears all touch targets.
2851 */
2852 private void cancelAndClearTouchTargets(MotionEvent event) {
Jeff Brown20e987b2010-08-23 12:01:02 -07002853 if (mFirstTouchTarget != null) {
2854 boolean syntheticEvent = false;
2855 if (event == null) {
2856 final long now = SystemClock.uptimeMillis();
2857 event = MotionEvent.obtain(now, now,
2858 MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
Jeff Brown2fdbc5a2011-06-30 12:25:54 -07002859 event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
Jeff Brown20e987b2010-08-23 12:01:02 -07002860 syntheticEvent = true;
2861 }
2862
2863 for (TouchTarget target = mFirstTouchTarget; target != null; target = target.next) {
2864 resetCancelNextUpFlag(target.child);
2865 dispatchTransformedTouchEvent(event, true, target.child, target.pointerIdBits);
2866 }
2867 clearTouchTargets();
2868
2869 if (syntheticEvent) {
2870 event.recycle();
2871 }
2872 }
2873 }
2874
Romain Guy469b1db2010-10-05 11:49:57 -07002875 /**
2876 * Gets the touch target for specified child view.
2877 * Returns null if not found.
2878 */
Alan Viverettea7b85e62016-01-22 10:14:02 -05002879 private TouchTarget getTouchTarget(@NonNull View child) {
Jeff Brown20e987b2010-08-23 12:01:02 -07002880 for (TouchTarget target = mFirstTouchTarget; target != null; target = target.next) {
2881 if (target.child == child) {
2882 return target;
2883 }
2884 }
2885 return null;
2886 }
2887
Romain Guy469b1db2010-10-05 11:49:57 -07002888 /**
2889 * Adds a touch target for specified child to the beginning of the list.
2890 * Assumes the target child is not already present.
2891 */
Alan Viverettea7b85e62016-01-22 10:14:02 -05002892 private TouchTarget addTouchTarget(@NonNull View child, int pointerIdBits) {
2893 final TouchTarget target = TouchTarget.obtain(child, pointerIdBits);
Jeff Brown20e987b2010-08-23 12:01:02 -07002894 target.next = mFirstTouchTarget;
2895 mFirstTouchTarget = target;
2896 return target;
2897 }
2898
Romain Guy469b1db2010-10-05 11:49:57 -07002899 /**
2900 * Removes the pointer ids from consideration.
2901 */
2902 private void removePointersFromTouchTargets(int pointerIdBits) {
Jeff Brown20e987b2010-08-23 12:01:02 -07002903 TouchTarget predecessor = null;
2904 TouchTarget target = mFirstTouchTarget;
2905 while (target != null) {
2906 final TouchTarget next = target.next;
2907 if ((target.pointerIdBits & pointerIdBits) != 0) {
2908 target.pointerIdBits &= ~pointerIdBits;
2909 if (target.pointerIdBits == 0) {
2910 if (predecessor == null) {
2911 mFirstTouchTarget = next;
2912 } else {
2913 predecessor.next = next;
2914 }
2915 target.recycle();
2916 target = next;
2917 continue;
2918 }
2919 }
2920 predecessor = target;
2921 target = next;
2922 }
2923 }
2924
Mathew Inwoode5ad5982018-08-17 15:07:52 +01002925 @UnsupportedAppUsage
Jeff Brown59a422e2012-04-19 15:19:19 -07002926 private void cancelTouchTarget(View view) {
2927 TouchTarget predecessor = null;
2928 TouchTarget target = mFirstTouchTarget;
2929 while (target != null) {
2930 final TouchTarget next = target.next;
2931 if (target.child == view) {
2932 if (predecessor == null) {
2933 mFirstTouchTarget = next;
2934 } else {
2935 predecessor.next = next;
2936 }
2937 target.recycle();
2938
2939 final long now = SystemClock.uptimeMillis();
2940 MotionEvent event = MotionEvent.obtain(now, now,
2941 MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
2942 event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
2943 view.dispatchTouchEvent(event);
2944 event.recycle();
2945 return;
2946 }
2947 predecessor = target;
2948 target = next;
2949 }
2950 }
2951
Romain Guy469b1db2010-10-05 11:49:57 -07002952 /**
Jeff Browna032cc02011-03-07 16:56:21 -08002953 * Returns true if a child view can receive pointer events.
2954 * @hide
2955 */
Alan Viverettea7b85e62016-01-22 10:14:02 -05002956 private static boolean canViewReceivePointerEvents(@NonNull View child) {
Jeff Browna032cc02011-03-07 16:56:21 -08002957 return (child.mViewFlags & VISIBILITY_MASK) == VISIBLE
2958 || child.getAnimation() != null;
2959 }
2960
Alan Viveretteb942b6f2014-12-08 10:37:39 -08002961 private float[] getTempPoint() {
2962 if (mTempPoint == null) {
2963 mTempPoint = new float[2];
2964 }
2965 return mTempPoint;
2966 }
2967
Jeff Browna032cc02011-03-07 16:56:21 -08002968 /**
Romain Guy469b1db2010-10-05 11:49:57 -07002969 * Returns true if a child view contains the specified point when transformed
Jeff Brown20e987b2010-08-23 12:01:02 -07002970 * into its coordinate space.
Romain Guy469b1db2010-10-05 11:49:57 -07002971 * Child must not be null.
Adam Cohena32edd42010-10-26 10:35:01 -07002972 * @hide
Romain Guy469b1db2010-10-05 11:49:57 -07002973 */
Mathew Inwoode5ad5982018-08-17 15:07:52 +01002974 @UnsupportedAppUsage
Adam Cohena32edd42010-10-26 10:35:01 -07002975 protected boolean isTransformedTouchPointInView(float x, float y, View child,
Christopher Tate2c095f32010-10-04 14:13:40 -07002976 PointF outLocalPoint) {
Alan Viveretteb942b6f2014-12-08 10:37:39 -08002977 final float[] point = getTempPoint();
2978 point[0] = x;
2979 point[1] = y;
2980 transformPointToViewLocal(point, child);
2981 final boolean isInView = child.pointInView(point[0], point[1]);
Christopher Tate2c095f32010-10-04 14:13:40 -07002982 if (isInView && outLocalPoint != null) {
Alan Viveretteb942b6f2014-12-08 10:37:39 -08002983 outLocalPoint.set(point[0], point[1]);
Christopher Tate2c095f32010-10-04 14:13:40 -07002984 }
2985 return isInView;
Adam Powell2b342f02010-08-18 18:14:13 -07002986 }
2987
Romain Guy469b1db2010-10-05 11:49:57 -07002988 /**
Alan Viveretteb942b6f2014-12-08 10:37:39 -08002989 * @hide
2990 */
Mathew Inwoode5ad5982018-08-17 15:07:52 +01002991 @UnsupportedAppUsage
Alan Viveretteb942b6f2014-12-08 10:37:39 -08002992 public void transformPointToViewLocal(float[] point, View child) {
2993 point[0] += mScrollX - child.mLeft;
2994 point[1] += mScrollY - child.mTop;
2995
2996 if (!child.hasIdentityMatrix()) {
2997 child.getInverseMatrix().mapPoints(point);
2998 }
2999 }
3000
3001 /**
Romain Guy469b1db2010-10-05 11:49:57 -07003002 * Transforms a motion event into the coordinate space of a particular child view,
Jeff Brown20e987b2010-08-23 12:01:02 -07003003 * filters out irrelevant pointer ids, and overrides its action if necessary.
Romain Guy469b1db2010-10-05 11:49:57 -07003004 * If child is null, assumes the MotionEvent will be sent to this ViewGroup instead.
3005 */
3006 private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,
Jeff Brown20e987b2010-08-23 12:01:02 -07003007 View child, int desiredPointerIdBits) {
3008 final boolean handled;
Adam Powell2b342f02010-08-18 18:14:13 -07003009
Jeff Brown20e987b2010-08-23 12:01:02 -07003010 // Canceling motions is a special case. We don't need to perform any transformations
3011 // or filtering. The important part is the action, not the contents.
3012 final int oldAction = event.getAction();
3013 if (cancel || oldAction == MotionEvent.ACTION_CANCEL) {
3014 event.setAction(MotionEvent.ACTION_CANCEL);
3015 if (child == null) {
3016 handled = super.dispatchTouchEvent(event);
3017 } else {
3018 handled = child.dispatchTouchEvent(event);
3019 }
3020 event.setAction(oldAction);
3021 return handled;
3022 }
Adam Powell2b342f02010-08-18 18:14:13 -07003023
Jeff Brown20e987b2010-08-23 12:01:02 -07003024 // Calculate the number of pointers to deliver.
Jeff Brownfe9f8ab2011-05-06 18:20:01 -07003025 final int oldPointerIdBits = event.getPointerIdBits();
3026 final int newPointerIdBits = oldPointerIdBits & desiredPointerIdBits;
Adam Powell2b342f02010-08-18 18:14:13 -07003027
Jeff Brown20e987b2010-08-23 12:01:02 -07003028 // If for some reason we ended up in an inconsistent state where it looks like we
3029 // might produce a motion event with no pointers in it, then drop the event.
Jeff Brownfe9f8ab2011-05-06 18:20:01 -07003030 if (newPointerIdBits == 0) {
Jeff Brown20e987b2010-08-23 12:01:02 -07003031 return false;
3032 }
Adam Powell2b342f02010-08-18 18:14:13 -07003033
Jeff Brown20e987b2010-08-23 12:01:02 -07003034 // If the number of pointers is the same and we don't need to perform any fancy
3035 // irreversible transformations, then we can reuse the motion event for this
3036 // dispatch as long as we are careful to revert any changes we make.
Jeff Brownfe9f8ab2011-05-06 18:20:01 -07003037 // Otherwise we need to make a copy.
3038 final MotionEvent transformedEvent;
3039 if (newPointerIdBits == oldPointerIdBits) {
3040 if (child == null || child.hasIdentityMatrix()) {
3041 if (child == null) {
3042 handled = super.dispatchTouchEvent(event);
3043 } else {
3044 final float offsetX = mScrollX - child.mLeft;
3045 final float offsetY = mScrollY - child.mTop;
3046 event.offsetLocation(offsetX, offsetY);
Adam Powell2b342f02010-08-18 18:14:13 -07003047
Jeff Brownfe9f8ab2011-05-06 18:20:01 -07003048 handled = child.dispatchTouchEvent(event);
Jeff Brown20e987b2010-08-23 12:01:02 -07003049
Jeff Brownfe9f8ab2011-05-06 18:20:01 -07003050 event.offsetLocation(-offsetX, -offsetY);
3051 }
3052 return handled;
Jeff Brown20e987b2010-08-23 12:01:02 -07003053 }
Jeff Brown20e987b2010-08-23 12:01:02 -07003054 transformedEvent = MotionEvent.obtain(event);
3055 } else {
Jeff Brownfe9f8ab2011-05-06 18:20:01 -07003056 transformedEvent = event.split(newPointerIdBits);
Adam Powell2b342f02010-08-18 18:14:13 -07003057 }
3058
Jeff Brown20e987b2010-08-23 12:01:02 -07003059 // Perform any necessary transformations and dispatch.
3060 if (child == null) {
3061 handled = super.dispatchTouchEvent(transformedEvent);
3062 } else {
3063 final float offsetX = mScrollX - child.mLeft;
3064 final float offsetY = mScrollY - child.mTop;
3065 transformedEvent.offsetLocation(offsetX, offsetY);
3066 if (! child.hasIdentityMatrix()) {
3067 transformedEvent.transform(child.getInverseMatrix());
Adam Powell2b342f02010-08-18 18:14:13 -07003068 }
3069
Jeff Brown20e987b2010-08-23 12:01:02 -07003070 handled = child.dispatchTouchEvent(transformedEvent);
Adam Powell2b342f02010-08-18 18:14:13 -07003071 }
3072
Jeff Brown20e987b2010-08-23 12:01:02 -07003073 // Done.
3074 transformedEvent.recycle();
Adam Powell2b342f02010-08-18 18:14:13 -07003075 return handled;
3076 }
3077
Romain Guy469b1db2010-10-05 11:49:57 -07003078 /**
Adam Powell2b342f02010-08-18 18:14:13 -07003079 * Enable or disable the splitting of MotionEvents to multiple children during touch event
Jeff Brown995e7742010-12-22 16:59:36 -08003080 * dispatch. This behavior is enabled by default for applications that target an
3081 * SDK version of {@link Build.VERSION_CODES#HONEYCOMB} or newer.
Adam Powell2b342f02010-08-18 18:14:13 -07003082 *
3083 * <p>When this option is enabled MotionEvents may be split and dispatched to different child
3084 * views depending on where each pointer initially went down. This allows for user interactions
3085 * such as scrolling two panes of content independently, chording of buttons, and performing
3086 * independent gestures on different pieces of content.
3087 *
3088 * @param split <code>true</code> to allow MotionEvents to be split and dispatched to multiple
3089 * child views. <code>false</code> to only allow one child view to be the target of
3090 * any MotionEvent received by this ViewGroup.
Scott Main27a85082013-06-10 10:39:48 -07003091 * @attr ref android.R.styleable#ViewGroup_splitMotionEvents
Adam Powell2b342f02010-08-18 18:14:13 -07003092 */
3093 public void setMotionEventSplittingEnabled(boolean split) {
3094 // TODO Applications really shouldn't change this setting mid-touch event,
3095 // but perhaps this should handle that case and send ACTION_CANCELs to any child views
3096 // with gestures in progress when this is changed.
3097 if (split) {
Adam Powell2b342f02010-08-18 18:14:13 -07003098 mGroupFlags |= FLAG_SPLIT_MOTION_EVENTS;
3099 } else {
3100 mGroupFlags &= ~FLAG_SPLIT_MOTION_EVENTS;
Adam Powell2b342f02010-08-18 18:14:13 -07003101 }
3102 }
3103
3104 /**
Jeff Brown995e7742010-12-22 16:59:36 -08003105 * Returns true if MotionEvents dispatched to this ViewGroup can be split to multiple children.
Adam Powell2b342f02010-08-18 18:14:13 -07003106 * @return true if MotionEvents dispatched to this ViewGroup can be split to multiple children.
3107 */
3108 public boolean isMotionEventSplittingEnabled() {
3109 return (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) == FLAG_SPLIT_MOTION_EVENTS;
3110 }
3111
3112 /**
George Mount0a778ed2013-12-13 13:35:36 -08003113 * Returns true if this ViewGroup should be considered as a single entity for removal
3114 * when executing an Activity transition. If this is false, child elements will move
3115 * individually during the transition.
George Mount427c6412014-11-05 16:45:36 -08003116 *
George Mount0a778ed2013-12-13 13:35:36 -08003117 * @return True if the ViewGroup should be acted on together during an Activity transition.
George Mount427c6412014-11-05 16:45:36 -08003118 * The default value is true when there is a non-null background or if
3119 * {@link #getTransitionName()} is not null or if a
3120 * non-null {@link android.view.ViewOutlineProvider} other than
3121 * {@link android.view.ViewOutlineProvider#BACKGROUND} was given to
3122 * {@link #setOutlineProvider(ViewOutlineProvider)} and false otherwise.
George Mount0a778ed2013-12-13 13:35:36 -08003123 */
3124 public boolean isTransitionGroup() {
3125 if ((mGroupFlags & FLAG_IS_TRANSITION_GROUP_SET) != 0) {
3126 return ((mGroupFlags & FLAG_IS_TRANSITION_GROUP) != 0);
3127 } else {
George Mount427c6412014-11-05 16:45:36 -08003128 final ViewOutlineProvider outlineProvider = getOutlineProvider();
3129 return getBackground() != null || getTransitionName() != null ||
3130 (outlineProvider != null && outlineProvider != ViewOutlineProvider.BACKGROUND);
George Mount0a778ed2013-12-13 13:35:36 -08003131 }
3132 }
3133
3134 /**
3135 * Changes whether or not this ViewGroup should be treated as a single entity during
George Mount31a21722014-03-24 17:44:36 -07003136 * Activity Transitions.
George Mount0a778ed2013-12-13 13:35:36 -08003137 * @param isTransitionGroup Whether or not the ViewGroup should be treated as a unit
3138 * in Activity transitions. If false, the ViewGroup won't transition,
3139 * only its children. If true, the entire ViewGroup will transition
3140 * together.
George Mount62ab9b72014-05-02 13:51:17 -07003141 * @see android.app.ActivityOptions#makeSceneTransitionAnimation(android.app.Activity,
3142 * android.util.Pair[])
George Mount0a778ed2013-12-13 13:35:36 -08003143 */
3144 public void setTransitionGroup(boolean isTransitionGroup) {
3145 mGroupFlags |= FLAG_IS_TRANSITION_GROUP_SET;
3146 if (isTransitionGroup) {
3147 mGroupFlags |= FLAG_IS_TRANSITION_GROUP;
3148 } else {
3149 mGroupFlags &= ~FLAG_IS_TRANSITION_GROUP;
3150 }
3151 }
3152
Alan Viverettebe463f22016-01-21 10:50:10 -05003153 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003154 public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
Romain Guy8506ab42009-06-11 17:35:47 -07003155
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003156 if (disallowIntercept == ((mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0)) {
3157 // We're already in this state, assume our ancestors are too
3158 return;
3159 }
Romain Guy8506ab42009-06-11 17:35:47 -07003160
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003161 if (disallowIntercept) {
3162 mGroupFlags |= FLAG_DISALLOW_INTERCEPT;
3163 } else {
3164 mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
3165 }
Romain Guy8506ab42009-06-11 17:35:47 -07003166
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003167 // Pass it up to our parent
3168 if (mParent != null) {
3169 mParent.requestDisallowInterceptTouchEvent(disallowIntercept);
3170 }
3171 }
3172
3173 /**
3174 * Implement this method to intercept all touch screen motion events. This
3175 * allows you to watch events as they are dispatched to your children, and
3176 * take ownership of the current gesture at any point.
3177 *
3178 * <p>Using this function takes some care, as it has a fairly complicated
3179 * interaction with {@link View#onTouchEvent(MotionEvent)
3180 * View.onTouchEvent(MotionEvent)}, and using it requires implementing
3181 * that method as well as this one in the correct way. Events will be
3182 * received in the following order:
3183 *
3184 * <ol>
3185 * <li> You will receive the down event here.
3186 * <li> The down event will be handled either by a child of this view
3187 * group, or given to your own onTouchEvent() method to handle; this means
3188 * you should implement onTouchEvent() to return true, so you will
3189 * continue to see the rest of the gesture (instead of looking for
3190 * a parent view to handle it). Also, by returning true from
3191 * onTouchEvent(), you will not receive any following
3192 * events in onInterceptTouchEvent() and all touch processing must
3193 * happen in onTouchEvent() like normal.
3194 * <li> For as long as you return false from this function, each following
3195 * event (up to and including the final up) will be delivered first here
3196 * and then to the target's onTouchEvent().
3197 * <li> If you return true from here, you will not receive any
3198 * following events: the target view will receive the same event but
3199 * with the action {@link MotionEvent#ACTION_CANCEL}, and all further
3200 * events will be delivered to your onTouchEvent() method and no longer
3201 * appear here.
3202 * </ol>
3203 *
3204 * @param ev The motion event being dispatched down the hierarchy.
3205 * @return Return true to steal motion events from the children and have
3206 * them dispatched to this ViewGroup through onTouchEvent().
3207 * The current target will receive an ACTION_CANCEL event, and no further
3208 * messages will be delivered here.
3209 */
3210 public boolean onInterceptTouchEvent(MotionEvent ev) {
Keisuke Kuroyanagid85bc502016-01-21 14:50:38 +09003211 if (ev.isFromSource(InputDevice.SOURCE_MOUSE)
3212 && ev.getAction() == MotionEvent.ACTION_DOWN
3213 && ev.isButtonPressed(MotionEvent.BUTTON_PRIMARY)
3214 && isOnScrollbarThumb(ev.getX(), ev.getY())) {
3215 return true;
3216 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003217 return false;
3218 }
3219
3220 /**
3221 * {@inheritDoc}
3222 *
3223 * Looks for a view to give focus to respecting the setting specified by
3224 * {@link #getDescendantFocusability()}.
3225 *
3226 * Uses {@link #onRequestFocusInDescendants(int, android.graphics.Rect)} to
3227 * find focus within the children of this group when appropriate.
3228 *
3229 * @see #FOCUS_BEFORE_DESCENDANTS
3230 * @see #FOCUS_AFTER_DESCENDANTS
3231 * @see #FOCUS_BLOCK_DESCENDANTS
Filip Gruszczynskia33bdf32015-11-19 18:22:16 -08003232 * @see #onRequestFocusInDescendants(int, android.graphics.Rect)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003233 */
3234 @Override
3235 public boolean requestFocus(int direction, Rect previouslyFocusedRect) {
3236 if (DBG) {
3237 System.out.println(this + " ViewGroup.requestFocus direction="
3238 + direction);
3239 }
3240 int descendantFocusability = getDescendantFocusability();
3241
Evan Rosky5db64eb2017-11-20 23:04:46 +00003242 boolean result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003243 switch (descendantFocusability) {
3244 case FOCUS_BLOCK_DESCENDANTS:
Evan Rosky5db64eb2017-11-20 23:04:46 +00003245 result = super.requestFocus(direction, previouslyFocusedRect);
3246 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003247 case FOCUS_BEFORE_DESCENDANTS: {
3248 final boolean took = super.requestFocus(direction, previouslyFocusedRect);
Evan Rosky5db64eb2017-11-20 23:04:46 +00003249 result = took ? took : onRequestFocusInDescendants(direction,
3250 previouslyFocusedRect);
3251 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003252 }
3253 case FOCUS_AFTER_DESCENDANTS: {
3254 final boolean took = onRequestFocusInDescendants(direction, previouslyFocusedRect);
Evan Rosky5db64eb2017-11-20 23:04:46 +00003255 result = took ? took : super.requestFocus(direction, previouslyFocusedRect);
3256 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003257 }
3258 default:
3259 throw new IllegalStateException("descendant focusability must be "
3260 + "one of FOCUS_BEFORE_DESCENDANTS, FOCUS_AFTER_DESCENDANTS, FOCUS_BLOCK_DESCENDANTS "
3261 + "but is " + descendantFocusability);
3262 }
Evan Rosky5db64eb2017-11-20 23:04:46 +00003263 if (result && !isLayoutValid() && ((mPrivateFlags & PFLAG_WANTS_FOCUS) == 0)) {
3264 mPrivateFlags |= PFLAG_WANTS_FOCUS;
3265 }
3266 return result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003267 }
3268
3269 /**
3270 * Look for a descendant to call {@link View#requestFocus} on.
3271 * Called by {@link ViewGroup#requestFocus(int, android.graphics.Rect)}
3272 * when it wants to request focus within its children. Override this to
3273 * customize how your {@link ViewGroup} requests focus within its children.
3274 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT
3275 * @param previouslyFocusedRect The rectangle (in this View's coordinate system)
3276 * to give a finer grained hint about where focus is coming from. May be null
3277 * if there is no hint.
3278 * @return Whether focus was taken.
3279 */
3280 @SuppressWarnings({"ConstantConditions"})
3281 protected boolean onRequestFocusInDescendants(int direction,
3282 Rect previouslyFocusedRect) {
3283 int index;
3284 int increment;
3285 int end;
3286 int count = mChildrenCount;
3287 if ((direction & FOCUS_FORWARD) != 0) {
3288 index = 0;
3289 increment = 1;
3290 end = count;
3291 } else {
3292 index = count - 1;
3293 increment = -1;
3294 end = -1;
3295 }
3296 final View[] children = mChildren;
3297 for (int i = index; i != end; i += increment) {
3298 View child = children[i];
Vadim Tryshevb5ced222017-01-17 19:31:35 -08003299 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003300 if (child.requestFocus(direction, previouslyFocusedRect)) {
3301 return true;
3302 }
3303 }
3304 }
3305 return false;
3306 }
Chet Haase5c13d892010-10-08 08:37:55 -07003307
Vadim Tryshev01d8c492016-12-15 11:33:15 -08003308 @Override
Evan Rosky53fcf112017-01-26 14:37:55 -08003309 public boolean restoreDefaultFocus() {
3310 if (mDefaultFocus != null
Vadim Tryshev01d8c492016-12-15 11:33:15 -08003311 && getDescendantFocusability() != FOCUS_BLOCK_DESCENDANTS
Vadim Tryshev5ca73982017-01-04 17:24:43 -08003312 && (mDefaultFocus.mViewFlags & VISIBILITY_MASK) == VISIBLE
Evan Rosky53fcf112017-01-26 14:37:55 -08003313 && mDefaultFocus.restoreDefaultFocus()) {
Vadim Tryshev01d8c492016-12-15 11:33:15 -08003314 return true;
3315 }
Evan Rosky53fcf112017-01-26 14:37:55 -08003316 return super.restoreDefaultFocus();
3317 }
3318
3319 /**
3320 * @hide
3321 */
Evan Rosky3ac64632017-02-13 18:04:43 -08003322 @TestApi
Evan Rosky53fcf112017-01-26 14:37:55 -08003323 @Override
3324 public boolean restoreFocusInCluster(@FocusRealDirection int direction) {
Evan Rosky18b886e2017-02-15 13:26:51 -08003325 // Allow cluster-navigation to enter touchscreenBlocksFocus ViewGroups.
3326 if (isKeyboardNavigationCluster()) {
3327 final boolean blockedFocus = getTouchscreenBlocksFocus();
3328 try {
3329 setTouchscreenBlocksFocusNoRefocus(false);
3330 return restoreFocusInClusterInternal(direction);
3331 } finally {
3332 setTouchscreenBlocksFocusNoRefocus(blockedFocus);
3333 }
3334 } else {
3335 return restoreFocusInClusterInternal(direction);
3336 }
3337 }
3338
3339 private boolean restoreFocusInClusterInternal(@FocusRealDirection int direction) {
Evan Rosky0e8a6832017-04-10 12:35:15 -07003340 if (mFocusedInCluster != null && getDescendantFocusability() != FOCUS_BLOCK_DESCENDANTS
Evan Rosky53fcf112017-01-26 14:37:55 -08003341 && (mFocusedInCluster.mViewFlags & VISIBILITY_MASK) == VISIBLE
3342 && mFocusedInCluster.restoreFocusInCluster(direction)) {
3343 return true;
3344 }
3345 return super.restoreFocusInCluster(direction);
Vadim Tryshev01d8c492016-12-15 11:33:15 -08003346 }
3347
Romain Guya440b002010-02-24 15:57:54 -08003348 /**
Evan Rosky3ac64632017-02-13 18:04:43 -08003349 * @hide
3350 */
3351 @Override
3352 public boolean restoreFocusNotInCluster() {
3353 if (mFocusedInCluster != null) {
3354 // since clusters don't nest; we can assume that a non-null mFocusedInCluster
3355 // will refer to a view not-in a cluster.
3356 return restoreFocusInCluster(View.FOCUS_DOWN);
3357 }
Evan Rosky2ae1bf52017-05-11 11:18:45 -07003358 if (isKeyboardNavigationCluster() || (mViewFlags & VISIBILITY_MASK) != VISIBLE) {
Evan Rosky3ac64632017-02-13 18:04:43 -08003359 return false;
3360 }
3361 int descendentFocusability = getDescendantFocusability();
3362 if (descendentFocusability == FOCUS_BLOCK_DESCENDANTS) {
3363 return super.requestFocus(FOCUS_DOWN, null);
3364 }
3365 if (descendentFocusability == FOCUS_BEFORE_DESCENDANTS
3366 && super.requestFocus(FOCUS_DOWN, null)) {
3367 return true;
3368 }
3369 for (int i = 0; i < mChildrenCount; ++i) {
3370 View child = mChildren[i];
3371 if (!child.isKeyboardNavigationCluster()
3372 && child.restoreFocusNotInCluster()) {
3373 return true;
3374 }
3375 }
Evan Rosky2ae1bf52017-05-11 11:18:45 -07003376 if (descendentFocusability == FOCUS_AFTER_DESCENDANTS && !hasFocusableChild(false)) {
Evan Rosky3ac64632017-02-13 18:04:43 -08003377 return super.requestFocus(FOCUS_DOWN, null);
3378 }
3379 return false;
3380 }
3381
3382 /**
Romain Guya440b002010-02-24 15:57:54 -08003383 * {@inheritDoc}
Chet Haase5c13d892010-10-08 08:37:55 -07003384 *
Romain Guydcc490f2010-02-24 17:59:35 -08003385 * @hide
Romain Guya440b002010-02-24 15:57:54 -08003386 */
3387 @Override
3388 public void dispatchStartTemporaryDetach() {
3389 super.dispatchStartTemporaryDetach();
3390 final int count = mChildrenCount;
3391 final View[] children = mChildren;
3392 for (int i = 0; i < count; i++) {
3393 children[i].dispatchStartTemporaryDetach();
3394 }
3395 }
Chet Haase5c13d892010-10-08 08:37:55 -07003396
Romain Guya440b002010-02-24 15:57:54 -08003397 /**
3398 * {@inheritDoc}
Chet Haase5c13d892010-10-08 08:37:55 -07003399 *
Romain Guydcc490f2010-02-24 17:59:35 -08003400 * @hide
Romain Guya440b002010-02-24 15:57:54 -08003401 */
3402 @Override
3403 public void dispatchFinishTemporaryDetach() {
3404 super.dispatchFinishTemporaryDetach();
3405 final int count = mChildrenCount;
3406 final View[] children = mChildren;
3407 for (int i = 0; i < count; i++) {
3408 children[i].dispatchFinishTemporaryDetach();
3409 }
3410 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003411
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003412 @Override
Mathew Inwoode5ad5982018-08-17 15:07:52 +01003413 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003414 void dispatchAttachedToWindow(AttachInfo info, int visibility) {
Adam Powell4b867882011-09-16 12:59:46 -07003415 mGroupFlags |= FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003416 super.dispatchAttachedToWindow(info, visibility);
Adam Powell4b867882011-09-16 12:59:46 -07003417 mGroupFlags &= ~FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW;
3418
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003419 final int count = mChildrenCount;
3420 final View[] children = mChildren;
3421 for (int i = 0; i < count; i++) {
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07003422 final View child = children[i];
3423 child.dispatchAttachedToWindow(info,
Adam Powelleb2b0af2015-05-20 18:26:35 -07003424 combineVisibility(visibility, child.getVisibility()));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003425 }
Chet Haasec633d2f2015-04-07 10:29:39 -07003426 final int transientCount = mTransientIndices == null ? 0 : mTransientIndices.size();
3427 for (int i = 0; i < transientCount; ++i) {
3428 View view = mTransientViews.get(i);
Adam Powelleb2b0af2015-05-20 18:26:35 -07003429 view.dispatchAttachedToWindow(info,
3430 combineVisibility(visibility, view.getVisibility()));
Chet Haasec633d2f2015-04-07 10:29:39 -07003431 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003432 }
3433
svetoslavganov75986cf2009-05-14 22:28:01 -07003434 @Override
Romain Guybb9908b2012-03-08 11:14:07 -08003435 void dispatchScreenStateChanged(int screenState) {
3436 super.dispatchScreenStateChanged(screenState);
3437
3438 final int count = mChildrenCount;
3439 final View[] children = mChildren;
3440 for (int i = 0; i < count; i++) {
3441 children[i].dispatchScreenStateChanged(screenState);
3442 }
3443 }
3444
Andrii Kulianb047b8b2017-02-08 18:38:26 -08003445 @Override
Andrii Kuliane5c58ee2017-03-27 19:25:24 -07003446 void dispatchMovedToDisplay(Display display, Configuration config) {
3447 super.dispatchMovedToDisplay(display, config);
Andrii Kulianb047b8b2017-02-08 18:38:26 -08003448
3449 final int count = mChildrenCount;
3450 final View[] children = mChildren;
3451 for (int i = 0; i < count; i++) {
Andrii Kuliane5c58ee2017-03-27 19:25:24 -07003452 children[i].dispatchMovedToDisplay(display, config);
Andrii Kulianb047b8b2017-02-08 18:38:26 -08003453 }
3454 }
3455
Alan Viverettea54956a2015-01-07 16:05:02 -08003456 /** @hide */
Romain Guybb9908b2012-03-08 11:14:07 -08003457 @Override
Alan Viverettea54956a2015-01-07 16:05:02 -08003458 public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07003459 boolean handled = false;
3460 if (includeForAccessibility()) {
3461 handled = super.dispatchPopulateAccessibilityEventInternal(event);
3462 if (handled) {
3463 return handled;
3464 }
Svetoslav Ganovb84b94e2011-09-22 19:26:56 -07003465 }
Svetoslav Ganov736c2752011-04-22 18:30:36 -07003466 // Let our children have a shot in populating the event.
Svetoslav Ganov42138042012-03-20 11:51:39 -07003467 ChildListForAccessibility children = ChildListForAccessibility.obtain(this, true);
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07003468 try {
3469 final int childCount = children.getChildCount();
3470 for (int i = 0; i < childCount; i++) {
3471 View child = children.getChildAt(i);
3472 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
3473 handled = child.dispatchPopulateAccessibilityEvent(event);
3474 if (handled) {
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07003475 return handled;
3476 }
Svetoslav Ganov6179ea32011-06-28 01:12:41 -07003477 }
Svetoslav Ganov736c2752011-04-22 18:30:36 -07003478 }
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07003479 } finally {
3480 children.recycle();
svetoslavganov75986cf2009-05-14 22:28:01 -07003481 }
Svetoslav Ganov736c2752011-04-22 18:30:36 -07003482 return false;
svetoslavganov75986cf2009-05-14 22:28:01 -07003483 }
3484
Dianne Hackborn6251f0d2015-04-01 16:45:03 -07003485 /**
Felipe Leme6d553872016-12-08 17:13:25 -08003486 * Dispatch creation of {@link ViewStructure} down the hierarchy. This implementation
3487 * adds in all child views of the view group, in addition to calling the default View
3488 * implementation.
3489 */
3490 @Override
3491 public void dispatchProvideStructure(ViewStructure structure) {
3492 super.dispatchProvideStructure(structure);
Svet Ganov2f8fb1f2017-03-13 00:21:04 -07003493 if (isAssistBlocked() || structure.getChildCount() != 0) {
3494 return;
3495 }
3496 final int childrenCount = mChildrenCount;
3497 if (childrenCount <= 0) {
3498 return;
3499 }
Philip P. Moltmann083d8aa2017-08-15 15:22:37 -07003500
3501 if (!isLaidOut()) {
Felipe Lemefe05a522018-01-23 15:57:49 -08003502 if (Helper.sVerbose) {
3503 Log.v(VIEW_LOG_TAG, "dispatchProvideStructure(): not laid out, ignoring "
3504 + childrenCount + " children of " + getAccessibilityViewId());
3505 }
Philip P. Moltmann083d8aa2017-08-15 15:22:37 -07003506 return;
3507 }
3508
Svet Ganov2f8fb1f2017-03-13 00:21:04 -07003509 structure.setChildCount(childrenCount);
3510 ArrayList<View> preorderedList = buildOrderedChildList();
3511 boolean customOrder = preorderedList == null
3512 && isChildrenDrawingOrderEnabled();
3513 for (int i = 0; i < childrenCount; i++) {
3514 int childIndex;
3515 try {
3516 childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
3517 } catch (IndexOutOfBoundsException e) {
3518 childIndex = i;
3519 if (mContext.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.M) {
3520 Log.w(TAG, "Bad getChildDrawingOrder while collecting assist @ "
3521 + i + " of " + childrenCount, e);
3522 // At least one app is failing when we call getChildDrawingOrder
3523 // at this point, so deal semi-gracefully with it by falling back
3524 // on the basic order.
3525 customOrder = false;
3526 if (i > 0) {
3527 // If we failed at the first index, there really isn't
3528 // anything to do -- we will just proceed with the simple
3529 // sequence order.
3530 // Otherwise, we failed in the middle, so need to come up
3531 // with an order for the remaining indices and use that.
3532 // Failed at the first one, easy peasy.
3533 int[] permutation = new int[childrenCount];
3534 SparseBooleanArray usedIndices = new SparseBooleanArray();
3535 // Go back and collected the indices we have done so far.
3536 for (int j = 0; j < i; j++) {
3537 permutation[j] = getChildDrawingOrder(childrenCount, j);
3538 usedIndices.put(permutation[j], true);
3539 }
3540 // Fill in the remaining indices with indices that have not
3541 // yet been used.
3542 int nextIndex = 0;
3543 for (int j = i; j < childrenCount; j++) {
3544 while (usedIndices.get(nextIndex, false)) {
3545 nextIndex++;
3546 }
3547 permutation[j] = nextIndex;
3548 nextIndex++;
3549 }
3550 // Build the final view list.
3551 preorderedList = new ArrayList<>(childrenCount);
3552 for (int j = 0; j < childrenCount; j++) {
3553 final int index = permutation[j];
3554 final View child = mChildren[index];
3555 preorderedList.add(child);
3556 }
3557 }
3558 } else {
3559 throw e;
3560 }
3561 }
3562 final View child = getAndVerifyPreorderedView(preorderedList, mChildren,
3563 childIndex);
3564 final ViewStructure cstructure = structure.newChild(i);
3565 child.dispatchProvideStructure(cstructure);
3566 }
3567 if (preorderedList != null) {
3568 preorderedList.clear();
3569 }
Felipe Leme6d553872016-12-08 17:13:25 -08003570 }
3571
3572 /**
Felipe Leme1ca634a2016-11-28 17:21:21 -08003573 * {@inheritDoc}
3574 *
3575 * <p>This implementation adds in all child views of the view group, in addition to calling the
3576 * default {@link View} implementation.
Dianne Hackborn6251f0d2015-04-01 16:45:03 -07003577 */
Alan Viverettebe463f22016-01-21 10:50:10 -05003578 @Override
Svet Ganovfd31f852017-04-26 15:54:27 -07003579 public void dispatchProvideAutofillStructure(ViewStructure structure,
3580 @AutofillFlags int flags) {
Felipe Leme640f30a2017-03-06 15:44:06 -08003581 super.dispatchProvideAutofillStructure(structure, flags);
Svetoslav Ganov24c90452017-12-27 15:17:14 -08003582
Svet Ganovfd31f852017-04-26 15:54:27 -07003583 if (structure.getChildCount() != 0) {
Svet Ganov2f8fb1f2017-03-13 00:21:04 -07003584 return;
3585 }
Philip P. Moltmann083d8aa2017-08-15 15:22:37 -07003586
3587 if (!isLaidOut()) {
Svetoslav Ganov24c90452017-12-27 15:17:14 -08003588 if (Helper.sVerbose) {
3589 Log.v(VIEW_LOG_TAG, "dispatchProvideAutofillStructure(): not laid out, ignoring "
3590 + mChildrenCount + " children of " + getAutofillId());
3591 }
Philip P. Moltmann083d8aa2017-08-15 15:22:37 -07003592 return;
3593 }
3594
Svet Ganovfd31f852017-04-26 15:54:27 -07003595 final ChildListForAutoFill children = getChildrenForAutofill(flags);
Svet Ganov2f8fb1f2017-03-13 00:21:04 -07003596 final int childrenCount = children.size();
3597 structure.setChildCount(childrenCount);
3598 for (int i = 0; i < childrenCount; i++) {
3599 final View child = children.get(i);
3600 final ViewStructure cstructure = structure.newChild(i);
3601 child.dispatchProvideAutofillStructure(cstructure, flags);
3602 }
3603 children.recycle();
Felipe Leme6d553872016-12-08 17:13:25 -08003604 }
Felipe Leme1ca634a2016-11-28 17:21:21 -08003605
Svet Ganov2f8fb1f2017-03-13 00:21:04 -07003606 /**
3607 * Gets the children for autofill. Children for autofill are the first
3608 * level descendants that are important for autofill. The returned
3609 * child list object is pooled and the caller must recycle it once done.
3610 * @hide */
Svet Ganovfd31f852017-04-26 15:54:27 -07003611 private @NonNull ChildListForAutoFill getChildrenForAutofill(@AutofillFlags int flags) {
Svet Ganov2f8fb1f2017-03-13 00:21:04 -07003612 final ChildListForAutoFill children = ChildListForAutoFill.obtain();
Svet Ganovfd31f852017-04-26 15:54:27 -07003613 populateChildrenForAutofill(children, flags);
Svet Ganov2f8fb1f2017-03-13 00:21:04 -07003614 return children;
Felipe Lemed04a6972017-03-02 12:56:18 -08003615 }
3616
3617 /** @hide */
Svet Ganovfd31f852017-04-26 15:54:27 -07003618 private void populateChildrenForAutofill(ArrayList<View> list, @AutofillFlags int flags) {
Svet Ganov2f8fb1f2017-03-13 00:21:04 -07003619 final int childrenCount = mChildrenCount;
3620 if (childrenCount <= 0) {
3621 return;
3622 }
3623 final ArrayList<View> preorderedList = buildOrderedChildList();
3624 final boolean customOrder = preorderedList == null
3625 && isChildrenDrawingOrderEnabled();
3626 for (int i = 0; i < childrenCount; i++) {
3627 final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
3628 final View child = (preorderedList == null)
3629 ? mChildren[childIndex] : preorderedList.get(childIndex);
Svet Ganovfd31f852017-04-26 15:54:27 -07003630 if ((flags & AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) != 0
3631 || child.isImportantForAutofill()) {
Felipe Lemed04a6972017-03-02 12:56:18 -08003632 list.add(child);
3633 } else if (child instanceof ViewGroup) {
Svet Ganovfd31f852017-04-26 15:54:27 -07003634 ((ViewGroup) child).populateChildrenForAutofill(list, flags);
Felipe Lemed04a6972017-03-02 12:56:18 -08003635 }
3636 }
3637 }
3638
Alan Viverettea7b85e62016-01-22 10:14:02 -05003639 private static View getAndVerifyPreorderedView(ArrayList<View> preorderedList, View[] children,
3640 int childIndex) {
3641 final View child;
3642 if (preorderedList != null) {
3643 child = preorderedList.get(childIndex);
3644 if (child == null) {
3645 throw new RuntimeException("Invalid preorderedList contained null child at index "
3646 + childIndex);
3647 }
3648 } else {
3649 child = children[childIndex];
3650 }
3651 return child;
3652 }
3653
Alan Viverettea54956a2015-01-07 16:05:02 -08003654 /** @hide */
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003655 @Override
Mathew Inwoode5ad5982018-08-17 15:07:52 +01003656 @UnsupportedAppUsage
Alan Viverettea54956a2015-01-07 16:05:02 -08003657 public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
Svetoslav Ganov031d9c12011-09-09 16:41:13 -07003658 super.onInitializeAccessibilityNodeInfoInternal(info);
Svet Ganov55bdb102015-02-06 12:41:17 -08003659 if (getAccessibilityNodeProvider() != null) {
3660 return;
3661 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07003662 if (mAttachInfo != null) {
Alan Viverettef0aed092013-11-06 15:33:03 -08003663 final ArrayList<View> childrenForAccessibility = mAttachInfo.mTempArrayList;
Svetoslav Ganov42138042012-03-20 11:51:39 -07003664 childrenForAccessibility.clear();
3665 addChildrenForAccessibility(childrenForAccessibility);
3666 final int childrenForAccessibilityCount = childrenForAccessibility.size();
3667 for (int i = 0; i < childrenForAccessibilityCount; i++) {
Alan Viverettef0aed092013-11-06 15:33:03 -08003668 final View child = childrenForAccessibility.get(i);
3669 info.addChildUnchecked(child);
Svetoslav Ganovea1da3d2011-06-15 17:16:02 -07003670 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07003671 childrenForAccessibility.clear();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003672 }
3673 }
3674
Svetoslav Ganov8a78fd42012-01-17 14:36:46 -08003675 @Override
Maxim Bogatovf399af32015-06-16 15:15:49 -07003676 public CharSequence getAccessibilityClassName() {
3677 return ViewGroup.class.getName();
Svetoslav Ganov8a78fd42012-01-17 14:36:46 -08003678 }
3679
Eugene Susla72c510f2018-01-23 21:12:11 +00003680 @Override
3681 public void notifySubtreeAccessibilityStateChanged(View child, View source, int changeType) {
3682 // If this is a live region, we should send a subtree change event
3683 // from this view. Otherwise, we can let it propagate up.
3684 if (getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE) {
3685 notifyViewAccessibilityStateChangedIfNeeded(
3686 AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE);
3687 } else if (mParent != null) {
3688 try {
3689 mParent.notifySubtreeAccessibilityStateChanged(this, source, changeType);
3690 } catch (AbstractMethodError e) {
3691 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() +
3692 " does not fully implement ViewParent", e);
3693 }
3694 }
3695 }
3696
Phil Weaver4d3eec412016-09-01 16:28:34 -07003697 /** @hide */
3698 @Override
Eugene Susla72c510f2018-01-23 21:12:11 +00003699 public void notifySubtreeAccessibilityStateChangedIfNeeded() {
Phil Weaver4d3eec412016-09-01 16:28:34 -07003700 if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) {
3701 return;
3702 }
3703 // If something important for a11y is happening in this subtree, make sure it's dispatched
3704 // from a view that is important for a11y so it doesn't get lost.
Eugene Susla72c510f2018-01-23 21:12:11 +00003705 if ((getImportantForAccessibility() != IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS)
3706 && !isImportantForAccessibility() && (getChildCount() > 0)) {
Phil Weaver4d3eec412016-09-01 16:28:34 -07003707 ViewParent a11yParent = getParentForAccessibility();
3708 if (a11yParent instanceof View) {
Eugene Susla72c510f2018-01-23 21:12:11 +00003709 ((View) a11yParent).notifySubtreeAccessibilityStateChangedIfNeeded();
Phil Weaver4d3eec412016-09-01 16:28:34 -07003710 return;
3711 }
3712 }
Eugene Susla72c510f2018-01-23 21:12:11 +00003713 super.notifySubtreeAccessibilityStateChangedIfNeeded();
Phil Weaver4d3eec412016-09-01 16:28:34 -07003714 }
3715
Svetoslav6254f482013-06-04 17:22:14 -07003716 @Override
Eugene Susla72c510f2018-01-23 21:12:11 +00003717 void resetSubtreeAccessibilityStateChanged() {
Svetoslav6254f482013-06-04 17:22:14 -07003718 super.resetSubtreeAccessibilityStateChanged();
Svetoslav Ganov42138042012-03-20 11:51:39 -07003719 View[] children = mChildren;
3720 final int childCount = mChildrenCount;
3721 for (int i = 0; i < childCount; i++) {
Svetoslav6254f482013-06-04 17:22:14 -07003722 children[i].resetSubtreeAccessibilityStateChanged();
Svetoslav Ganov42138042012-03-20 11:51:39 -07003723 }
3724 }
3725
3726 /**
Phil Weaver1f222542016-01-08 11:49:32 -08003727 * Counts the number of children of this View that will be sent to an accessibility service.
3728 *
3729 * @return The number of children an {@code AccessibilityNodeInfo} rooted at this View
3730 * would have.
3731 */
3732 int getNumChildrenForAccessibility() {
3733 int numChildrenForAccessibility = 0;
3734 for (int i = 0; i < getChildCount(); i++) {
3735 View child = getChildAt(i);
3736 if (child.includeForAccessibility()) {
3737 numChildrenForAccessibility++;
3738 } else if (child instanceof ViewGroup) {
3739 numChildrenForAccessibility += ((ViewGroup) child)
3740 .getNumChildrenForAccessibility();
3741 }
3742 }
3743 return numChildrenForAccessibility;
3744 }
3745
3746 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003747 * {@inheritDoc}
Adam Powellb6ab0982015-01-07 17:00:12 -08003748 *
3749 * <p>Subclasses should always call <code>super.onNestedPrePerformAccessibilityAction</code></p>
3750 *
3751 * @param target The target view dispatching this action
3752 * @param action Action being performed; see
3753 * {@link android.view.accessibility.AccessibilityNodeInfo}
3754 * @param args Optional action arguments
3755 * @return false by default. Subclasses should return true if they handle the event.
3756 */
3757 @Override
3758 public boolean onNestedPrePerformAccessibilityAction(View target, int action, Bundle args) {
3759 return false;
3760 }
3761
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003762 @Override
Mathew Inwoode5ad5982018-08-17 15:07:52 +01003763 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003764 void dispatchDetachedFromWindow() {
Jeff Brown20e987b2010-08-23 12:01:02 -07003765 // If we still have a touch target, we are still in the process of
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003766 // dispatching motion events to a child; we need to get rid of that
3767 // child to avoid dispatching events to it after the window is torn
3768 // down. To make sure we keep the child in a consistent state, we
3769 // first send it an ACTION_CANCEL motion event.
Jeff Brown20e987b2010-08-23 12:01:02 -07003770 cancelAndClearTouchTargets(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003771
Jeff Brown59a422e2012-04-19 15:19:19 -07003772 // Similarly, set ACTION_EXIT to all hover targets and clear them.
3773 exitHoverTargets();
Vladislav Kaznacheevf847ee32016-11-21 14:11:00 -08003774 exitTooltipHoverTargets();
Jeff Brown59a422e2012-04-19 15:19:19 -07003775
Chet Haase9c087442011-01-12 16:20:16 -08003776 // In case view is detached while transition is running
Chet Haaseb9895022013-04-02 15:10:58 -07003777 mLayoutCalledWhileSuppressed = false;
Chet Haase9c087442011-01-12 16:20:16 -08003778
Christopher Tate86cab1b2011-01-13 20:28:55 -08003779 // Tear down our drag tracking
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07003780 mChildrenInterestedInDrag = null;
3781 mIsInterestedInDrag = false;
3782 if (mCurrentDragStartEvent != null) {
3783 mCurrentDragStartEvent.recycle();
3784 mCurrentDragStartEvent = null;
Christopher Tate86cab1b2011-01-13 20:28:55 -08003785 }
3786
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003787 final int count = mChildrenCount;
3788 final View[] children = mChildren;
3789 for (int i = 0; i < count; i++) {
3790 children[i].dispatchDetachedFromWindow();
3791 }
John Reckca7a9da2014-03-05 16:29:07 -08003792 clearDisappearingChildren();
Chet Haasec633d2f2015-04-07 10:29:39 -07003793 final int transientCount = mTransientViews == null ? 0 : mTransientIndices.size();
3794 for (int i = 0; i < transientCount; ++i) {
3795 View view = mTransientViews.get(i);
3796 view.dispatchDetachedFromWindow();
3797 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003798 super.dispatchDetachedFromWindow();
3799 }
3800
Fabrice Di Meglio23c89fd2012-08-13 12:17:42 -07003801 /**
3802 * @hide
3803 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003804 @Override
Fabrice Di Meglio23c89fd2012-08-13 12:17:42 -07003805 protected void internalSetPadding(int left, int top, int right, int bottom) {
Romain Guy2440e672012-08-07 14:43:43 -07003806 super.internalSetPadding(left, top, right, bottom);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003807
Romain Guy13f35f32011-03-24 12:03:17 -07003808 if ((mPaddingLeft | mPaddingTop | mPaddingRight | mPaddingBottom) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003809 mGroupFlags |= FLAG_PADDING_NOT_NULL;
3810 } else {
3811 mGroupFlags &= ~FLAG_PADDING_NOT_NULL;
3812 }
3813 }
3814
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003815 @Override
3816 protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
3817 super.dispatchSaveInstanceState(container);
3818 final int count = mChildrenCount;
3819 final View[] children = mChildren;
3820 for (int i = 0; i < count; i++) {
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07003821 View c = children[i];
3822 if ((c.mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED) {
3823 c.dispatchSaveInstanceState(container);
3824 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003825 }
3826 }
3827
3828 /**
Romain Guy9fc27812011-04-27 14:21:41 -07003829 * Perform dispatching of a {@link #saveHierarchyState(android.util.SparseArray)} freeze()}
3830 * to only this view, not to its children. For use when overriding
3831 * {@link #dispatchSaveInstanceState(android.util.SparseArray)} dispatchFreeze()} to allow
3832 * subclasses to freeze their own state but not the state of their children.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003833 *
3834 * @param container the container
3835 */
3836 protected void dispatchFreezeSelfOnly(SparseArray<Parcelable> container) {
3837 super.dispatchSaveInstanceState(container);
3838 }
3839
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003840 @Override
3841 protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
3842 super.dispatchRestoreInstanceState(container);
3843 final int count = mChildrenCount;
3844 final View[] children = mChildren;
3845 for (int i = 0; i < count; i++) {
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07003846 View c = children[i];
3847 if ((c.mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED) {
3848 c.dispatchRestoreInstanceState(container);
3849 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003850 }
3851 }
3852
3853 /**
Romain Guy02739a82011-05-16 11:43:18 -07003854 * Perform dispatching of a {@link #restoreHierarchyState(android.util.SparseArray)}
3855 * to only this view, not to its children. For use when overriding
3856 * {@link #dispatchRestoreInstanceState(android.util.SparseArray)} to allow
3857 * subclasses to thaw their own state but not the state of their children.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003858 *
3859 * @param container the container
3860 */
3861 protected void dispatchThawSelfOnly(SparseArray<Parcelable> container) {
3862 super.dispatchRestoreInstanceState(container);
3863 }
3864
3865 /**
3866 * Enables or disables the drawing cache for each child of this view group.
3867 *
3868 * @param enabled true to enable the cache, false to dispose of it
John Reck949cfe12017-10-09 13:27:03 -07003869 *
3870 * @deprecated The view drawing cache was largely made obsolete with the introduction of
3871 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache
3872 * layers are largely unnecessary and can easily result in a net loss in performance due to the
3873 * cost of creating and updating the layer. In the rare cases where caching layers are useful,
3874 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware
3875 * rendering. For software-rendered snapshots of a small part of the View hierarchy or
3876 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or
3877 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these
3878 * software-rendered usages are discouraged and have compatibility issues with hardware-only
3879 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE}
3880 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback
3881 * reports or unit testing the {@link PixelCopy} API is recommended.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003882 */
John Reck949cfe12017-10-09 13:27:03 -07003883 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003884 protected void setChildrenDrawingCacheEnabled(boolean enabled) {
3885 if (enabled || (mPersistentDrawingCache & PERSISTENT_ALL_CACHES) != PERSISTENT_ALL_CACHES) {
3886 final View[] children = mChildren;
3887 final int count = mChildrenCount;
3888 for (int i = 0; i < count; i++) {
3889 children[i].setDrawingCacheEnabled(enabled);
3890 }
3891 }
3892 }
3893
sergeyvb37d44e2016-03-29 20:27:44 -07003894 /**
3895 * @hide
3896 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003897 @Override
Sunny Goyald1b287e2018-01-04 09:37:22 -08003898 public Bitmap createSnapshot(ViewDebug.CanvasProvider canvasProvider, boolean skipChildren) {
Romain Guy65554f22010-03-22 18:58:21 -07003899 int count = mChildrenCount;
3900 int[] visibilities = null;
3901
Romain Guy223ff5c2010-03-02 17:07:47 -08003902 if (skipChildren) {
Romain Guy65554f22010-03-22 18:58:21 -07003903 visibilities = new int[count];
3904 for (int i = 0; i < count; i++) {
3905 View child = getChildAt(i);
3906 visibilities[i] = child.getVisibility();
3907 if (visibilities[i] == View.VISIBLE) {
sergeyvb37d44e2016-03-29 20:27:44 -07003908 child.mViewFlags = (child.mViewFlags & ~View.VISIBILITY_MASK)
3909 | (View.INVISIBLE & View.VISIBILITY_MASK);
Romain Guy65554f22010-03-22 18:58:21 -07003910 }
3911 }
Romain Guy223ff5c2010-03-02 17:07:47 -08003912 }
3913
Sunny Goyald1b287e2018-01-04 09:37:22 -08003914 try {
3915 return super.createSnapshot(canvasProvider, skipChildren);
3916 } finally {
3917 if (skipChildren) {
3918 for (int i = 0; i < count; i++) {
3919 View child = getChildAt(i);
3920 child.mViewFlags = (child.mViewFlags & ~View.VISIBILITY_MASK)
3921 | (visibilities[i] & View.VISIBILITY_MASK);
3922 }
Chet Haase5c13d892010-10-08 08:37:55 -07003923 }
Romain Guy65554f22010-03-22 18:58:21 -07003924 }
Romain Guy223ff5c2010-03-02 17:07:47 -08003925 }
3926
Philip Milne7b757812012-09-19 18:13:44 -07003927 /** Return true if this ViewGroup is laying out using optical bounds. */
3928 boolean isLayoutModeOptical() {
3929 return mLayoutMode == LAYOUT_MODE_OPTICAL_BOUNDS;
3930 }
Romain Guycbc67742012-04-27 16:12:57 -07003931
Alan Viverettebe463f22016-01-21 10:50:10 -05003932 @Override
Philip Milne7b757812012-09-19 18:13:44 -07003933 Insets computeOpticalInsets() {
3934 if (isLayoutModeOptical()) {
3935 int left = 0;
3936 int top = 0;
3937 int right = 0;
3938 int bottom = 0;
3939 for (int i = 0; i < mChildrenCount; i++) {
3940 View child = getChildAt(i);
3941 if (child.getVisibility() == VISIBLE) {
3942 Insets insets = child.getOpticalInsets();
3943 left = Math.max(left, insets.left);
3944 top = Math.max(top, insets.top);
3945 right = Math.max(right, insets.right);
3946 bottom = Math.max(bottom, insets.bottom);
3947 }
3948 }
3949 return Insets.of(left, top, right, bottom);
3950 } else {
3951 return Insets.NONE;
3952 }
3953 }
3954
3955 private static void fillRect(Canvas canvas, Paint paint, int x1, int y1, int x2, int y2) {
3956 if (x1 != x2 && y1 != y2) {
3957 if (x1 > x2) {
3958 int tmp = x1; x1 = x2; x2 = tmp;
3959 }
3960 if (y1 > y2) {
3961 int tmp = y1; y1 = y2; y2 = tmp;
3962 }
3963 canvas.drawRect(x1, y1, x2, y2, paint);
3964 }
3965 }
3966
3967 private static int sign(int x) {
3968 return (x >= 0) ? 1 : -1;
3969 }
3970
3971 private static void drawCorner(Canvas c, Paint paint, int x1, int y1, int dx, int dy, int lw) {
3972 fillRect(c, paint, x1, y1, x1 + dx, y1 + lw * sign(dy));
3973 fillRect(c, paint, x1, y1, x1 + lw * sign(dx), y1 + dy);
3974 }
3975
Romain Guy6410c0a2013-06-17 11:21:58 -07003976 private static void drawRectCorners(Canvas canvas, int x1, int y1, int x2, int y2, Paint paint,
3977 int lineLength, int lineWidth) {
Philip Milne7b757812012-09-19 18:13:44 -07003978 drawCorner(canvas, paint, x1, y1, lineLength, lineLength, lineWidth);
3979 drawCorner(canvas, paint, x1, y2, lineLength, -lineLength, lineWidth);
3980 drawCorner(canvas, paint, x2, y1, -lineLength, lineLength, lineWidth);
3981 drawCorner(canvas, paint, x2, y2, -lineLength, -lineLength, lineWidth);
3982 }
3983
3984 private static void fillDifference(Canvas canvas,
3985 int x2, int y2, int x3, int y3,
3986 int dx1, int dy1, int dx2, int dy2, Paint paint) {
3987 int x1 = x2 - dx1;
3988 int y1 = y2 - dy1;
3989
3990 int x4 = x3 + dx2;
3991 int y4 = y3 + dy2;
3992
3993 fillRect(canvas, paint, x1, y1, x4, y2);
3994 fillRect(canvas, paint, x1, y2, x2, y3);
3995 fillRect(canvas, paint, x3, y2, x4, y3);
3996 fillRect(canvas, paint, x1, y3, x4, y4);
Philip Milne10ca24a2012-04-23 15:38:27 -07003997 }
3998
3999 /**
Alan Viverette2d7771c2018-01-31 17:04:31 -05004000 * @hide
Philip Milne10ca24a2012-04-23 15:38:27 -07004001 */
Philip Milne7b757812012-09-19 18:13:44 -07004002 protected void onDebugDrawMargins(Canvas canvas, Paint paint) {
Philip Milne10ca24a2012-04-23 15:38:27 -07004003 for (int i = 0; i < getChildCount(); i++) {
4004 View c = getChildAt(i);
Philip Milne7b757812012-09-19 18:13:44 -07004005 c.getLayoutParams().onDebugDraw(c, canvas, paint);
Philip Milne10ca24a2012-04-23 15:38:27 -07004006 }
4007 }
4008
4009 /**
Alan Viverette2d7771c2018-01-31 17:04:31 -05004010 * @hide
Philip Milne10ca24a2012-04-23 15:38:27 -07004011 */
4012 protected void onDebugDraw(Canvas canvas) {
Philip Milne7b757812012-09-19 18:13:44 -07004013 Paint paint = getDebugPaint();
4014
Philip Milne10ca24a2012-04-23 15:38:27 -07004015 // Draw optical bounds
Philip Milne7b757812012-09-19 18:13:44 -07004016 {
4017 paint.setColor(Color.RED);
4018 paint.setStyle(Paint.Style.STROKE);
Philip Milne7b757812012-09-19 18:13:44 -07004019
Philip Milne10ca24a2012-04-23 15:38:27 -07004020 for (int i = 0; i < getChildCount(); i++) {
4021 View c = getChildAt(i);
Chris Craika1dab8b2015-06-30 13:51:25 -07004022 if (c.getVisibility() != View.GONE) {
4023 Insets insets = c.getOpticalInsets();
Philip Milne7b757812012-09-19 18:13:44 -07004024
Chris Craika1dab8b2015-06-30 13:51:25 -07004025 drawRect(canvas, paint,
4026 c.getLeft() + insets.left,
4027 c.getTop() + insets.top,
4028 c.getRight() - insets.right - 1,
4029 c.getBottom() - insets.bottom - 1);
4030 }
Philip Milne10ca24a2012-04-23 15:38:27 -07004031 }
4032 }
4033
Philip Milne10ca24a2012-04-23 15:38:27 -07004034 // Draw margins
Philip Milne7b757812012-09-19 18:13:44 -07004035 {
4036 paint.setColor(Color.argb(63, 255, 0, 255));
4037 paint.setStyle(Paint.Style.FILL);
Philip Milne604f4402012-04-24 19:27:11 -07004038
Philip Milne7b757812012-09-19 18:13:44 -07004039 onDebugDrawMargins(canvas, paint);
4040 }
4041
4042 // Draw clip bounds
4043 {
Vadim Tryshevcdf38ba2016-10-11 18:33:10 -07004044 paint.setColor(DEBUG_CORNERS_COLOR);
Philip Milne7b757812012-09-19 18:13:44 -07004045 paint.setStyle(Paint.Style.FILL);
4046
Vadim Tryshevcdf38ba2016-10-11 18:33:10 -07004047 int lineLength = dipsToPixels(DEBUG_CORNERS_SIZE_DIP);
Philip Milne7b757812012-09-19 18:13:44 -07004048 int lineWidth = dipsToPixels(1);
4049 for (int i = 0; i < getChildCount(); i++) {
4050 View c = getChildAt(i);
Chris Craika1dab8b2015-06-30 13:51:25 -07004051 if (c.getVisibility() != View.GONE) {
4052 drawRectCorners(canvas, c.getLeft(), c.getTop(), c.getRight(), c.getBottom(),
4053 paint, lineLength, lineWidth);
4054 }
Philip Milne7b757812012-09-19 18:13:44 -07004055 }
Philip Milne604f4402012-04-24 19:27:11 -07004056 }
Philip Milne10ca24a2012-04-23 15:38:27 -07004057 }
4058
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004059 @Override
4060 protected void dispatchDraw(Canvas canvas) {
Chris Craika753f4c2014-07-24 12:39:17 -07004061 boolean usingRenderNodeProperties = canvas.isRecordingFor(mRenderNode);
Chris Craikab008f02014-05-23 17:55:03 -07004062 final int childrenCount = mChildrenCount;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004063 final View[] children = mChildren;
4064 int flags = mGroupFlags;
4065
4066 if ((flags & FLAG_RUN_ANIMATION) != 0 && canAnimate()) {
Romain Guy0d9275e2010-10-26 14:22:30 -07004067 final boolean buildCache = !isHardwareAccelerated();
Chris Craikab008f02014-05-23 17:55:03 -07004068 for (int i = 0; i < childrenCount; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004069 final View child = children[i];
4070 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
4071 final LayoutParams params = child.getLayoutParams();
Chris Craikab008f02014-05-23 17:55:03 -07004072 attachLayoutAnimationParameters(child, params, i, childrenCount);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004073 bindLayoutAnimation(child);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004074 }
4075 }
4076
4077 final LayoutAnimationController controller = mLayoutAnimationController;
4078 if (controller.willOverlap()) {
4079 mGroupFlags |= FLAG_OPTIMIZE_INVALIDATE;
4080 }
4081
4082 controller.start();
4083
4084 mGroupFlags &= ~FLAG_RUN_ANIMATION;
4085 mGroupFlags &= ~FLAG_ANIMATION_DONE;
4086
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004087 if (mAnimationListener != null) {
4088 mAnimationListener.onAnimationStart(controller.getAnimation());
4089 }
4090 }
4091
Selim Cinek19cadc22014-04-16 17:27:19 +02004092 int clipSaveCount = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004093 final boolean clipToPadding = (flags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK;
4094 if (clipToPadding) {
John Reck41f864e2016-05-12 15:07:49 -07004095 clipSaveCount = canvas.save(Canvas.CLIP_SAVE_FLAG);
Romain Guy8f2d94f2009-03-25 18:04:42 -07004096 canvas.clipRect(mScrollX + mPaddingLeft, mScrollY + mPaddingTop,
4097 mScrollX + mRight - mLeft - mPaddingRight,
4098 mScrollY + mBottom - mTop - mPaddingBottom);
Selim Cinek19cadc22014-04-16 17:27:19 +02004099 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004100
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004101 // We will draw our child's animation, let's reset the flag
Dianne Hackborn4702a852012-08-17 15:18:29 -07004102 mPrivateFlags &= ~PFLAG_DRAW_ANIMATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004103 mGroupFlags &= ~FLAG_INVALIDATE_REQUIRED;
4104
4105 boolean more = false;
4106 final long drawingTime = getDrawingTime();
4107
Chris Craik8afd0f22014-08-21 17:41:57 -07004108 if (usingRenderNodeProperties) canvas.insertReorderBarrier();
Chet Haasec633d2f2015-04-07 10:29:39 -07004109 final int transientCount = mTransientIndices == null ? 0 : mTransientIndices.size();
4110 int transientIndex = transientCount != 0 ? 0 : -1;
Chris Craikab008f02014-05-23 17:55:03 -07004111 // Only use the preordered list if not HW accelerated, since the HW pipeline will do the
4112 // draw reordering internally
Chris Craika753f4c2014-07-24 12:39:17 -07004113 final ArrayList<View> preorderedList = usingRenderNodeProperties
Chris Craikab008f02014-05-23 17:55:03 -07004114 ? null : buildOrderedChildList();
4115 final boolean customOrder = preorderedList == null
4116 && isChildrenDrawingOrderEnabled();
4117 for (int i = 0; i < childrenCount; i++) {
Chet Haasec633d2f2015-04-07 10:29:39 -07004118 while (transientIndex >= 0 && mTransientIndices.get(transientIndex) == i) {
4119 final View transientChild = mTransientViews.get(transientIndex);
4120 if ((transientChild.mViewFlags & VISIBILITY_MASK) == VISIBLE ||
4121 transientChild.getAnimation() != null) {
4122 more |= drawChild(canvas, transientChild, drawingTime);
4123 }
4124 transientIndex++;
4125 if (transientIndex >= transientCount) {
4126 transientIndex = -1;
4127 }
4128 }
Alan Viverettea7b85e62016-01-22 10:14:02 -05004129
4130 final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
4131 final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);
Chris Craikab008f02014-05-23 17:55:03 -07004132 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
4133 more |= drawChild(canvas, child, drawingTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004134 }
4135 }
Chet Haasec633d2f2015-04-07 10:29:39 -07004136 while (transientIndex >= 0) {
4137 // there may be additional transient views after the normal views
4138 final View transientChild = mTransientViews.get(transientIndex);
4139 if ((transientChild.mViewFlags & VISIBILITY_MASK) == VISIBLE ||
4140 transientChild.getAnimation() != null) {
4141 more |= drawChild(canvas, transientChild, drawingTime);
4142 }
4143 transientIndex++;
4144 if (transientIndex >= transientCount) {
4145 break;
4146 }
4147 }
Chris Craikab008f02014-05-23 17:55:03 -07004148 if (preorderedList != null) preorderedList.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004149
4150 // Draw any disappearing views that have animations
4151 if (mDisappearingChildren != null) {
4152 final ArrayList<View> disappearingChildren = mDisappearingChildren;
4153 final int disappearingCount = disappearingChildren.size() - 1;
4154 // Go backwards -- we may delete as animations finish
4155 for (int i = disappearingCount; i >= 0; i--) {
4156 final View child = disappearingChildren.get(i);
4157 more |= drawChild(canvas, child, drawingTime);
4158 }
4159 }
Chris Craik8afd0f22014-08-21 17:41:57 -07004160 if (usingRenderNodeProperties) canvas.insertInorderBarrier();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004161
Philip Milne10ca24a2012-04-23 15:38:27 -07004162 if (debugDraw()) {
4163 onDebugDraw(canvas);
4164 }
4165
Chris Craike4cf1522014-08-04 17:55:22 -07004166 if (clipToPadding) {
Selim Cinek19cadc22014-04-16 17:27:19 +02004167 canvas.restoreToCount(clipSaveCount);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004168 }
4169
4170 // mGroupFlags might have been updated by drawChild()
4171 flags = mGroupFlags;
4172
4173 if ((flags & FLAG_INVALIDATE_REQUIRED) == FLAG_INVALIDATE_REQUIRED) {
Romain Guy849d0a32011-02-01 17:20:48 -08004174 invalidate(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004175 }
4176
4177 if ((flags & FLAG_ANIMATION_DONE) == 0 && (flags & FLAG_NOTIFY_ANIMATION_LISTENER) == 0 &&
4178 mLayoutAnimationController.isDone() && !more) {
4179 // We want to erase the drawing cache and notify the listener after the
4180 // next frame is drawn because one extra invalidate() is caused by
4181 // drawChild() after the animation is over
4182 mGroupFlags |= FLAG_NOTIFY_ANIMATION_LISTENER;
4183 final Runnable end = new Runnable() {
Alan Viverettebe463f22016-01-21 10:50:10 -05004184 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004185 public void run() {
4186 notifyAnimationListener();
4187 }
4188 };
4189 post(end);
4190 }
4191 }
Romain Guy8506ab42009-06-11 17:35:47 -07004192
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004193 /**
Chet Haaseedf6f4b2013-03-26 07:55:30 -07004194 * Returns the ViewGroupOverlay for this view group, creating it if it does
4195 * not yet exist. In addition to {@link ViewOverlay}'s support for drawables,
4196 * {@link ViewGroupOverlay} allows views to be added to the overlay. These
4197 * views, like overlay drawables, are visual-only; they do not receive input
4198 * events and should not be used as anything other than a temporary
4199 * representation of a view in a parent container, such as might be used
4200 * by an animation effect.
4201 *
Chet Haase95399492013-04-08 14:30:31 -07004202 * <p>Note: Overlays do not currently work correctly with {@link
4203 * SurfaceView} or {@link TextureView}; contents in overlays for these
4204 * types of views may not display correctly.</p>
4205 *
Chet Haaseedf6f4b2013-03-26 07:55:30 -07004206 * @return The ViewGroupOverlay object for this view.
4207 * @see ViewGroupOverlay
4208 */
4209 @Override
4210 public ViewGroupOverlay getOverlay() {
4211 if (mOverlay == null) {
4212 mOverlay = new ViewGroupOverlay(mContext, this);
4213 }
4214 return (ViewGroupOverlay) mOverlay;
4215 }
4216
4217 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004218 * Returns the index of the child to draw for this iteration. Override this
4219 * if you want to change the drawing order of children. By default, it
4220 * returns i.
4221 * <p>
Romain Guy293451e2009-11-04 13:59:48 -08004222 * NOTE: In order for this method to be called, you must enable child ordering
4223 * first by calling {@link #setChildrenDrawingOrderEnabled(boolean)}.
Romain Guy8506ab42009-06-11 17:35:47 -07004224 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004225 * @param i The current iteration.
4226 * @return The index of the child to draw this iteration.
Chet Haase5c13d892010-10-08 08:37:55 -07004227 *
Romain Guy293451e2009-11-04 13:59:48 -08004228 * @see #setChildrenDrawingOrderEnabled(boolean)
4229 * @see #isChildrenDrawingOrderEnabled()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004230 */
4231 protected int getChildDrawingOrder(int childCount, int i) {
4232 return i;
4233 }
Romain Guy8506ab42009-06-11 17:35:47 -07004234
Chris Craikab008f02014-05-23 17:55:03 -07004235 private boolean hasChildWithZ() {
4236 for (int i = 0; i < mChildrenCount; i++) {
4237 if (mChildren[i].getZ() != 0) return true;
4238 }
4239 return false;
4240 }
4241
4242 /**
4243 * Populates (and returns) mPreSortedChildren with a pre-ordered list of the View's children,
Chris Craik57c79c82014-09-30 12:54:31 -07004244 * sorted first by Z, then by child drawing order (if applicable). This list must be cleared
4245 * after use to avoid leaking child Views.
Chris Craikab008f02014-05-23 17:55:03 -07004246 *
4247 * Uses a stable, insertion sort which is commonly O(n) for ViewGroups with very few elevated
4248 * children.
4249 */
George Mount81206522014-09-26 21:53:39 -07004250 ArrayList<View> buildOrderedChildList() {
Alan Viverettea7b85e62016-01-22 10:14:02 -05004251 final int childrenCount = mChildrenCount;
4252 if (childrenCount <= 1 || !hasChildWithZ()) return null;
Chris Craikab008f02014-05-23 17:55:03 -07004253
4254 if (mPreSortedChildren == null) {
Alan Viverettea7b85e62016-01-22 10:14:02 -05004255 mPreSortedChildren = new ArrayList<>(childrenCount);
Chris Craikab008f02014-05-23 17:55:03 -07004256 } else {
Chris Craikfc563772016-05-04 13:34:30 -07004257 // callers should clear, so clear shouldn't be necessary, but for safety...
4258 mPreSortedChildren.clear();
Alan Viverettea7b85e62016-01-22 10:14:02 -05004259 mPreSortedChildren.ensureCapacity(childrenCount);
Chris Craikab008f02014-05-23 17:55:03 -07004260 }
4261
Alan Viverettea7b85e62016-01-22 10:14:02 -05004262 final boolean customOrder = isChildrenDrawingOrderEnabled();
4263 for (int i = 0; i < childrenCount; i++) {
Chris Craikab008f02014-05-23 17:55:03 -07004264 // add next child (in child order) to end of list
Alan Viverettea7b85e62016-01-22 10:14:02 -05004265 final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
4266 final View nextChild = mChildren[childIndex];
4267 final float currentZ = nextChild.getZ();
Chris Craikab008f02014-05-23 17:55:03 -07004268
4269 // insert ahead of any Views with greater Z
4270 int insertIndex = i;
4271 while (insertIndex > 0 && mPreSortedChildren.get(insertIndex - 1).getZ() > currentZ) {
4272 insertIndex--;
4273 }
4274 mPreSortedChildren.add(insertIndex, nextChild);
4275 }
4276 return mPreSortedChildren;
4277 }
4278
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004279 private void notifyAnimationListener() {
4280 mGroupFlags &= ~FLAG_NOTIFY_ANIMATION_LISTENER;
4281 mGroupFlags |= FLAG_ANIMATION_DONE;
4282
4283 if (mAnimationListener != null) {
4284 final Runnable end = new Runnable() {
Alan Viverettebe463f22016-01-21 10:50:10 -05004285 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004286 public void run() {
4287 mAnimationListener.onAnimationEnd(mLayoutAnimationController.getAnimation());
4288 }
4289 };
4290 post(end);
4291 }
4292
Romain Guy849d0a32011-02-01 17:20:48 -08004293 invalidate(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004294 }
4295
4296 /**
Chet Haasedaf98e92011-01-10 14:10:36 -08004297 * This method is used to cause children of this ViewGroup to restore or recreate their
4298 * display lists. It is called by getDisplayList() when the parent ViewGroup does not need
4299 * to recreate its own display list, which would happen if it went through the normal
4300 * draw/dispatchDraw mechanisms.
4301 *
4302 * @hide
4303 */
4304 @Override
Mathew Inwoode5ad5982018-08-17 15:07:52 +01004305 @UnsupportedAppUsage
Chet Haasedaf98e92011-01-10 14:10:36 -08004306 protected void dispatchGetDisplayList() {
4307 final int count = mChildrenCount;
4308 final View[] children = mChildren;
4309 for (int i = 0; i < count; i++) {
4310 final View child = children[i];
John Reckc2330f52015-04-28 13:18:52 -07004311 if (((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null)) {
Chet Haase6c0665f2014-08-01 13:32:27 -07004312 recreateChildDisplayList(child);
Romain Guy2f57ba52011-02-03 18:03:29 -08004313 }
Chet Haasedaf98e92011-01-10 14:10:36 -08004314 }
Selim Cinekd6a51b12018-03-15 17:10:20 -07004315 final int transientCount = mTransientViews == null ? 0 : mTransientIndices.size();
4316 for (int i = 0; i < transientCount; ++i) {
4317 View child = mTransientViews.get(i);
4318 if (((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null)) {
4319 recreateChildDisplayList(child);
4320 }
4321 }
Chet Haase91cedf12013-03-11 07:56:30 -07004322 if (mOverlay != null) {
Chet Haaseedf6f4b2013-03-26 07:55:30 -07004323 View overlayView = mOverlay.getOverlayView();
Chet Haase6c0665f2014-08-01 13:32:27 -07004324 recreateChildDisplayList(overlayView);
Chet Haase91cedf12013-03-11 07:56:30 -07004325 }
Chet Haase6c0665f2014-08-01 13:32:27 -07004326 if (mDisappearingChildren != null) {
4327 final ArrayList<View> disappearingChildren = mDisappearingChildren;
4328 final int disappearingCount = disappearingChildren.size();
4329 for (int i = 0; i < disappearingCount; ++i) {
4330 final View child = disappearingChildren.get(i);
4331 recreateChildDisplayList(child);
4332 }
4333 }
4334 }
4335
4336 private void recreateChildDisplayList(View child) {
Chris Craik31a2d062015-05-01 14:22:47 -07004337 child.mRecreateDisplayList = (child.mPrivateFlags & PFLAG_INVALIDATED) != 0;
Chet Haase6c0665f2014-08-01 13:32:27 -07004338 child.mPrivateFlags &= ~PFLAG_INVALIDATED;
Chris Craik31a2d062015-05-01 14:22:47 -07004339 child.updateDisplayListIfDirty();
Chet Haase6c0665f2014-08-01 13:32:27 -07004340 child.mRecreateDisplayList = false;
Chet Haasedaf98e92011-01-10 14:10:36 -08004341 }
4342
4343 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004344 * Draw one child of this View Group. This method is responsible for getting
4345 * the canvas in the right state. This includes clipping, translating so
4346 * that the child's scrolled origin is at 0, 0, and applying any animation
4347 * transformations.
4348 *
4349 * @param canvas The canvas on which to draw the child
4350 * @param child Who to draw
Chet Haasebcca79a2012-02-14 08:45:14 -08004351 * @param drawingTime The time at which draw is occurring
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004352 * @return True if an invalidate() was issued
4353 */
4354 protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
Chet Haase64a48c12012-02-13 16:33:29 -08004355 return child.draw(canvas, this, drawingTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004356 }
4357
Alan Viverette922e1c62015-05-05 17:18:27 -07004358 @Override
4359 void getScrollIndicatorBounds(@NonNull Rect out) {
4360 super.getScrollIndicatorBounds(out);
4361
4362 // If we have padding and we're supposed to clip children to that
4363 // padding, offset the scroll indicators to match our clip bounds.
4364 final boolean clipToPadding = (mGroupFlags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK;
4365 if (clipToPadding) {
4366 out.left += mPaddingLeft;
4367 out.right -= mPaddingRight;
4368 out.top += mPaddingTop;
4369 out.bottom -= mPaddingBottom;
4370 }
4371 }
4372
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004373 /**
Chris Craikd863a102013-12-19 13:31:15 -08004374 * Returns whether this group's children are clipped to their bounds before drawing.
Chet Haase430742f2013-04-12 11:18:36 -07004375 * The default value is true.
4376 * @see #setClipChildren(boolean)
4377 *
4378 * @return True if the group's children will be clipped to their bounds,
4379 * false otherwise.
4380 */
Chris Craik5c75c522014-09-05 14:08:08 -07004381 @ViewDebug.ExportedProperty(category = "drawing")
Chet Haase430742f2013-04-12 11:18:36 -07004382 public boolean getClipChildren() {
4383 return ((mGroupFlags & FLAG_CLIP_CHILDREN) != 0);
4384 }
4385
4386 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004387 * By default, children are clipped to their bounds before drawing. This
4388 * allows view groups to override this behavior for animations, etc.
4389 *
4390 * @param clipChildren true to clip children to their bounds,
4391 * false otherwise
4392 * @attr ref android.R.styleable#ViewGroup_clipChildren
4393 */
4394 public void setClipChildren(boolean clipChildren) {
Chet Haasea1cff502012-02-21 13:43:44 -08004395 boolean previousValue = (mGroupFlags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN;
4396 if (clipChildren != previousValue) {
4397 setBooleanFlag(FLAG_CLIP_CHILDREN, clipChildren);
Chet Haase1271e2c2012-04-20 09:54:27 -07004398 for (int i = 0; i < mChildrenCount; ++i) {
4399 View child = getChildAt(i);
Chris Craik64a12e12014-03-28 18:12:12 -07004400 if (child.mRenderNode != null) {
4401 child.mRenderNode.setClipToBounds(clipChildren);
Chet Haasea1cff502012-02-21 13:43:44 -08004402 }
4403 }
John Reckaae9f3b2014-07-28 09:30:36 -07004404 invalidate(true);
Chet Haasea1cff502012-02-21 13:43:44 -08004405 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004406 }
4407
4408 /**
Doris Liub134b5e2015-05-28 17:26:46 -07004409 * Sets whether this ViewGroup will clip its children to its padding and resize (but not
4410 * clip) any EdgeEffect to the padded region, if padding is present.
Chris Craikb1652962014-11-14 17:05:06 -08004411 * <p>
4412 * By default, children are clipped to the padding of their parent
Doris Liub134b5e2015-05-28 17:26:46 -07004413 * ViewGroup. This clipping behavior is only enabled if padding is non-zero.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004414 *
Doris Liub134b5e2015-05-28 17:26:46 -07004415 * @param clipToPadding true to clip children to the padding of the group, and resize (but
4416 * not clip) any EdgeEffect to the padded region. False otherwise.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004417 * @attr ref android.R.styleable#ViewGroup_clipToPadding
4418 */
4419 public void setClipToPadding(boolean clipToPadding) {
John Reck9fa3a242014-06-27 15:57:19 -07004420 if (hasBooleanFlag(FLAG_CLIP_TO_PADDING) != clipToPadding) {
4421 setBooleanFlag(FLAG_CLIP_TO_PADDING, clipToPadding);
John Reckaae9f3b2014-07-28 09:30:36 -07004422 invalidate(true);
John Reck9fa3a242014-06-27 15:57:19 -07004423 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004424 }
4425
4426 /**
Doris Liub134b5e2015-05-28 17:26:46 -07004427 * Returns whether this ViewGroup will clip its children to its padding, and resize (but
4428 * not clip) any EdgeEffect to the padded region, if padding is present.
Chris Craikb1652962014-11-14 17:05:06 -08004429 * <p>
4430 * By default, children are clipped to the padding of their parent
4431 * Viewgroup. This clipping behavior is only enabled if padding is non-zero.
Adam Powell1c35b082014-07-11 15:37:15 -07004432 *
Doris Liub134b5e2015-05-28 17:26:46 -07004433 * @return true if this ViewGroup clips children to its padding and resizes (but doesn't
4434 * clip) any EdgeEffect to the padded region, false otherwise.
Adam Powell1c35b082014-07-11 15:37:15 -07004435 *
4436 * @attr ref android.R.styleable#ViewGroup_clipToPadding
4437 */
Chris Craik5c75c522014-09-05 14:08:08 -07004438 @ViewDebug.ExportedProperty(category = "drawing")
Adam Powell1c35b082014-07-11 15:37:15 -07004439 public boolean getClipToPadding() {
4440 return hasBooleanFlag(FLAG_CLIP_TO_PADDING);
4441 }
4442
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004443 @Override
4444 public void dispatchSetSelected(boolean selected) {
4445 final View[] children = mChildren;
4446 final int count = mChildrenCount;
4447 for (int i = 0; i < count; i++) {
4448 children[i].setSelected(selected);
4449 }
4450 }
Romain Guy8506ab42009-06-11 17:35:47 -07004451
Dianne Hackbornd0fa3712010-09-14 18:57:14 -07004452 @Override
4453 public void dispatchSetActivated(boolean activated) {
4454 final View[] children = mChildren;
4455 final int count = mChildrenCount;
4456 for (int i = 0; i < count; i++) {
Dianne Hackbornd0fa3712010-09-14 18:57:14 -07004457 children[i].setActivated(activated);
4458 }
4459 }
4460
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004461 @Override
4462 protected void dispatchSetPressed(boolean pressed) {
4463 final View[] children = mChildren;
4464 final int count = mChildrenCount;
4465 for (int i = 0; i < count; i++) {
Adam Powell035a1fc2012-02-27 15:23:50 -08004466 final View child = children[i];
4467 // Children that are clickable on their own should not
4468 // show a pressed state when their parent view does.
4469 // Clearing a pressed state always propagates.
4470 if (!pressed || (!child.isClickable() && !child.isLongClickable())) {
4471 child.setPressed(pressed);
4472 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004473 }
4474 }
4475
Alan Viveretteb942b6f2014-12-08 10:37:39 -08004476 /**
4477 * Dispatches drawable hotspot changes to child views that meet at least
4478 * one of the following criteria:
4479 * <ul>
4480 * <li>Returns {@code false} from both {@link View#isClickable()} and
4481 * {@link View#isLongClickable()}</li>
4482 * <li>Requests duplication of parent state via
4483 * {@link View#setDuplicateParentStateEnabled(boolean)}</li>
4484 * </ul>
4485 *
4486 * @param x hotspot x coordinate
4487 * @param y hotspot y coordinate
4488 * @see #drawableHotspotChanged(float, float)
4489 */
4490 @Override
4491 public void dispatchDrawableHotspotChanged(float x, float y) {
4492 final int count = mChildrenCount;
4493 if (count == 0) {
4494 return;
4495 }
4496
4497 final View[] children = mChildren;
4498 for (int i = 0; i < count; i++) {
4499 final View child = children[i];
4500 // Children that are clickable on their own should not
4501 // receive hotspots when their parent view does.
4502 final boolean nonActionable = !child.isClickable() && !child.isLongClickable();
4503 final boolean duplicatesState = (child.mViewFlags & DUPLICATE_PARENT_STATE) != 0;
4504 if (nonActionable || duplicatesState) {
4505 final float[] point = getTempPoint();
4506 point[0] = x;
4507 point[1] = y;
4508 transformPointToViewLocal(point, child);
4509 child.drawableHotspotChanged(point[0], point[1]);
4510 }
4511 }
4512 }
4513
Adam Powell14874662013-07-18 19:42:41 -07004514 @Override
4515 void dispatchCancelPendingInputEvents() {
4516 super.dispatchCancelPendingInputEvents();
4517
4518 final View[] children = mChildren;
4519 final int count = mChildrenCount;
4520 for (int i = 0; i < count; i++) {
4521 children[i].dispatchCancelPendingInputEvents();
4522 }
4523 }
4524
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004525 /**
4526 * When this property is set to true, this ViewGroup supports static transformations on
4527 * children; this causes
4528 * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} to be
4529 * invoked when a child is drawn.
4530 *
4531 * Any subclass overriding
4532 * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} should
4533 * set this property to true.
4534 *
4535 * @param enabled True to enable static transformations on children, false otherwise.
4536 *
Chet Haase599913d2012-07-23 16:22:05 -07004537 * @see #getChildStaticTransformation(View, android.view.animation.Transformation)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004538 */
4539 protected void setStaticTransformationsEnabled(boolean enabled) {
4540 setBooleanFlag(FLAG_SUPPORT_STATIC_TRANSFORMATIONS, enabled);
4541 }
4542
4543 /**
Chet Haase2d46fcc2011-12-19 18:01:05 -08004544 * Sets <code>t</code> to be the static transformation of the child, if set, returning a
4545 * boolean to indicate whether a static transform was set. The default implementation
4546 * simply returns <code>false</code>; subclasses may override this method for different
Chet Haase599913d2012-07-23 16:22:05 -07004547 * behavior. {@link #setStaticTransformationsEnabled(boolean)} must be set to true
4548 * for this method to be called.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004549 *
Chet Haase2d46fcc2011-12-19 18:01:05 -08004550 * @param child The child view whose static transform is being requested
4551 * @param t The Transformation which will hold the result
4552 * @return true if the transformation was set, false otherwise
Romain Guy8506ab42009-06-11 17:35:47 -07004553 * @see #setStaticTransformationsEnabled(boolean)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004554 */
4555 protected boolean getChildStaticTransformation(View child, Transformation t) {
4556 return false;
4557 }
4558
Romain Guyf6991302013-06-05 17:19:01 -07004559 Transformation getChildTransformation() {
4560 if (mChildTransformation == null) {
4561 mChildTransformation = new Transformation();
4562 }
4563 return mChildTransformation;
4564 }
4565
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004566 /**
4567 * {@hide}
4568 */
4569 @Override
Alan Viverette8e1a7292017-02-27 10:57:58 -05004570 protected <T extends View> T findViewTraversal(@IdRes int id) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004571 if (id == mID) {
Alan Viverette8e1a7292017-02-27 10:57:58 -05004572 return (T) this;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004573 }
4574
4575 final View[] where = mChildren;
4576 final int len = mChildrenCount;
4577
4578 for (int i = 0; i < len; i++) {
4579 View v = where[i];
4580
Dianne Hackborn4702a852012-08-17 15:18:29 -07004581 if ((v.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004582 v = v.findViewById(id);
4583
4584 if (v != null) {
Alan Viverette8e1a7292017-02-27 10:57:58 -05004585 return (T) v;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004586 }
4587 }
4588 }
4589
4590 return null;
4591 }
4592
4593 /**
4594 * {@hide}
4595 */
4596 @Override
Alan Viverette8e1a7292017-02-27 10:57:58 -05004597 protected <T extends View> T findViewWithTagTraversal(Object tag) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004598 if (tag != null && tag.equals(mTag)) {
Alan Viverette8e1a7292017-02-27 10:57:58 -05004599 return (T) this;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004600 }
4601
4602 final View[] where = mChildren;
4603 final int len = mChildrenCount;
4604
4605 for (int i = 0; i < len; i++) {
4606 View v = where[i];
4607
Dianne Hackborn4702a852012-08-17 15:18:29 -07004608 if ((v.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004609 v = v.findViewWithTag(tag);
4610
4611 if (v != null) {
Alan Viverette8e1a7292017-02-27 10:57:58 -05004612 return (T) v;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004613 }
4614 }
4615 }
4616
4617 return null;
4618 }
4619
4620 /**
Jeff Brown4e6319b2010-12-13 10:36:51 -08004621 * {@hide}
4622 */
4623 @Override
Alan Viverette8e1a7292017-02-27 10:57:58 -05004624 protected <T extends View> T findViewByPredicateTraversal(Predicate<View> predicate,
4625 View childToSkip) {
Paul Duffinca4964c2017-02-07 15:04:10 +00004626 if (predicate.test(this)) {
Alan Viverette8e1a7292017-02-27 10:57:58 -05004627 return (T) this;
Jeff Brown4e6319b2010-12-13 10:36:51 -08004628 }
4629
4630 final View[] where = mChildren;
4631 final int len = mChildrenCount;
4632
4633 for (int i = 0; i < len; i++) {
4634 View v = where[i];
4635
Dianne Hackborn4702a852012-08-17 15:18:29 -07004636 if (v != childToSkip && (v.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
Jeff Brown4e6319b2010-12-13 10:36:51 -08004637 v = v.findViewByPredicate(predicate);
4638
4639 if (v != null) {
Alan Viverette8e1a7292017-02-27 10:57:58 -05004640 return (T) v;
Jeff Brown4e6319b2010-12-13 10:36:51 -08004641 }
4642 }
4643 }
4644
4645 return null;
4646 }
4647
4648 /**
Chet Haasec633d2f2015-04-07 10:29:39 -07004649 * This method adds a view to this container at the specified index purely for the
4650 * purposes of allowing that view to draw even though it is not a normal child of
4651 * the container. That is, the view does not participate in layout, focus, accessibility,
4652 * input, or other normal view operations; it is purely an item to be drawn during the normal
4653 * rendering operation of this container. The index that it is added at is the order
4654 * in which it will be drawn, with respect to the other views in the container.
4655 * For example, a transient view added at index 0 will be drawn before all other views
4656 * in the container because it will be drawn first (including before any real view
4657 * at index 0). There can be more than one transient view at any particular index;
4658 * these views will be drawn in the order in which they were added to the list of
4659 * transient views. The index of transient views can also be greater than the number
4660 * of normal views in the container; that just means that they will be drawn after all
4661 * other views are drawn.
4662 *
4663 * <p>Note that since transient views do not participate in layout, they must be sized
4664 * manually or, more typically, they should just use the size that they had before they
4665 * were removed from their container.</p>
4666 *
4667 * <p>Transient views are useful for handling animations of views that have been removed
4668 * from the container, but which should be animated out after the removal. Adding these
4669 * views as transient views allows them to participate in drawing without side-effecting
4670 * the layout of the container.</p>
4671 *
4672 * <p>Transient views must always be explicitly {@link #removeTransientView(View) removed}
4673 * from the container when they are no longer needed. For example, a transient view
4674 * which is added in order to fade it out in its old location should be removed
4675 * once the animation is complete.</p>
4676 *
4677 * @param view The view to be added
4678 * @param index The index at which this view should be drawn, must be >= 0.
4679 * This value is relative to the {@link #getChildAt(int) index} values in the normal
4680 * child list of this container, where any transient view at a particular index will
4681 * be drawn before any normal child at that same index.
Chris Craik66b41392015-04-17 10:08:10 -07004682 *
4683 * @hide
Chet Haasec633d2f2015-04-07 10:29:39 -07004684 */
Mathew Inwoode5ad5982018-08-17 15:07:52 +01004685 @UnsupportedAppUsage
Chet Haasec633d2f2015-04-07 10:29:39 -07004686 public void addTransientView(View view, int index) {
4687 if (index < 0) {
4688 return;
4689 }
4690 if (mTransientIndices == null) {
4691 mTransientIndices = new ArrayList<Integer>();
4692 mTransientViews = new ArrayList<View>();
4693 }
4694 final int oldSize = mTransientIndices.size();
4695 if (oldSize > 0) {
4696 int insertionIndex;
4697 for (insertionIndex = 0; insertionIndex < oldSize; ++insertionIndex) {
4698 if (index < mTransientIndices.get(insertionIndex)) {
4699 break;
4700 }
4701 }
4702 mTransientIndices.add(insertionIndex, index);
4703 mTransientViews.add(insertionIndex, view);
4704 } else {
4705 mTransientIndices.add(index);
4706 mTransientViews.add(view);
4707 }
4708 view.mParent = this;
4709 view.dispatchAttachedToWindow(mAttachInfo, (mViewFlags&VISIBILITY_MASK));
4710 invalidate(true);
4711 }
4712
4713 /**
4714 * Removes a view from the list of transient views in this container. If there is no
4715 * such transient view, this method does nothing.
4716 *
4717 * @param view The transient view to be removed
Chris Craik66b41392015-04-17 10:08:10 -07004718 *
4719 * @hide
Chet Haasec633d2f2015-04-07 10:29:39 -07004720 */
Mathew Inwoode5ad5982018-08-17 15:07:52 +01004721 @UnsupportedAppUsage
Chet Haasec633d2f2015-04-07 10:29:39 -07004722 public void removeTransientView(View view) {
4723 if (mTransientViews == null) {
4724 return;
4725 }
4726 final int size = mTransientViews.size();
4727 for (int i = 0; i < size; ++i) {
4728 if (view == mTransientViews.get(i)) {
4729 mTransientViews.remove(i);
4730 mTransientIndices.remove(i);
4731 view.mParent = null;
4732 view.dispatchDetachedFromWindow();
4733 invalidate(true);
4734 return;
4735 }
4736 }
4737 }
4738
4739 /**
4740 * Returns the number of transient views in this container. Specific transient
4741 * views and the index at which they were added can be retrieved via
4742 * {@link #getTransientView(int)} and {@link #getTransientViewIndex(int)}.
4743 *
4744 * @see #addTransientView(View, int)
4745 * @return The number of transient views in this container
Chris Craik66b41392015-04-17 10:08:10 -07004746 *
4747 * @hide
Chet Haasec633d2f2015-04-07 10:29:39 -07004748 */
Mathew Inwoode5ad5982018-08-17 15:07:52 +01004749 @UnsupportedAppUsage
Chet Haasec633d2f2015-04-07 10:29:39 -07004750 public int getTransientViewCount() {
4751 return mTransientIndices == null ? 0 : mTransientIndices.size();
4752 }
4753
4754 /**
4755 * Given a valid position within the list of transient views, returns the index of
4756 * the transient view at that position.
4757 *
4758 * @param position The position of the index being queried. Must be at least 0
4759 * and less than the value returned by {@link #getTransientViewCount()}.
4760 * @return The index of the transient view stored in the given position if the
4761 * position is valid, otherwise -1
Chris Craik66b41392015-04-17 10:08:10 -07004762 *
4763 * @hide
Chet Haasec633d2f2015-04-07 10:29:39 -07004764 */
4765 public int getTransientViewIndex(int position) {
4766 if (position < 0 || mTransientIndices == null || position >= mTransientIndices.size()) {
4767 return -1;
4768 }
4769 return mTransientIndices.get(position);
4770 }
4771
4772 /**
4773 * Given a valid position within the list of transient views, returns the
4774 * transient view at that position.
4775 *
4776 * @param position The position of the view being queried. Must be at least 0
4777 * and less than the value returned by {@link #getTransientViewCount()}.
4778 * @return The transient view stored in the given position if the
4779 * position is valid, otherwise null
Chris Craik66b41392015-04-17 10:08:10 -07004780 *
4781 * @hide
Chet Haasec633d2f2015-04-07 10:29:39 -07004782 */
Mathew Inwoode5ad5982018-08-17 15:07:52 +01004783 @UnsupportedAppUsage
Chet Haasec633d2f2015-04-07 10:29:39 -07004784 public View getTransientView(int position) {
4785 if (mTransientViews == null || position >= mTransientViews.size()) {
4786 return null;
4787 }
4788 return mTransientViews.get(position);
4789 }
4790
4791 /**
Romain Guy393a52c2012-05-22 20:21:08 -07004792 * <p>Adds a child view. If no layout parameters are already set on the child, the
4793 * default parameters for this ViewGroup are set on the child.</p>
Filip Gruszczynskia33bdf32015-11-19 18:22:16 -08004794 *
Romain Guy393a52c2012-05-22 20:21:08 -07004795 * <p><strong>Note:</strong> do not invoke this method from
4796 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
4797 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004798 *
4799 * @param child the child view to add
4800 *
4801 * @see #generateDefaultLayoutParams()
4802 */
4803 public void addView(View child) {
4804 addView(child, -1);
4805 }
4806
4807 /**
4808 * Adds a child view. If no layout parameters are already set on the child, the
4809 * default parameters for this ViewGroup are set on the child.
Filip Gruszczynskia33bdf32015-11-19 18:22:16 -08004810 *
Romain Guy393a52c2012-05-22 20:21:08 -07004811 * <p><strong>Note:</strong> do not invoke this method from
4812 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
4813 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004814 *
4815 * @param child the child view to add
4816 * @param index the position at which to add the child
4817 *
4818 * @see #generateDefaultLayoutParams()
4819 */
4820 public void addView(View child, int index) {
Adam Powell45a9da52014-10-09 09:44:18 -07004821 if (child == null) {
4822 throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup");
4823 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004824 LayoutParams params = child.getLayoutParams();
4825 if (params == null) {
4826 params = generateDefaultLayoutParams();
4827 if (params == null) {
4828 throw new IllegalArgumentException("generateDefaultLayoutParams() cannot return null");
4829 }
4830 }
4831 addView(child, index, params);
4832 }
4833
4834 /**
4835 * Adds a child view with this ViewGroup's default layout parameters and the
4836 * specified width and height.
4837 *
Romain Guy393a52c2012-05-22 20:21:08 -07004838 * <p><strong>Note:</strong> do not invoke this method from
4839 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
4840 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
4841 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004842 * @param child the child view to add
4843 */
4844 public void addView(View child, int width, int height) {
4845 final LayoutParams params = generateDefaultLayoutParams();
4846 params.width = width;
4847 params.height = height;
4848 addView(child, -1, params);
4849 }
4850
4851 /**
4852 * Adds a child view with the specified layout parameters.
4853 *
Romain Guy393a52c2012-05-22 20:21:08 -07004854 * <p><strong>Note:</strong> do not invoke this method from
4855 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
4856 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
4857 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004858 * @param child the child view to add
4859 * @param params the layout parameters to set on the child
4860 */
Alan Viverettebe463f22016-01-21 10:50:10 -05004861 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004862 public void addView(View child, LayoutParams params) {
4863 addView(child, -1, params);
4864 }
4865
4866 /**
4867 * Adds a child view with the specified layout parameters.
4868 *
Romain Guy393a52c2012-05-22 20:21:08 -07004869 * <p><strong>Note:</strong> do not invoke this method from
4870 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
4871 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
4872 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004873 * @param child the child view to add
Alan Viverette77bb6f12015-02-11 17:24:33 -08004874 * @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 -08004875 * @param params the layout parameters to set on the child
4876 */
4877 public void addView(View child, int index, LayoutParams params) {
4878 if (DBG) {
4879 System.out.println(this + " addView");
4880 }
4881
Adam Powell45a9da52014-10-09 09:44:18 -07004882 if (child == null) {
4883 throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup");
4884 }
4885
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004886 // addViewInner() will call child.requestLayout() when setting the new LayoutParams
4887 // therefore, we call requestLayout() on ourselves before, so that the child's request
4888 // will be blocked at our level
4889 requestLayout();
Romain Guy849d0a32011-02-01 17:20:48 -08004890 invalidate(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004891 addViewInner(child, index, params, false);
4892 }
4893
Alan Viverettebe463f22016-01-21 10:50:10 -05004894 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004895 public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
4896 if (!checkLayoutParams(params)) {
4897 throw new IllegalArgumentException("Invalid LayoutParams supplied to " + this);
4898 }
4899 if (view.mParent != this) {
4900 throw new IllegalArgumentException("Given view not a child of " + this);
4901 }
4902 view.setLayoutParams(params);
4903 }
4904
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004905 protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
4906 return p != null;
4907 }
4908
4909 /**
4910 * Interface definition for a callback to be invoked when the hierarchy
4911 * within this view changed. The hierarchy changes whenever a child is added
4912 * to or removed from this view.
4913 */
4914 public interface OnHierarchyChangeListener {
4915 /**
4916 * Called when a new child is added to a parent view.
4917 *
4918 * @param parent the view in which a child was added
4919 * @param child the new child view added in the hierarchy
4920 */
4921 void onChildViewAdded(View parent, View child);
4922
4923 /**
4924 * Called when a child is removed from a parent view.
4925 *
4926 * @param parent the view from which the child was removed
4927 * @param child the child removed from the hierarchy
4928 */
4929 void onChildViewRemoved(View parent, View child);
4930 }
4931
4932 /**
4933 * Register a callback to be invoked when a child is added to or removed
4934 * from this view.
4935 *
4936 * @param listener the callback to invoke on hierarchy change
4937 */
4938 public void setOnHierarchyChangeListener(OnHierarchyChangeListener listener) {
4939 mOnHierarchyChangeListener = listener;
4940 }
4941
Mathew Inwoode5ad5982018-08-17 15:07:52 +01004942 @UnsupportedAppUsage
Adam Powell6690d012015-06-17 16:41:56 -07004943 void dispatchViewAdded(View child) {
4944 onViewAdded(child);
Philip Milnef51d91c2011-07-18 16:12:19 -07004945 if (mOnHierarchyChangeListener != null) {
4946 mOnHierarchyChangeListener.onChildViewAdded(this, child);
4947 }
4948 }
4949
4950 /**
Adam Powell6690d012015-06-17 16:41:56 -07004951 * Called when a new child is added to this ViewGroup. Overrides should always
4952 * call super.onViewAdded.
4953 *
4954 * @param child the added child view
Philip Milnef51d91c2011-07-18 16:12:19 -07004955 */
Adam Powell6690d012015-06-17 16:41:56 -07004956 public void onViewAdded(View child) {
4957 }
4958
Mathew Inwoode5ad5982018-08-17 15:07:52 +01004959 @UnsupportedAppUsage
Adam Powell6690d012015-06-17 16:41:56 -07004960 void dispatchViewRemoved(View child) {
4961 onViewRemoved(child);
Philip Milnef51d91c2011-07-18 16:12:19 -07004962 if (mOnHierarchyChangeListener != null) {
4963 mOnHierarchyChangeListener.onChildViewRemoved(this, child);
4964 }
4965 }
4966
Adam Powell6690d012015-06-17 16:41:56 -07004967 /**
4968 * Called when a child view is removed from this ViewGroup. Overrides should always
4969 * call super.onViewRemoved.
4970 *
4971 * @param child the removed child view
4972 */
4973 public void onViewRemoved(View child) {
4974 }
4975
Philip Milnecfb631b2012-10-26 10:51:46 -07004976 private void clearCachedLayoutMode() {
Svetoslav6254f482013-06-04 17:22:14 -07004977 if (!hasBooleanFlag(FLAG_LAYOUT_MODE_WAS_EXPLICITLY_SET)) {
Philip Milnecfb631b2012-10-26 10:51:46 -07004978 mLayoutMode = LAYOUT_MODE_UNDEFINED;
4979 }
4980 }
4981
4982 @Override
4983 protected void onAttachedToWindow() {
4984 super.onAttachedToWindow();
4985 clearCachedLayoutMode();
4986 }
4987
4988 @Override
4989 protected void onDetachedFromWindow() {
4990 super.onDetachedFromWindow();
4991 clearCachedLayoutMode();
4992 }
4993
John Reck2de950d2017-01-25 10:58:30 -08004994 /** @hide */
4995 @Override
4996 protected void destroyHardwareResources() {
4997 super.destroyHardwareResources();
4998 int count = getChildCount();
4999 for (int i = 0; i < count; i++) {
5000 getChildAt(i).destroyHardwareResources();
5001 }
5002 }
5003
Philip Milnef51d91c2011-07-18 16:12:19 -07005004 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005005 * Adds a view during layout. This is useful if in your onLayout() method,
5006 * you need to add more views (as does the list view for example).
5007 *
5008 * If index is negative, it means put it at the end of the list.
5009 *
5010 * @param child the view to add to the group
Alan Viverette77bb6f12015-02-11 17:24:33 -08005011 * @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 -08005012 * @param params the layout parameters to associate with the child
5013 * @return true if the child was added, false otherwise
5014 */
5015 protected boolean addViewInLayout(View child, int index, LayoutParams params) {
5016 return addViewInLayout(child, index, params, false);
5017 }
5018
5019 /**
5020 * Adds a view during layout. This is useful if in your onLayout() method,
5021 * you need to add more views (as does the list view for example).
5022 *
5023 * If index is negative, it means put it at the end of the list.
5024 *
5025 * @param child the view to add to the group
Alan Viverette77bb6f12015-02-11 17:24:33 -08005026 * @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 -08005027 * @param params the layout parameters to associate with the child
5028 * @param preventRequestLayout if true, calling this method will not trigger a
5029 * layout request on child
5030 * @return true if the child was added, false otherwise
5031 */
5032 protected boolean addViewInLayout(View child, int index, LayoutParams params,
5033 boolean preventRequestLayout) {
Adam Powell45a9da52014-10-09 09:44:18 -07005034 if (child == null) {
5035 throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup");
5036 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005037 child.mParent = null;
5038 addViewInner(child, index, params, preventRequestLayout);
Dianne Hackborn4702a852012-08-17 15:18:29 -07005039 child.mPrivateFlags = (child.mPrivateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005040 return true;
5041 }
5042
5043 /**
5044 * Prevents the specified child to be laid out during the next layout pass.
5045 *
5046 * @param child the child on which to perform the cleanup
5047 */
5048 protected void cleanupLayoutState(View child) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07005049 child.mPrivateFlags &= ~View.PFLAG_FORCE_LAYOUT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005050 }
5051
5052 private void addViewInner(View child, int index, LayoutParams params,
5053 boolean preventRequestLayout) {
5054
Chet Haasee8e45d32011-03-02 17:07:35 -08005055 if (mTransition != null) {
5056 // Don't prevent other add transitions from completing, but cancel remove
5057 // transitions to let them complete the process before we add to the container
5058 mTransition.cancel(LayoutTransition.DISAPPEARING);
Chet Haaseadd65772011-02-09 16:47:29 -08005059 }
5060
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005061 if (child.getParent() != null) {
5062 throw new IllegalStateException("The specified child already has a parent. " +
5063 "You must call removeView() on the child's parent first.");
5064 }
5065
Chet Haase21cd1382010-09-01 17:42:29 -07005066 if (mTransition != null) {
Chet Haase5e25c2c2010-09-16 11:15:56 -07005067 mTransition.addChild(this, child);
Chet Haase21cd1382010-09-01 17:42:29 -07005068 }
5069
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005070 if (!checkLayoutParams(params)) {
5071 params = generateLayoutParams(params);
5072 }
5073
5074 if (preventRequestLayout) {
5075 child.mLayoutParams = params;
5076 } else {
5077 child.setLayoutParams(params);
5078 }
5079
5080 if (index < 0) {
5081 index = mChildrenCount;
5082 }
5083
5084 addInArray(child, index);
5085
5086 // tell our children
5087 if (preventRequestLayout) {
5088 child.assignParent(this);
5089 } else {
5090 child.mParent = this;
Evan Roskycd80e612018-05-17 17:46:09 -07005091 }
5092 if (child.hasUnhandledKeyListener()) {
5093 incrementChildUnhandledKeyListeners();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005094 }
5095
Evan Rosky2ae1bf52017-05-11 11:18:45 -07005096 final boolean childHasFocus = child.hasFocus();
5097 if (childHasFocus) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005098 requestChildFocus(child, child.findFocus());
5099 }
Romain Guy8506ab42009-06-11 17:35:47 -07005100
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005101 AttachInfo ai = mAttachInfo;
Adam Powell4b867882011-09-16 12:59:46 -07005102 if (ai != null && (mGroupFlags & FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW) == 0) {
Romain Guy8506ab42009-06-11 17:35:47 -07005103 boolean lastKeepOn = ai.mKeepScreenOn;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005104 ai.mKeepScreenOn = false;
5105 child.dispatchAttachedToWindow(mAttachInfo, (mViewFlags&VISIBILITY_MASK));
5106 if (ai.mKeepScreenOn) {
5107 needGlobalAttributesUpdate(true);
5108 }
5109 ai.mKeepScreenOn = lastKeepOn;
5110 }
5111
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07005112 if (child.isLayoutDirectionInherited()) {
Fabrice Di Meglioa7e0bcd2012-10-16 19:55:01 -07005113 child.resetRtlProperties();
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07005114 }
5115
Adam Powell6690d012015-06-17 16:41:56 -07005116 dispatchViewAdded(child);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005117
5118 if ((child.mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE) {
5119 mGroupFlags |= FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE;
5120 }
Adam Powell539ee872012-02-03 19:00:49 -08005121
5122 if (child.hasTransientState()) {
5123 childHasTransientStateChanged(child, true);
5124 }
Svetoslav6254f482013-06-04 17:22:14 -07005125
Svetoslav8e3feb12014-02-24 13:46:47 -08005126 if (child.getVisibility() != View.GONE) {
Eugene Susla72c510f2018-01-23 21:12:11 +00005127 notifySubtreeAccessibilityStateChangedIfNeeded();
Svetoslav6254f482013-06-04 17:22:14 -07005128 }
Chet Haasec633d2f2015-04-07 10:29:39 -07005129
5130 if (mTransientIndices != null) {
5131 final int transientCount = mTransientIndices.size();
5132 for (int i = 0; i < transientCount; ++i) {
5133 final int oldIndex = mTransientIndices.get(i);
5134 if (index <= oldIndex) {
5135 mTransientIndices.set(i, oldIndex + 1);
5136 }
5137 }
5138 }
Vadim Tryshev02ed4a02015-10-23 17:39:33 -07005139
5140 if (mCurrentDragStartEvent != null && child.getVisibility() == VISIBLE) {
5141 notifyChildOfDragStart(child);
5142 }
Vadim Tryshev5ca73982017-01-04 17:24:43 -08005143
5144 if (child.hasDefaultFocus()) {
5145 // When adding a child that contains default focus, either during inflation or while
5146 // manually assembling the hierarchy, update the ancestor default-focus chain.
5147 setDefaultFocus(child);
5148 }
Svetoslav Ganov24c90452017-12-27 15:17:14 -08005149
5150 touchAccessibilityNodeProviderIfNeeded(child);
5151 }
5152
5153 /**
5154 * We may need to touch the provider to bring up the a11y layer. In a11y mode
5155 * clients inspect the screen or the user touches it which triggers bringing up
5156 * of the a11y infrastructure while in autofill mode we want the infra up and
5157 * running from the beginning since we watch for a11y events to drive autofill.
5158 */
5159 private void touchAccessibilityNodeProviderIfNeeded(View child) {
5160 if (mContext.isAutofillCompatibilityEnabled()) {
5161 child.getAccessibilityNodeProvider();
5162 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005163 }
5164
5165 private void addInArray(View child, int index) {
5166 View[] children = mChildren;
5167 final int count = mChildrenCount;
5168 final int size = children.length;
5169 if (index == count) {
5170 if (size == count) {
5171 mChildren = new View[size + ARRAY_CAPACITY_INCREMENT];
5172 System.arraycopy(children, 0, mChildren, 0, size);
5173 children = mChildren;
5174 }
5175 children[mChildrenCount++] = child;
5176 } else if (index < count) {
5177 if (size == count) {
5178 mChildren = new View[size + ARRAY_CAPACITY_INCREMENT];
5179 System.arraycopy(children, 0, mChildren, 0, index);
5180 System.arraycopy(children, index, mChildren, index + 1, count - index);
5181 children = mChildren;
5182 } else {
5183 System.arraycopy(children, index, children, index + 1, count - index);
5184 }
5185 children[index] = child;
5186 mChildrenCount++;
Joe Onorato03ab0c72011-01-06 15:46:27 -08005187 if (mLastTouchDownIndex >= index) {
5188 mLastTouchDownIndex++;
5189 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005190 } else {
5191 throw new IndexOutOfBoundsException("index=" + index + " count=" + count);
5192 }
5193 }
5194
5195 // This method also sets the child's mParent to null
5196 private void removeFromArray(int index) {
5197 final View[] children = mChildren;
Chet Haase21cd1382010-09-01 17:42:29 -07005198 if (!(mTransitioningViews != null && mTransitioningViews.contains(children[index]))) {
5199 children[index].mParent = null;
5200 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005201 final int count = mChildrenCount;
5202 if (index == count - 1) {
5203 children[--mChildrenCount] = null;
5204 } else if (index >= 0 && index < count) {
5205 System.arraycopy(children, index + 1, children, index, count - index - 1);
5206 children[--mChildrenCount] = null;
5207 } else {
5208 throw new IndexOutOfBoundsException();
5209 }
Joe Onorato03ab0c72011-01-06 15:46:27 -08005210 if (mLastTouchDownIndex == index) {
5211 mLastTouchDownTime = 0;
5212 mLastTouchDownIndex = -1;
5213 } else if (mLastTouchDownIndex > index) {
5214 mLastTouchDownIndex--;
5215 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005216 }
5217
5218 // This method also sets the children's mParent to null
5219 private void removeFromArray(int start, int count) {
5220 final View[] children = mChildren;
5221 final int childrenCount = mChildrenCount;
5222
5223 start = Math.max(0, start);
5224 final int end = Math.min(childrenCount, start + count);
5225
5226 if (start == end) {
5227 return;
5228 }
5229
5230 if (end == childrenCount) {
5231 for (int i = start; i < end; i++) {
5232 children[i].mParent = null;
5233 children[i] = null;
5234 }
5235 } else {
5236 for (int i = start; i < end; i++) {
5237 children[i].mParent = null;
5238 }
5239
5240 // Since we're looping above, we might as well do the copy, but is arraycopy()
5241 // faster than the extra 2 bounds checks we would do in the loop?
5242 System.arraycopy(children, end, children, start, childrenCount - end);
5243
5244 for (int i = childrenCount - (end - start); i < childrenCount; i++) {
5245 children[i] = null;
5246 }
5247 }
5248
5249 mChildrenCount -= (end - start);
5250 }
5251
5252 private void bindLayoutAnimation(View child) {
5253 Animation a = mLayoutAnimationController.getAnimationForView(child);
5254 child.setAnimation(a);
5255 }
5256
5257 /**
5258 * Subclasses should override this method to set layout animation
5259 * parameters on the supplied child.
5260 *
5261 * @param child the child to associate with animation parameters
5262 * @param params the child's layout parameters which hold the animation
5263 * parameters
5264 * @param index the index of the child in the view group
5265 * @param count the number of children in the view group
5266 */
5267 protected void attachLayoutAnimationParameters(View child,
5268 LayoutParams params, int index, int count) {
5269 LayoutAnimationController.AnimationParameters animationParams =
5270 params.layoutAnimationParameters;
5271 if (animationParams == null) {
5272 animationParams = new LayoutAnimationController.AnimationParameters();
5273 params.layoutAnimationParameters = animationParams;
5274 }
5275
5276 animationParams.count = count;
5277 animationParams.index = index;
5278 }
5279
5280 /**
5281 * {@inheritDoc}
Filip Gruszczynskia33bdf32015-11-19 18:22:16 -08005282 *
Romain Guy393a52c2012-05-22 20:21:08 -07005283 * <p><strong>Note:</strong> do not invoke this method from
5284 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
5285 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005286 */
Alan Viverettebe463f22016-01-21 10:50:10 -05005287 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005288 public void removeView(View view) {
Alan Viverette177ec4602014-10-17 13:34:50 -07005289 if (removeViewInternal(view)) {
5290 requestLayout();
5291 invalidate(true);
5292 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005293 }
5294
5295 /**
5296 * Removes a view during layout. This is useful if in your onLayout() method,
5297 * you need to remove more views.
5298 *
Romain Guy393a52c2012-05-22 20:21:08 -07005299 * <p><strong>Note:</strong> do not invoke this method from
5300 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
5301 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
Filip Gruszczynskia33bdf32015-11-19 18:22:16 -08005302 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005303 * @param view the view to remove from the group
5304 */
5305 public void removeViewInLayout(View view) {
5306 removeViewInternal(view);
5307 }
5308
5309 /**
5310 * Removes a range of views during layout. This is useful if in your onLayout() method,
5311 * you need to remove more views.
5312 *
Romain Guy393a52c2012-05-22 20:21:08 -07005313 * <p><strong>Note:</strong> do not invoke this method from
5314 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
5315 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
5316 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005317 * @param start the index of the first view to remove from the group
5318 * @param count the number of views to remove from the group
5319 */
5320 public void removeViewsInLayout(int start, int count) {
5321 removeViewsInternal(start, count);
5322 }
5323
5324 /**
5325 * Removes the view at the specified position in the group.
5326 *
Romain Guy393a52c2012-05-22 20:21:08 -07005327 * <p><strong>Note:</strong> do not invoke this method from
5328 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
5329 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
Filip Gruszczynskia33bdf32015-11-19 18:22:16 -08005330 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005331 * @param index the position in the group of the view to remove
5332 */
5333 public void removeViewAt(int index) {
5334 removeViewInternal(index, getChildAt(index));
5335 requestLayout();
Romain Guy849d0a32011-02-01 17:20:48 -08005336 invalidate(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005337 }
5338
5339 /**
5340 * Removes the specified range of views from the group.
5341 *
Romain Guy393a52c2012-05-22 20:21:08 -07005342 * <p><strong>Note:</strong> do not invoke this method from
5343 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
5344 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
5345 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005346 * @param start the first position in the group of the range of views to remove
5347 * @param count the number of views to remove
5348 */
5349 public void removeViews(int start, int count) {
5350 removeViewsInternal(start, count);
5351 requestLayout();
Romain Guy849d0a32011-02-01 17:20:48 -08005352 invalidate(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005353 }
5354
Alan Viverette177ec4602014-10-17 13:34:50 -07005355 private boolean removeViewInternal(View view) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005356 final int index = indexOfChild(view);
5357 if (index >= 0) {
5358 removeViewInternal(index, view);
Alan Viverette177ec4602014-10-17 13:34:50 -07005359 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005360 }
Alan Viverette177ec4602014-10-17 13:34:50 -07005361 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005362 }
5363
5364 private void removeViewInternal(int index, View view) {
Chet Haase21cd1382010-09-01 17:42:29 -07005365 if (mTransition != null) {
Chet Haase5e25c2c2010-09-16 11:15:56 -07005366 mTransition.removeChild(this, view);
Chet Haase21cd1382010-09-01 17:42:29 -07005367 }
5368
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005369 boolean clearChildFocus = false;
5370 if (view == mFocused) {
Alan Viverette223622a2013-12-17 13:29:02 -08005371 view.unFocus(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005372 clearChildFocus = true;
5373 }
Evan Rosky53fcf112017-01-26 14:37:55 -08005374 if (view == mFocusedInCluster) {
Evan Rosky0e8a6832017-04-10 12:35:15 -07005375 clearFocusedInCluster(view);
Vadim Tryshev01d8c492016-12-15 11:33:15 -08005376 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005377
Alan Viverette632af842014-10-28 13:45:11 -07005378 view.clearAccessibilityFocus();
Svetoslav Ganov961bf0e2012-05-08 09:40:03 -07005379
Jeff Brown59a422e2012-04-19 15:19:19 -07005380 cancelTouchTarget(view);
5381 cancelHoverTarget(view);
5382
Chet Haase21cd1382010-09-01 17:42:29 -07005383 if (view.getAnimation() != null ||
5384 (mTransitioningViews != null && mTransitioningViews.contains(view))) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005385 addDisappearingView(view);
5386 } else if (view.mAttachInfo != null) {
5387 view.dispatchDetachedFromWindow();
5388 }
5389
Adam Powell539ee872012-02-03 19:00:49 -08005390 if (view.hasTransientState()) {
5391 childHasTransientStateChanged(view, false);
5392 }
5393
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005394 needGlobalAttributesUpdate(false);
Romain Guy8506ab42009-06-11 17:35:47 -07005395
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005396 removeFromArray(index);
5397
Evan Rosky4807ae22018-03-22 16:04:15 -07005398 if (view.hasUnhandledKeyListener()) {
5399 decrementChildUnhandledKeyListeners();
5400 }
5401
Evan Rosky53fcf112017-01-26 14:37:55 -08005402 if (view == mDefaultFocus) {
5403 clearDefaultFocus(view);
5404 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005405 if (clearChildFocus) {
5406 clearChildFocus(view);
Svetoslav Ganov149567f2013-01-08 15:23:34 -08005407 if (!rootViewRequestFocus()) {
5408 notifyGlobalFocusCleared(this);
5409 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07005410 }
Romain Guy6fb05632012-11-29 10:50:33 -08005411
Adam Powell6690d012015-06-17 16:41:56 -07005412 dispatchViewRemoved(view);
Svetoslav6254f482013-06-04 17:22:14 -07005413
Svetoslav8e3feb12014-02-24 13:46:47 -08005414 if (view.getVisibility() != View.GONE) {
Eugene Susla72c510f2018-01-23 21:12:11 +00005415 notifySubtreeAccessibilityStateChangedIfNeeded();
Svetoslav6254f482013-06-04 17:22:14 -07005416 }
Chet Haasec633d2f2015-04-07 10:29:39 -07005417
5418 int transientCount = mTransientIndices == null ? 0 : mTransientIndices.size();
5419 for (int i = 0; i < transientCount; ++i) {
5420 final int oldIndex = mTransientIndices.get(i);
5421 if (index < oldIndex) {
5422 mTransientIndices.set(i, oldIndex - 1);
5423 }
5424 }
Vadim Tryshev02ed4a02015-10-23 17:39:33 -07005425
5426 if (mCurrentDragStartEvent != null) {
5427 mChildrenInterestedInDrag.remove(view);
5428 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005429 }
5430
Chet Haase21cd1382010-09-01 17:42:29 -07005431 /**
5432 * Sets the LayoutTransition object for this ViewGroup. If the LayoutTransition object is
5433 * not null, changes in layout which occur because of children being added to or removed from
5434 * the ViewGroup will be animated according to the animations defined in that LayoutTransition
5435 * object. By default, the transition object is null (so layout changes are not animated).
5436 *
Chet Haaseef3cbfd2013-08-21 14:01:02 -07005437 * <p>Replacing a non-null transition will cause that previous transition to be
5438 * canceled, if it is currently running, to restore this container to
5439 * its correct post-transition state.</p>
5440 *
Chet Haase21cd1382010-09-01 17:42:29 -07005441 * @param transition The LayoutTransition object that will animated changes in layout. A value
5442 * of <code>null</code> means no transition will run on layout changes.
Chet Haase13cc1202010-09-03 15:39:20 -07005443 * @attr ref android.R.styleable#ViewGroup_animateLayoutChanges
Chet Haase21cd1382010-09-01 17:42:29 -07005444 */
5445 public void setLayoutTransition(LayoutTransition transition) {
Chet Haaseb20db3e2010-09-10 13:07:30 -07005446 if (mTransition != null) {
Chet Haasefee6f2b2013-08-27 12:22:29 -07005447 LayoutTransition previousTransition = mTransition;
5448 previousTransition.cancel();
5449 previousTransition.removeTransitionListener(mLayoutTransitionListener);
Chet Haaseb20db3e2010-09-10 13:07:30 -07005450 }
Chet Haase21cd1382010-09-01 17:42:29 -07005451 mTransition = transition;
Chet Haase13cc1202010-09-03 15:39:20 -07005452 if (mTransition != null) {
5453 mTransition.addTransitionListener(mLayoutTransitionListener);
5454 }
5455 }
5456
5457 /**
5458 * Gets the LayoutTransition object for this ViewGroup. If the LayoutTransition object is
5459 * not null, changes in layout which occur because of children being added to or removed from
5460 * the ViewGroup will be animated according to the animations defined in that LayoutTransition
5461 * object. By default, the transition object is null (so layout changes are not animated).
5462 *
5463 * @return LayoutTranstion The LayoutTransition object that will animated changes in layout.
5464 * A value of <code>null</code> means no transition will run on layout changes.
5465 */
5466 public LayoutTransition getLayoutTransition() {
5467 return mTransition;
Chet Haase21cd1382010-09-01 17:42:29 -07005468 }
5469
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005470 private void removeViewsInternal(int start, int count) {
Chris Craik18a759d2015-10-14 14:16:33 -07005471 final int end = start + count;
5472
5473 if (start < 0 || count < 0 || end > mChildrenCount) {
5474 throw new IndexOutOfBoundsException();
5475 }
5476
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005477 final View focused = mFocused;
5478 final boolean detach = mAttachInfo != null;
Svetoslav Ganov149567f2013-01-08 15:23:34 -08005479 boolean clearChildFocus = false;
Evan Rosky53fcf112017-01-26 14:37:55 -08005480 View clearDefaultFocus = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005481
5482 final View[] children = mChildren;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005483
5484 for (int i = start; i < end; i++) {
5485 final View view = children[i];
5486
Chet Haase21cd1382010-09-01 17:42:29 -07005487 if (mTransition != null) {
Chet Haase5e25c2c2010-09-16 11:15:56 -07005488 mTransition.removeChild(this, view);
Chet Haase21cd1382010-09-01 17:42:29 -07005489 }
5490
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005491 if (view == focused) {
Alan Viverette223622a2013-12-17 13:29:02 -08005492 view.unFocus(null);
Svetoslav Ganov149567f2013-01-08 15:23:34 -08005493 clearChildFocus = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005494 }
Vadim Tryshev5ca73982017-01-04 17:24:43 -08005495 if (view == mDefaultFocus) {
Evan Rosky53fcf112017-01-26 14:37:55 -08005496 clearDefaultFocus = view;
5497 }
5498 if (view == mFocusedInCluster) {
Evan Rosky0e8a6832017-04-10 12:35:15 -07005499 clearFocusedInCluster(view);
Vadim Tryshev01d8c492016-12-15 11:33:15 -08005500 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005501
Alan Viverette632af842014-10-28 13:45:11 -07005502 view.clearAccessibilityFocus();
Svetoslav Ganov961bf0e2012-05-08 09:40:03 -07005503
Jeff Brown59a422e2012-04-19 15:19:19 -07005504 cancelTouchTarget(view);
5505 cancelHoverTarget(view);
5506
Chet Haase21cd1382010-09-01 17:42:29 -07005507 if (view.getAnimation() != null ||
5508 (mTransitioningViews != null && mTransitioningViews.contains(view))) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005509 addDisappearingView(view);
5510 } else if (detach) {
5511 view.dispatchDetachedFromWindow();
5512 }
5513
Adam Powell539ee872012-02-03 19:00:49 -08005514 if (view.hasTransientState()) {
5515 childHasTransientStateChanged(view, false);
5516 }
5517
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005518 needGlobalAttributesUpdate(false);
Romain Guy8506ab42009-06-11 17:35:47 -07005519
Adam Powell6690d012015-06-17 16:41:56 -07005520 dispatchViewRemoved(view);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005521 }
5522
5523 removeFromArray(start, count);
5524
Evan Rosky53fcf112017-01-26 14:37:55 -08005525 if (clearDefaultFocus != null) {
5526 clearDefaultFocus(clearDefaultFocus);
5527 }
Svetoslav Ganov149567f2013-01-08 15:23:34 -08005528 if (clearChildFocus) {
5529 clearChildFocus(focused);
5530 if (!rootViewRequestFocus()) {
5531 notifyGlobalFocusCleared(focused);
5532 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005533 }
5534 }
5535
5536 /**
5537 * Call this method to remove all child views from the
5538 * ViewGroup.
Filip Gruszczynskia33bdf32015-11-19 18:22:16 -08005539 *
Romain Guy393a52c2012-05-22 20:21:08 -07005540 * <p><strong>Note:</strong> do not invoke this method from
5541 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
5542 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005543 */
5544 public void removeAllViews() {
5545 removeAllViewsInLayout();
5546 requestLayout();
Romain Guy849d0a32011-02-01 17:20:48 -08005547 invalidate(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005548 }
5549
5550 /**
5551 * Called by a ViewGroup subclass to remove child views from itself,
5552 * when it must first know its size on screen before it can calculate how many
5553 * child views it will render. An example is a Gallery or a ListView, which
5554 * may "have" 50 children, but actually only render the number of children
5555 * that can currently fit inside the object on screen. Do not call
5556 * this method unless you are extending ViewGroup and understand the
5557 * view measuring and layout pipeline.
Romain Guy393a52c2012-05-22 20:21:08 -07005558 *
5559 * <p><strong>Note:</strong> do not invoke this method from
5560 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
5561 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005562 */
5563 public void removeAllViewsInLayout() {
5564 final int count = mChildrenCount;
5565 if (count <= 0) {
5566 return;
5567 }
5568
5569 final View[] children = mChildren;
5570 mChildrenCount = 0;
5571
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005572 final View focused = mFocused;
5573 final boolean detach = mAttachInfo != null;
Svetoslav Ganov149567f2013-01-08 15:23:34 -08005574 boolean clearChildFocus = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005575
5576 needGlobalAttributesUpdate(false);
Romain Guy8506ab42009-06-11 17:35:47 -07005577
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005578 for (int i = count - 1; i >= 0; i--) {
5579 final View view = children[i];
5580
Chet Haase21cd1382010-09-01 17:42:29 -07005581 if (mTransition != null) {
Chet Haase5e25c2c2010-09-16 11:15:56 -07005582 mTransition.removeChild(this, view);
Chet Haase21cd1382010-09-01 17:42:29 -07005583 }
5584
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005585 if (view == focused) {
Alan Viverette223622a2013-12-17 13:29:02 -08005586 view.unFocus(null);
Svetoslav Ganov149567f2013-01-08 15:23:34 -08005587 clearChildFocus = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005588 }
5589
Alan Viverette632af842014-10-28 13:45:11 -07005590 view.clearAccessibilityFocus();
Svetoslav Ganov961bf0e2012-05-08 09:40:03 -07005591
Jeff Brown59a422e2012-04-19 15:19:19 -07005592 cancelTouchTarget(view);
5593 cancelHoverTarget(view);
5594
Chet Haase21cd1382010-09-01 17:42:29 -07005595 if (view.getAnimation() != null ||
5596 (mTransitioningViews != null && mTransitioningViews.contains(view))) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005597 addDisappearingView(view);
5598 } else if (detach) {
5599 view.dispatchDetachedFromWindow();
5600 }
5601
Adam Powell539ee872012-02-03 19:00:49 -08005602 if (view.hasTransientState()) {
5603 childHasTransientStateChanged(view, false);
5604 }
5605
Adam Powell6690d012015-06-17 16:41:56 -07005606 dispatchViewRemoved(view);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005607
5608 view.mParent = null;
5609 children[i] = null;
5610 }
5611
Evan Rosky53fcf112017-01-26 14:37:55 -08005612 if (mDefaultFocus != null) {
5613 clearDefaultFocus(mDefaultFocus);
5614 }
Evan Rosky776fa5f2017-04-26 16:47:54 -07005615 if (mFocusedInCluster != null) {
5616 clearFocusedInCluster(mFocusedInCluster);
5617 }
Svetoslav Ganov149567f2013-01-08 15:23:34 -08005618 if (clearChildFocus) {
5619 clearChildFocus(focused);
5620 if (!rootViewRequestFocus()) {
5621 notifyGlobalFocusCleared(focused);
5622 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005623 }
5624 }
5625
5626 /**
5627 * Finishes the removal of a detached view. This method will dispatch the detached from
5628 * window event and notify the hierarchy change listener.
Chet Haaseca479d42012-08-30 17:20:08 -07005629 * <p>
5630 * This method is intended to be lightweight and makes no assumptions about whether the
5631 * parent or child should be redrawn. Proper use of this method will include also making
5632 * any appropriate {@link #requestLayout()} or {@link #invalidate()} calls.
5633 * For example, callers can {@link #post(Runnable) post} a {@link Runnable}
5634 * which performs a {@link #requestLayout()} on the next frame, after all detach/remove
5635 * calls are finished, causing layout to be run prior to redrawing the view hierarchy.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005636 *
5637 * @param child the child to be definitely removed from the view hierarchy
5638 * @param animate if true and the view has an animation, the view is placed in the
5639 * disappearing views list, otherwise, it is detached from the window
5640 *
5641 * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
5642 * @see #detachAllViewsFromParent()
5643 * @see #detachViewFromParent(View)
5644 * @see #detachViewFromParent(int)
5645 */
5646 protected void removeDetachedView(View child, boolean animate) {
Chet Haase21cd1382010-09-01 17:42:29 -07005647 if (mTransition != null) {
Chet Haase5e25c2c2010-09-16 11:15:56 -07005648 mTransition.removeChild(this, child);
Chet Haase21cd1382010-09-01 17:42:29 -07005649 }
5650
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005651 if (child == mFocused) {
5652 child.clearFocus();
5653 }
Vadim Tryshev5ca73982017-01-04 17:24:43 -08005654 if (child == mDefaultFocus) {
Evan Rosky53fcf112017-01-26 14:37:55 -08005655 clearDefaultFocus(child);
5656 }
5657 if (child == mFocusedInCluster) {
Evan Rosky0e8a6832017-04-10 12:35:15 -07005658 clearFocusedInCluster(child);
Vadim Tryshev01d8c492016-12-15 11:33:15 -08005659 }
Romain Guy8506ab42009-06-11 17:35:47 -07005660
Svetoslav Ganov961bf0e2012-05-08 09:40:03 -07005661 child.clearAccessibilityFocus();
5662
Jeff Brown59a422e2012-04-19 15:19:19 -07005663 cancelTouchTarget(child);
5664 cancelHoverTarget(child);
5665
Chet Haase21cd1382010-09-01 17:42:29 -07005666 if ((animate && child.getAnimation() != null) ||
5667 (mTransitioningViews != null && mTransitioningViews.contains(child))) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005668 addDisappearingView(child);
5669 } else if (child.mAttachInfo != null) {
5670 child.dispatchDetachedFromWindow();
5671 }
5672
Adam Powell539ee872012-02-03 19:00:49 -08005673 if (child.hasTransientState()) {
5674 childHasTransientStateChanged(child, false);
5675 }
5676
Adam Powell6690d012015-06-17 16:41:56 -07005677 dispatchViewRemoved(child);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005678 }
5679
5680 /**
5681 * Attaches a view to this view group. Attaching a view assigns this group as the parent,
Chet Haaseca479d42012-08-30 17:20:08 -07005682 * sets the layout parameters and puts the view in the list of children so that
5683 * it can be retrieved by calling {@link #getChildAt(int)}.
5684 * <p>
5685 * This method is intended to be lightweight and makes no assumptions about whether the
5686 * parent or child should be redrawn. Proper use of this method will include also making
5687 * any appropriate {@link #requestLayout()} or {@link #invalidate()} calls.
5688 * For example, callers can {@link #post(Runnable) post} a {@link Runnable}
5689 * which performs a {@link #requestLayout()} on the next frame, after all detach/attach
5690 * calls are finished, causing layout to be run prior to redrawing the view hierarchy.
5691 * <p>
5692 * This method should be called only for views which were detached from their parent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005693 *
5694 * @param child the child to attach
5695 * @param index the index at which the child should be attached
5696 * @param params the layout parameters of the child
5697 *
5698 * @see #removeDetachedView(View, boolean)
5699 * @see #detachAllViewsFromParent()
5700 * @see #detachViewFromParent(View)
5701 * @see #detachViewFromParent(int)
5702 */
5703 protected void attachViewToParent(View child, int index, LayoutParams params) {
5704 child.mLayoutParams = params;
5705
5706 if (index < 0) {
5707 index = mChildrenCount;
5708 }
5709
5710 addInArray(child, index);
5711
5712 child.mParent = this;
Dianne Hackborn4702a852012-08-17 15:18:29 -07005713 child.mPrivateFlags = (child.mPrivateFlags & ~PFLAG_DIRTY_MASK
5714 & ~PFLAG_DRAWING_CACHE_VALID)
5715 | PFLAG_DRAWN | PFLAG_INVALIDATED;
5716 this.mPrivateFlags |= PFLAG_INVALIDATED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005717
5718 if (child.hasFocus()) {
5719 requestChildFocus(child, child.findFocus());
5720 }
Adam Powellc5874092016-03-17 16:27:24 -07005721 dispatchVisibilityAggregated(isAttachedToWindow() && getWindowVisibility() == VISIBLE
5722 && isShown());
Phil Weaver13171622018-04-03 11:39:20 -07005723 notifySubtreeAccessibilityStateChangedIfNeeded();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005724 }
5725
5726 /**
Chet Haaseca479d42012-08-30 17:20:08 -07005727 * Detaches a view from its parent. Detaching a view should be followed
5728 * either by a call to
5729 * {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
5730 * or a call to {@link #removeDetachedView(View, boolean)}. Detachment should only be
5731 * temporary; reattachment or removal should happen within the same drawing cycle as
5732 * detachment. When a view is detached, its parent is null and cannot be retrieved by a
5733 * call to {@link #getChildAt(int)}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005734 *
5735 * @param child the child to detach
5736 *
5737 * @see #detachViewFromParent(int)
5738 * @see #detachViewsFromParent(int, int)
5739 * @see #detachAllViewsFromParent()
5740 * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
5741 * @see #removeDetachedView(View, boolean)
5742 */
5743 protected void detachViewFromParent(View child) {
5744 removeFromArray(indexOfChild(child));
5745 }
5746
5747 /**
Chet Haaseca479d42012-08-30 17:20:08 -07005748 * Detaches a view from its parent. Detaching a view should be followed
5749 * either by a call to
5750 * {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
5751 * or a call to {@link #removeDetachedView(View, boolean)}. Detachment should only be
5752 * temporary; reattachment or removal should happen within the same drawing cycle as
5753 * detachment. When a view is detached, its parent is null and cannot be retrieved by a
5754 * call to {@link #getChildAt(int)}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005755 *
5756 * @param index the index of the child to detach
5757 *
5758 * @see #detachViewFromParent(View)
5759 * @see #detachAllViewsFromParent()
5760 * @see #detachViewsFromParent(int, int)
5761 * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
5762 * @see #removeDetachedView(View, boolean)
5763 */
5764 protected void detachViewFromParent(int index) {
5765 removeFromArray(index);
5766 }
5767
5768 /**
Chet Haaseca479d42012-08-30 17:20:08 -07005769 * Detaches a range of views from their parents. Detaching a view should be followed
5770 * either by a call to
5771 * {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
5772 * or a call to {@link #removeDetachedView(View, boolean)}. Detachment should only be
5773 * temporary; reattachment or removal should happen within the same drawing cycle as
5774 * detachment. When a view is detached, its parent is null and cannot be retrieved by a
5775 * call to {@link #getChildAt(int)}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005776 *
5777 * @param start the first index of the childrend range to detach
5778 * @param count the number of children to detach
5779 *
5780 * @see #detachViewFromParent(View)
5781 * @see #detachViewFromParent(int)
5782 * @see #detachAllViewsFromParent()
5783 * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
5784 * @see #removeDetachedView(View, boolean)
5785 */
5786 protected void detachViewsFromParent(int start, int count) {
5787 removeFromArray(start, count);
5788 }
5789
5790 /**
Chet Haaseca479d42012-08-30 17:20:08 -07005791 * Detaches all views from the parent. Detaching a view should be followed
5792 * either by a call to
5793 * {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
5794 * or a call to {@link #removeDetachedView(View, boolean)}. Detachment should only be
5795 * temporary; reattachment or removal should happen within the same drawing cycle as
5796 * detachment. When a view is detached, its parent is null and cannot be retrieved by a
5797 * call to {@link #getChildAt(int)}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005798 *
5799 * @see #detachViewFromParent(View)
5800 * @see #detachViewFromParent(int)
5801 * @see #detachViewsFromParent(int, int)
5802 * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
5803 * @see #removeDetachedView(View, boolean)
5804 */
5805 protected void detachAllViewsFromParent() {
5806 final int count = mChildrenCount;
5807 if (count <= 0) {
5808 return;
5809 }
5810
5811 final View[] children = mChildren;
5812 mChildrenCount = 0;
5813
5814 for (int i = count - 1; i >= 0; i--) {
5815 children[i].mParent = null;
5816 children[i] = null;
5817 }
5818 }
5819
Chris Craik9de95db2017-01-18 17:59:23 -08005820 @Override
5821 @CallSuper
5822 public void onDescendantInvalidated(@NonNull View child, @NonNull View target) {
5823 /*
5824 * HW-only, Rect-ignoring damage codepath
5825 *
5826 * We don't deal with rectangles here, since RenderThread native code computes damage for
5827 * everything drawn by HWUI (and SW layer / drawing cache doesn't keep track of damage area)
5828 */
5829
5830 // if set, combine the animation flag into the parent
5831 mPrivateFlags |= (target.mPrivateFlags & PFLAG_DRAW_ANIMATION);
5832
5833 if ((target.mPrivateFlags & ~PFLAG_DIRTY_MASK) != 0) {
5834 // We lazily use PFLAG_DIRTY, since computing opaque isn't worth the potential
5835 // optimization in provides in a DisplayList world.
5836 mPrivateFlags = (mPrivateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DIRTY;
5837
5838 // simplified invalidateChildInParent behavior: clear cache validity to be safe...
5839 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
Chris Craik3f06c6d2017-01-09 18:19:48 +00005840 }
5841
Chris Craik9de95db2017-01-18 17:59:23 -08005842 // ... and mark inval if in software layer that needs to repaint (hw handled in native)
5843 if (mLayerType == LAYER_TYPE_SOFTWARE) {
5844 // Layered parents should be invalidated. Escalate to a full invalidate (and note that
5845 // we do this after consuming any relevant flags from the originating descendant)
5846 mPrivateFlags |= PFLAG_INVALIDATED | PFLAG_DIRTY;
5847 target = this;
Chris Craik3f06c6d2017-01-09 18:19:48 +00005848 }
5849
Chris Craik9de95db2017-01-18 17:59:23 -08005850 if (mParent != null) {
5851 mParent.onDescendantInvalidated(this, target);
Chris Craik3f06c6d2017-01-09 18:19:48 +00005852 }
Chris Craik3f06c6d2017-01-09 18:19:48 +00005853 }
5854
5855
5856 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005857 * Don't call or override this method. It is used for the implementation of
5858 * the view hierarchy.
Chris Craik9de95db2017-01-18 17:59:23 -08005859 *
5860 * @deprecated Use {@link #onDescendantInvalidated(View, View)} instead to observe updates to
5861 * draw state in descendants.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005862 */
Chris Craik9de95db2017-01-18 17:59:23 -08005863 @Deprecated
Alan Viverettebe463f22016-01-21 10:50:10 -05005864 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005865 public final void invalidateChild(View child, final Rect dirty) {
Chris Craik9de95db2017-01-18 17:59:23 -08005866 final AttachInfo attachInfo = mAttachInfo;
5867 if (attachInfo != null && attachInfo.mHardwareAccelerated) {
5868 // HW accelerated fast path
5869 onDescendantInvalidated(child, child);
Chris Craik3f06c6d2017-01-09 18:19:48 +00005870 return;
5871 }
5872
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005873 ViewParent parent = this;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005874 if (attachInfo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005875 // If the child is drawing an animation, we want to copy this flag onto
5876 // ourselves and the parent to make sure the invalidate request goes
5877 // through
Chris Craik3f06c6d2017-01-09 18:19:48 +00005878 final boolean drawAnimation = (child.mPrivateFlags & PFLAG_DRAW_ANIMATION) != 0;
Romain Guy24443ea2009-05-11 11:56:30 -07005879
Romain Guyfe455af2012-02-15 16:40:20 -08005880 // Check whether the child that requests the invalidate is fully opaque
5881 // Views being animated or transformed are not considered opaque because we may
5882 // be invalidating their old position and need the parent to paint behind them.
5883 Matrix childMatrix = child.getMatrix();
5884 final boolean isOpaque = child.isOpaque() && !drawAnimation &&
5885 child.getAnimation() == null && childMatrix.isIdentity();
5886 // Mark the child as dirty, using the appropriate flag
5887 // Make sure we do not set both flags at the same time
Dianne Hackborn4702a852012-08-17 15:18:29 -07005888 int opaqueFlag = isOpaque ? PFLAG_DIRTY_OPAQUE : PFLAG_DIRTY;
Romain Guyfe455af2012-02-15 16:40:20 -08005889
John Reck96bb8ad2014-06-19 10:53:03 -07005890 if (child.mLayerType != LAYER_TYPE_NONE) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07005891 mPrivateFlags |= PFLAG_INVALIDATED;
5892 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
Romain Guyfe455af2012-02-15 16:40:20 -08005893 }
5894
5895 final int[] location = attachInfo.mInvalidateChildLocation;
5896 location[CHILD_LEFT_INDEX] = child.mLeft;
5897 location[CHILD_TOP_INDEX] = child.mTop;
Chet Haase599913d2012-07-23 16:22:05 -07005898 if (!childMatrix.isIdentity() ||
5899 (mGroupFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) {
Romain Guyfe455af2012-02-15 16:40:20 -08005900 RectF boundingRect = attachInfo.mTmpTransformRect;
5901 boundingRect.set(dirty);
Chet Haase599913d2012-07-23 16:22:05 -07005902 Matrix transformMatrix;
5903 if ((mGroupFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) {
5904 Transformation t = attachInfo.mTmpTransformation;
5905 boolean transformed = getChildStaticTransformation(child, t);
5906 if (transformed) {
5907 transformMatrix = attachInfo.mTmpMatrix;
5908 transformMatrix.set(t.getMatrix());
5909 if (!childMatrix.isIdentity()) {
5910 transformMatrix.preConcat(childMatrix);
5911 }
5912 } else {
5913 transformMatrix = childMatrix;
5914 }
5915 } else {
5916 transformMatrix = childMatrix;
5917 }
5918 transformMatrix.mapRect(boundingRect);
Alan Viverettec45b1d42015-11-16 15:38:59 -05005919 dirty.set((int) Math.floor(boundingRect.left),
5920 (int) Math.floor(boundingRect.top),
5921 (int) Math.ceil(boundingRect.right),
5922 (int) Math.ceil(boundingRect.bottom));
Romain Guyfe455af2012-02-15 16:40:20 -08005923 }
5924
5925 do {
5926 View view = null;
5927 if (parent instanceof View) {
5928 view = (View) parent;
Romain Guyfe455af2012-02-15 16:40:20 -08005929 }
5930
5931 if (drawAnimation) {
5932 if (view != null) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07005933 view.mPrivateFlags |= PFLAG_DRAW_ANIMATION;
Romain Guyfe455af2012-02-15 16:40:20 -08005934 } else if (parent instanceof ViewRootImpl) {
5935 ((ViewRootImpl) parent).mIsAnimating = true;
5936 }
5937 }
5938
5939 // If the parent is dirty opaque or not dirty, mark it dirty with the opaque
5940 // flag coming from the child that initiated the invalidate
5941 if (view != null) {
5942 if ((view.mViewFlags & FADING_EDGE_MASK) != 0 &&
5943 view.getSolidColor() == 0) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07005944 opaqueFlag = PFLAG_DIRTY;
Romain Guyfe455af2012-02-15 16:40:20 -08005945 }
Dianne Hackborn4702a852012-08-17 15:18:29 -07005946 if ((view.mPrivateFlags & PFLAG_DIRTY_MASK) != PFLAG_DIRTY) {
5947 view.mPrivateFlags = (view.mPrivateFlags & ~PFLAG_DIRTY_MASK) | opaqueFlag;
Romain Guyfe455af2012-02-15 16:40:20 -08005948 }
5949 }
5950
5951 parent = parent.invalidateChildInParent(location, dirty);
5952 if (view != null) {
5953 // Account for transform on current parent
5954 Matrix m = view.getMatrix();
5955 if (!m.isIdentity()) {
5956 RectF boundingRect = attachInfo.mTmpTransformRect;
5957 boundingRect.set(dirty);
5958 m.mapRect(boundingRect);
Alan Viverettec45b1d42015-11-16 15:38:59 -05005959 dirty.set((int) Math.floor(boundingRect.left),
5960 (int) Math.floor(boundingRect.top),
5961 (int) Math.ceil(boundingRect.right),
5962 (int) Math.ceil(boundingRect.bottom));
Romain Guyfe455af2012-02-15 16:40:20 -08005963 }
5964 }
5965 } while (parent != null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005966 }
5967 }
5968
5969 /**
5970 * Don't call or override this method. It is used for the implementation of
5971 * the view hierarchy.
5972 *
5973 * This implementation returns null if this ViewGroup does not have a parent,
5974 * if this ViewGroup is already fully invalidated or if the dirty rectangle
5975 * does not intersect with this ViewGroup's bounds.
Chris Craik9de95db2017-01-18 17:59:23 -08005976 *
5977 * @deprecated Use {@link #onDescendantInvalidated(View, View)} instead to observe updates to
5978 * draw state in descendants.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005979 */
Chris Craik9de95db2017-01-18 17:59:23 -08005980 @Deprecated
Alan Viverettebe463f22016-01-21 10:50:10 -05005981 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005982 public ViewParent invalidateChildInParent(final int[] location, final Rect dirty) {
Chris Craik3f06c6d2017-01-09 18:19:48 +00005983 if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID)) != 0) {
5984 // either DRAWN, or DRAWING_CACHE_VALID
5985 if ((mGroupFlags & (FLAG_OPTIMIZE_INVALIDATE | FLAG_ANIMATION_DONE))
5986 != FLAG_OPTIMIZE_INVALIDATE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005987 dirty.offset(location[CHILD_LEFT_INDEX] - mScrollX,
5988 location[CHILD_TOP_INDEX] - mScrollY);
Chet Haasea4f14eb2013-04-22 11:11:39 -07005989 if ((mGroupFlags & FLAG_CLIP_CHILDREN) == 0) {
5990 dirty.union(0, 0, mRight - mLeft, mBottom - mTop);
5991 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005992
5993 final int left = mLeft;
5994 final int top = mTop;
5995
Chet Haase05e91ed2012-07-03 14:17:57 -07005996 if ((mGroupFlags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN) {
5997 if (!dirty.intersect(0, 0, mRight - left, mBottom - top)) {
5998 dirty.setEmpty();
Romain Guy3a3133d2011-02-01 22:59:58 -08005999 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006000 }
Chet Haase05e91ed2012-07-03 14:17:57 -07006001
6002 location[CHILD_LEFT_INDEX] = left;
6003 location[CHILD_TOP_INDEX] = top;
Selim Cinek1cb8b082016-12-21 15:34:30 +00006004 } else {
Selim Cinek1cb8b082016-12-21 15:34:30 +00006005
Chet Haasea3db8662011-07-19 10:36:05 -07006006 if ((mGroupFlags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN) {
6007 dirty.set(0, 0, mRight - mLeft, mBottom - mTop);
6008 } else {
6009 // in case the dirty rect extends outside the bounds of this container
6010 dirty.union(0, 0, mRight - mLeft, mBottom - mTop);
6011 }
Chris Craik3f06c6d2017-01-09 18:19:48 +00006012 location[CHILD_LEFT_INDEX] = mLeft;
6013 location[CHILD_TOP_INDEX] = mTop;
Romain Guy3a3133d2011-02-01 22:59:58 -08006014
Chris Craik3f06c6d2017-01-09 18:19:48 +00006015 mPrivateFlags &= ~PFLAG_DRAWN;
Selim Cinek1cb8b082016-12-21 15:34:30 +00006016 }
Chris Craik3f06c6d2017-01-09 18:19:48 +00006017 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
6018 if (mLayerType != LAYER_TYPE_NONE) {
6019 mPrivateFlags |= PFLAG_INVALIDATED;
6020 }
6021
6022 return mParent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006023 }
6024
6025 return null;
6026 }
6027
6028 /**
6029 * Offset a rectangle that is in a descendant's coordinate
6030 * space into our coordinate space.
6031 * @param descendant A descendant of this view
6032 * @param rect A rectangle defined in descendant's coordinate space.
6033 */
6034 public final void offsetDescendantRectToMyCoords(View descendant, Rect rect) {
6035 offsetRectBetweenParentAndChild(descendant, rect, true, false);
6036 }
6037
6038 /**
6039 * Offset a rectangle that is in our coordinate space into an ancestor's
6040 * coordinate space.
6041 * @param descendant A descendant of this view
6042 * @param rect A rectangle defined in descendant's coordinate space.
6043 */
6044 public final void offsetRectIntoDescendantCoords(View descendant, Rect rect) {
6045 offsetRectBetweenParentAndChild(descendant, rect, false, false);
6046 }
6047
6048 /**
6049 * Helper method that offsets a rect either from parent to descendant or
6050 * descendant to parent.
6051 */
6052 void offsetRectBetweenParentAndChild(View descendant, Rect rect,
6053 boolean offsetFromChildToParent, boolean clipToBounds) {
6054
6055 // already in the same coord system :)
6056 if (descendant == this) {
6057 return;
6058 }
6059
6060 ViewParent theParent = descendant.mParent;
6061
6062 // search and offset up to the parent
6063 while ((theParent != null)
6064 && (theParent instanceof View)
6065 && (theParent != this)) {
6066
6067 if (offsetFromChildToParent) {
Hyunyoung Song4eb1a4e2016-03-09 22:51:02 +00006068 rect.offset(descendant.mLeft - descendant.mScrollX,
6069 descendant.mTop - descendant.mScrollY);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006070 if (clipToBounds) {
6071 View p = (View) theParent;
Doris Liu9607fbe2015-05-28 17:17:28 -07006072 boolean intersected = rect.intersect(0, 0, p.mRight - p.mLeft,
6073 p.mBottom - p.mTop);
6074 if (!intersected) {
6075 rect.setEmpty();
6076 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006077 }
6078 } else {
6079 if (clipToBounds) {
6080 View p = (View) theParent;
Doris Liu9607fbe2015-05-28 17:17:28 -07006081 boolean intersected = rect.intersect(0, 0, p.mRight - p.mLeft,
6082 p.mBottom - p.mTop);
6083 if (!intersected) {
6084 rect.setEmpty();
6085 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006086 }
Hyunyoung Song4eb1a4e2016-03-09 22:51:02 +00006087 rect.offset(descendant.mScrollX - descendant.mLeft,
6088 descendant.mScrollY - descendant.mTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006089 }
6090
6091 descendant = (View) theParent;
6092 theParent = descendant.mParent;
6093 }
6094
6095 // now that we are up to this view, need to offset one more time
6096 // to get into our coordinate space
6097 if (theParent == this) {
6098 if (offsetFromChildToParent) {
Hyunyoung Song4eb1a4e2016-03-09 22:51:02 +00006099 rect.offset(descendant.mLeft - descendant.mScrollX,
6100 descendant.mTop - descendant.mScrollY);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006101 } else {
Hyunyoung Song4eb1a4e2016-03-09 22:51:02 +00006102 rect.offset(descendant.mScrollX - descendant.mLeft,
6103 descendant.mScrollY - descendant.mTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006104 }
6105 } else {
6106 throw new IllegalArgumentException("parameter must be a descendant of this view");
6107 }
6108 }
6109
6110 /**
6111 * Offset the vertical location of all children of this view by the specified number of pixels.
6112 *
6113 * @param offset the number of pixels to offset
6114 *
6115 * @hide
6116 */
Mathew Inwoode5ad5982018-08-17 15:07:52 +01006117 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006118 public void offsetChildrenTopAndBottom(int offset) {
6119 final int count = mChildrenCount;
6120 final View[] children = mChildren;
Romain Guy5549cb52013-05-06 18:42:08 -07006121 boolean invalidate = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006122
6123 for (int i = 0; i < count; i++) {
6124 final View v = children[i];
6125 v.mTop += offset;
6126 v.mBottom += offset;
Chris Craik64a12e12014-03-28 18:12:12 -07006127 if (v.mRenderNode != null) {
Romain Guy5549cb52013-05-06 18:42:08 -07006128 invalidate = true;
Chris Craik64a12e12014-03-28 18:12:12 -07006129 v.mRenderNode.offsetTopAndBottom(offset);
Chet Haasea1cff502012-02-21 13:43:44 -08006130 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006131 }
Romain Guy5549cb52013-05-06 18:42:08 -07006132
6133 if (invalidate) {
6134 invalidateViewProperty(false, false);
6135 }
Eugene Susla72c510f2018-01-23 21:12:11 +00006136 notifySubtreeAccessibilityStateChangedIfNeeded();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006137 }
6138
Alan Viverettebe463f22016-01-21 10:50:10 -05006139 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006140 public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) {
Abodunrinwa Toki4e7a1202016-05-03 18:23:12 +01006141 return getChildVisibleRect(child, r, offset, false);
6142 }
6143
6144 /**
Abodunrinwa Tokicb664062016-05-13 19:26:03 +01006145 * @param forceParentCheck true to guarantee that this call will propagate to all ancestors,
6146 * false otherwise
6147 *
Abodunrinwa Toki4e7a1202016-05-03 18:23:12 +01006148 * @hide
6149 */
6150 public boolean getChildVisibleRect(
6151 View child, Rect r, android.graphics.Point offset, boolean forceParentCheck) {
Adam Powellf93bb6d2011-12-12 15:21:57 -08006152 // It doesn't make a whole lot of sense to call this on a view that isn't attached,
6153 // but for some simple tests it can be useful. If we don't have attach info this
6154 // will allocate memory.
6155 final RectF rect = mAttachInfo != null ? mAttachInfo.mTmpTransformRect : new RectF();
Gilles Debunnecea45132011-11-24 02:19:27 +01006156 rect.set(r);
6157
6158 if (!child.hasIdentityMatrix()) {
George Mount002d43d2014-11-11 12:54:43 -08006159 child.getMatrix().mapRect(rect);
Gilles Debunnecea45132011-11-24 02:19:27 +01006160 }
6161
Alan Viveretteab2cf6d2014-11-26 14:34:36 -08006162 final int dx = child.mLeft - mScrollX;
6163 final int dy = child.mTop - mScrollY;
Gilles Debunnecea45132011-11-24 02:19:27 +01006164
6165 rect.offset(dx, dy);
6166
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006167 if (offset != null) {
Gilles Debunnecea45132011-11-24 02:19:27 +01006168 if (!child.hasIdentityMatrix()) {
Adam Powellf93bb6d2011-12-12 15:21:57 -08006169 float[] position = mAttachInfo != null ? mAttachInfo.mTmpTransformLocation
6170 : new float[2];
Gilles Debunnecea45132011-11-24 02:19:27 +01006171 position[0] = offset.x;
6172 position[1] = offset.y;
6173 child.getMatrix().mapPoints(position);
Alan Viverettec45b1d42015-11-16 15:38:59 -05006174 offset.x = Math.round(position[0]);
6175 offset.y = Math.round(position[1]);
Gilles Debunnecea45132011-11-24 02:19:27 +01006176 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006177 offset.x += dx;
6178 offset.y += dy;
6179 }
Gilles Debunnecea45132011-11-24 02:19:27 +01006180
Alan Viveretteab2cf6d2014-11-26 14:34:36 -08006181 final int width = mRight - mLeft;
6182 final int height = mBottom - mTop;
6183
George Mount002d43d2014-11-11 12:54:43 -08006184 boolean rectIsVisible = true;
Adam Powell35da41e2014-12-10 18:59:34 -08006185 if (mParent == null ||
6186 (mParent instanceof ViewGroup && ((ViewGroup) mParent).getClipChildren())) {
Alan Viveretteab2cf6d2014-11-26 14:34:36 -08006187 // Clip to bounds.
6188 rectIsVisible = rect.intersect(0, 0, width, height);
Gilles Debunnecea45132011-11-24 02:19:27 +01006189 }
6190
Abodunrinwa Toki4e7a1202016-05-03 18:23:12 +01006191 if ((forceParentCheck || rectIsVisible)
6192 && (mGroupFlags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK) {
Alan Viveretteab2cf6d2014-11-26 14:34:36 -08006193 // Clip to padding.
George Mount002d43d2014-11-11 12:54:43 -08006194 rectIsVisible = rect.intersect(mPaddingLeft, mPaddingTop,
Alan Viveretteab2cf6d2014-11-26 14:34:36 -08006195 width - mPaddingRight, height - mPaddingBottom);
George Mount002d43d2014-11-11 12:54:43 -08006196 }
6197
Abodunrinwa Toki4e7a1202016-05-03 18:23:12 +01006198 if ((forceParentCheck || rectIsVisible) && mClipBounds != null) {
Alan Viveretteab2cf6d2014-11-26 14:34:36 -08006199 // Clip to clipBounds.
George Mount002d43d2014-11-11 12:54:43 -08006200 rectIsVisible = rect.intersect(mClipBounds.left, mClipBounds.top, mClipBounds.right,
6201 mClipBounds.bottom);
6202 }
Alan Viverettec45b1d42015-11-16 15:38:59 -05006203 r.set((int) Math.floor(rect.left), (int) Math.floor(rect.top),
6204 (int) Math.ceil(rect.right), (int) Math.ceil(rect.bottom));
Abodunrinwa Toki4e7a1202016-05-03 18:23:12 +01006205
6206 if ((forceParentCheck || rectIsVisible) && mParent != null) {
Abodunrinwa Tokicb664062016-05-13 19:26:03 +01006207 if (mParent instanceof ViewGroup) {
6208 rectIsVisible = ((ViewGroup) mParent)
6209 .getChildVisibleRect(this, r, offset, forceParentCheck);
6210 } else {
6211 rectIsVisible = mParent.getChildVisibleRect(this, r, offset);
6212 }
George Mount002d43d2014-11-11 12:54:43 -08006213 }
6214 return rectIsVisible;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006215 }
6216
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006217 @Override
Chet Haase9c087442011-01-12 16:20:16 -08006218 public final void layout(int l, int t, int r, int b) {
Chet Haase430742f2013-04-12 11:18:36 -07006219 if (!mSuppressLayout && (mTransition == null || !mTransition.isChangingLayout())) {
Chet Haase7dd4a532012-04-16 13:35:09 -07006220 if (mTransition != null) {
6221 mTransition.layoutChange(this);
6222 }
Chet Haase9c087442011-01-12 16:20:16 -08006223 super.layout(l, t, r, b);
6224 } else {
6225 // record the fact that we noop'd it; request layout when transition finishes
Chet Haaseb9895022013-04-02 15:10:58 -07006226 mLayoutCalledWhileSuppressed = true;
Chet Haase9c087442011-01-12 16:20:16 -08006227 }
6228 }
6229
Chet Haase9c087442011-01-12 16:20:16 -08006230 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006231 protected abstract void onLayout(boolean changed,
6232 int l, int t, int r, int b);
6233
6234 /**
6235 * Indicates whether the view group has the ability to animate its children
6236 * after the first layout.
6237 *
6238 * @return true if the children can be animated, false otherwise
6239 */
6240 protected boolean canAnimate() {
6241 return mLayoutAnimationController != null;
6242 }
6243
6244 /**
6245 * Runs the layout animation. Calling this method triggers a relayout of
6246 * this view group.
6247 */
6248 public void startLayoutAnimation() {
6249 if (mLayoutAnimationController != null) {
6250 mGroupFlags |= FLAG_RUN_ANIMATION;
6251 requestLayout();
6252 }
6253 }
6254
6255 /**
6256 * Schedules the layout animation to be played after the next layout pass
6257 * of this view group. This can be used to restart the layout animation
6258 * when the content of the view group changes or when the activity is
6259 * paused and resumed.
6260 */
6261 public void scheduleLayoutAnimation() {
6262 mGroupFlags |= FLAG_RUN_ANIMATION;
6263 }
6264
6265 /**
6266 * Sets the layout animation controller used to animate the group's
6267 * children after the first layout.
6268 *
6269 * @param controller the animation controller
6270 */
6271 public void setLayoutAnimation(LayoutAnimationController controller) {
6272 mLayoutAnimationController = controller;
6273 if (mLayoutAnimationController != null) {
6274 mGroupFlags |= FLAG_RUN_ANIMATION;
6275 }
6276 }
6277
6278 /**
6279 * Returns the layout animation controller used to animate the group's
6280 * children.
6281 *
6282 * @return the current animation controller
6283 */
6284 public LayoutAnimationController getLayoutAnimation() {
6285 return mLayoutAnimationController;
6286 }
6287
6288 /**
6289 * Indicates whether the children's drawing cache is used during a layout
6290 * animation. By default, the drawing cache is enabled but this will prevent
6291 * nested layout animations from working. To nest animations, you must disable
6292 * the cache.
6293 *
6294 * @return true if the animation cache is enabled, false otherwise
6295 *
6296 * @see #setAnimationCacheEnabled(boolean)
6297 * @see View#setDrawingCacheEnabled(boolean)
Chris Craik5a6bbae2015-04-10 17:41:34 -07006298 *
Dianne Hackborn0e3de6c2015-07-29 15:20:21 -07006299 * @deprecated As of {@link android.os.Build.VERSION_CODES#M}, this property is ignored.
Chris Craik5a6bbae2015-04-10 17:41:34 -07006300 * Caching behavior of children may be controlled through {@link View#setLayerType(int, Paint)}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006301 */
Aurimas Liutikas514c5ef2016-05-24 15:22:55 -07006302 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006303 public boolean isAnimationCacheEnabled() {
6304 return (mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE;
6305 }
6306
6307 /**
6308 * Enables or disables the children's drawing cache during a layout animation.
6309 * By default, the drawing cache is enabled but this will prevent nested
6310 * layout animations from working. To nest animations, you must disable the
6311 * cache.
6312 *
6313 * @param enabled true to enable the animation cache, false otherwise
6314 *
6315 * @see #isAnimationCacheEnabled()
6316 * @see View#setDrawingCacheEnabled(boolean)
Chris Craik5a6bbae2015-04-10 17:41:34 -07006317 *
Dianne Hackborn0e3de6c2015-07-29 15:20:21 -07006318 * @deprecated As of {@link android.os.Build.VERSION_CODES#M}, this property is ignored.
Chris Craik5a6bbae2015-04-10 17:41:34 -07006319 * Caching behavior of children may be controlled through {@link View#setLayerType(int, Paint)}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006320 */
Aurimas Liutikas514c5ef2016-05-24 15:22:55 -07006321 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006322 public void setAnimationCacheEnabled(boolean enabled) {
6323 setBooleanFlag(FLAG_ANIMATION_CACHE, enabled);
6324 }
6325
6326 /**
6327 * Indicates whether this ViewGroup will always try to draw its children using their
6328 * drawing cache. By default this property is enabled.
6329 *
6330 * @return true if the animation cache is enabled, false otherwise
6331 *
6332 * @see #setAlwaysDrawnWithCacheEnabled(boolean)
6333 * @see #setChildrenDrawnWithCacheEnabled(boolean)
6334 * @see View#setDrawingCacheEnabled(boolean)
Chris Craik5a6bbae2015-04-10 17:41:34 -07006335 *
Dianne Hackborn0e3de6c2015-07-29 15:20:21 -07006336 * @deprecated As of {@link android.os.Build.VERSION_CODES#M}, this property is ignored.
Chris Craik5a6bbae2015-04-10 17:41:34 -07006337 * Child views may no longer have their caching behavior disabled by parents.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006338 */
Aurimas Liutikas514c5ef2016-05-24 15:22:55 -07006339 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006340 public boolean isAlwaysDrawnWithCacheEnabled() {
6341 return (mGroupFlags & FLAG_ALWAYS_DRAWN_WITH_CACHE) == FLAG_ALWAYS_DRAWN_WITH_CACHE;
6342 }
6343
6344 /**
6345 * Indicates whether this ViewGroup will always try to draw its children using their
6346 * drawing cache. This property can be set to true when the cache rendering is
6347 * slightly different from the children's normal rendering. Renderings can be different,
6348 * for instance, when the cache's quality is set to low.
6349 *
6350 * When this property is disabled, the ViewGroup will use the drawing cache of its
6351 * children only when asked to. It's usually the task of subclasses to tell ViewGroup
6352 * when to start using the drawing cache and when to stop using it.
6353 *
6354 * @param always true to always draw with the drawing cache, false otherwise
6355 *
6356 * @see #isAlwaysDrawnWithCacheEnabled()
6357 * @see #setChildrenDrawnWithCacheEnabled(boolean)
6358 * @see View#setDrawingCacheEnabled(boolean)
6359 * @see View#setDrawingCacheQuality(int)
Chris Craik5a6bbae2015-04-10 17:41:34 -07006360 *
Dianne Hackborn0e3de6c2015-07-29 15:20:21 -07006361 * @deprecated As of {@link android.os.Build.VERSION_CODES#M}, this property is ignored.
Chris Craik5a6bbae2015-04-10 17:41:34 -07006362 * Child views may no longer have their caching behavior disabled by parents.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006363 */
Aurimas Liutikas514c5ef2016-05-24 15:22:55 -07006364 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006365 public void setAlwaysDrawnWithCacheEnabled(boolean always) {
6366 setBooleanFlag(FLAG_ALWAYS_DRAWN_WITH_CACHE, always);
6367 }
6368
6369 /**
6370 * Indicates whether the ViewGroup is currently drawing its children using
6371 * their drawing cache.
6372 *
6373 * @return true if children should be drawn with their cache, false otherwise
6374 *
6375 * @see #setAlwaysDrawnWithCacheEnabled(boolean)
6376 * @see #setChildrenDrawnWithCacheEnabled(boolean)
Chris Craik5a6bbae2015-04-10 17:41:34 -07006377 *
Dianne Hackborn0e3de6c2015-07-29 15:20:21 -07006378 * @deprecated As of {@link android.os.Build.VERSION_CODES#M}, this property is ignored.
Chris Craik5a6bbae2015-04-10 17:41:34 -07006379 * Child views may no longer be forced to cache their rendering state by their parents.
6380 * Use {@link View#setLayerType(int, Paint)} on individual Views instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006381 */
Aurimas Liutikas514c5ef2016-05-24 15:22:55 -07006382 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006383 protected boolean isChildrenDrawnWithCacheEnabled() {
6384 return (mGroupFlags & FLAG_CHILDREN_DRAWN_WITH_CACHE) == FLAG_CHILDREN_DRAWN_WITH_CACHE;
6385 }
6386
6387 /**
6388 * Tells the ViewGroup to draw its children using their drawing cache. This property
6389 * is ignored when {@link #isAlwaysDrawnWithCacheEnabled()} is true. A child's drawing cache
6390 * will be used only if it has been enabled.
6391 *
6392 * Subclasses should call this method to start and stop using the drawing cache when
6393 * they perform performance sensitive operations, like scrolling or animating.
6394 *
6395 * @param enabled true if children should be drawn with their cache, false otherwise
6396 *
6397 * @see #setAlwaysDrawnWithCacheEnabled(boolean)
6398 * @see #isChildrenDrawnWithCacheEnabled()
Chris Craik5a6bbae2015-04-10 17:41:34 -07006399 *
Dianne Hackborn0e3de6c2015-07-29 15:20:21 -07006400 * @deprecated As of {@link android.os.Build.VERSION_CODES#M}, this property is ignored.
Chris Craik5a6bbae2015-04-10 17:41:34 -07006401 * Child views may no longer be forced to cache their rendering state by their parents.
6402 * Use {@link View#setLayerType(int, Paint)} on individual Views instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006403 */
Aurimas Liutikas514c5ef2016-05-24 15:22:55 -07006404 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006405 protected void setChildrenDrawnWithCacheEnabled(boolean enabled) {
6406 setBooleanFlag(FLAG_CHILDREN_DRAWN_WITH_CACHE, enabled);
6407 }
6408
Romain Guy293451e2009-11-04 13:59:48 -08006409 /**
6410 * Indicates whether the ViewGroup is drawing its children in the order defined by
6411 * {@link #getChildDrawingOrder(int, int)}.
6412 *
6413 * @return true if children drawing order is defined by {@link #getChildDrawingOrder(int, int)},
6414 * false otherwise
6415 *
6416 * @see #setChildrenDrawingOrderEnabled(boolean)
6417 * @see #getChildDrawingOrder(int, int)
6418 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07006419 @ViewDebug.ExportedProperty(category = "drawing")
Romain Guy293451e2009-11-04 13:59:48 -08006420 protected boolean isChildrenDrawingOrderEnabled() {
6421 return (mGroupFlags & FLAG_USE_CHILD_DRAWING_ORDER) == FLAG_USE_CHILD_DRAWING_ORDER;
6422 }
6423
6424 /**
6425 * Tells the ViewGroup whether to draw its children in the order defined by the method
6426 * {@link #getChildDrawingOrder(int, int)}.
Chris Craike83cbd42014-09-03 17:52:24 -07006427 * <p>
6428 * Note that {@link View#getZ() Z} reordering, done by {@link #dispatchDraw(Canvas)},
6429 * will override custom child ordering done via this method.
Romain Guy293451e2009-11-04 13:59:48 -08006430 *
6431 * @param enabled true if the order of the children when drawing is determined by
6432 * {@link #getChildDrawingOrder(int, int)}, false otherwise
6433 *
6434 * @see #isChildrenDrawingOrderEnabled()
6435 * @see #getChildDrawingOrder(int, int)
6436 */
6437 protected void setChildrenDrawingOrderEnabled(boolean enabled) {
6438 setBooleanFlag(FLAG_USE_CHILD_DRAWING_ORDER, enabled);
6439 }
6440
Svetoslav6254f482013-06-04 17:22:14 -07006441 private boolean hasBooleanFlag(int flag) {
Philip Milnef091b662013-02-27 11:15:21 -08006442 return (mGroupFlags & flag) == flag;
6443 }
6444
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006445 private void setBooleanFlag(int flag, boolean value) {
6446 if (value) {
6447 mGroupFlags |= flag;
6448 } else {
6449 mGroupFlags &= ~flag;
6450 }
6451 }
6452
6453 /**
6454 * Returns an integer indicating what types of drawing caches are kept in memory.
6455 *
6456 * @see #setPersistentDrawingCache(int)
6457 * @see #setAnimationCacheEnabled(boolean)
6458 *
6459 * @return one or a combination of {@link #PERSISTENT_NO_CACHE},
6460 * {@link #PERSISTENT_ANIMATION_CACHE}, {@link #PERSISTENT_SCROLLING_CACHE}
6461 * and {@link #PERSISTENT_ALL_CACHES}
John Reck949cfe12017-10-09 13:27:03 -07006462 *
6463 * @deprecated The view drawing cache was largely made obsolete with the introduction of
6464 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache
6465 * layers are largely unnecessary and can easily result in a net loss in performance due to the
6466 * cost of creating and updating the layer. In the rare cases where caching layers are useful,
6467 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware
6468 * rendering. For software-rendered snapshots of a small part of the View hierarchy or
6469 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or
6470 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these
6471 * software-rendered usages are discouraged and have compatibility issues with hardware-only
6472 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE}
6473 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback
6474 * reports or unit testing the {@link PixelCopy} API is recommended.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006475 */
John Reck949cfe12017-10-09 13:27:03 -07006476 @Deprecated
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07006477 @ViewDebug.ExportedProperty(category = "drawing", mapping = {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006478 @ViewDebug.IntToString(from = PERSISTENT_NO_CACHE, to = "NONE"),
Romain Guy203688c2010-05-12 15:41:32 -07006479 @ViewDebug.IntToString(from = PERSISTENT_ANIMATION_CACHE, to = "ANIMATION"),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006480 @ViewDebug.IntToString(from = PERSISTENT_SCROLLING_CACHE, to = "SCROLLING"),
6481 @ViewDebug.IntToString(from = PERSISTENT_ALL_CACHES, to = "ALL")
6482 })
6483 public int getPersistentDrawingCache() {
6484 return mPersistentDrawingCache;
6485 }
6486
6487 /**
6488 * Indicates what types of drawing caches should be kept in memory after
6489 * they have been created.
6490 *
6491 * @see #getPersistentDrawingCache()
6492 * @see #setAnimationCacheEnabled(boolean)
6493 *
6494 * @param drawingCacheToKeep one or a combination of {@link #PERSISTENT_NO_CACHE},
6495 * {@link #PERSISTENT_ANIMATION_CACHE}, {@link #PERSISTENT_SCROLLING_CACHE}
6496 * and {@link #PERSISTENT_ALL_CACHES}
John Reck949cfe12017-10-09 13:27:03 -07006497 *
6498 * @deprecated The view drawing cache was largely made obsolete with the introduction of
6499 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache
6500 * layers are largely unnecessary and can easily result in a net loss in performance due to the
6501 * cost of creating and updating the layer. In the rare cases where caching layers are useful,
6502 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware
6503 * rendering. For software-rendered snapshots of a small part of the View hierarchy or
6504 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or
6505 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these
6506 * software-rendered usages are discouraged and have compatibility issues with hardware-only
6507 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE}
6508 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback
6509 * reports or unit testing the {@link PixelCopy} API is recommended.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006510 */
John Reck949cfe12017-10-09 13:27:03 -07006511 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006512 public void setPersistentDrawingCache(int drawingCacheToKeep) {
6513 mPersistentDrawingCache = drawingCacheToKeep & PERSISTENT_ALL_CACHES;
6514 }
6515
Philip Milnef091b662013-02-27 11:15:21 -08006516 private void setLayoutMode(int layoutMode, boolean explicitly) {
6517 mLayoutMode = layoutMode;
6518 setBooleanFlag(FLAG_LAYOUT_MODE_WAS_EXPLICITLY_SET, explicitly);
6519 }
6520
6521 /**
6522 * Recursively traverse the view hierarchy, resetting the layoutMode of any
6523 * descendants that had inherited a different layoutMode from a previous parent.
6524 * Recursion terminates when a descendant's mode is:
6525 * <ul>
6526 * <li>Undefined</li>
6527 * <li>The same as the root node's</li>
6528 * <li>A mode that had been explicitly set</li>
6529 * <ul/>
6530 * The first two clauses are optimizations.
6531 * @param layoutModeOfRoot
6532 */
6533 @Override
6534 void invalidateInheritedLayoutMode(int layoutModeOfRoot) {
6535 if (mLayoutMode == LAYOUT_MODE_UNDEFINED ||
6536 mLayoutMode == layoutModeOfRoot ||
Svetoslav6254f482013-06-04 17:22:14 -07006537 hasBooleanFlag(FLAG_LAYOUT_MODE_WAS_EXPLICITLY_SET)) {
Philip Milnef091b662013-02-27 11:15:21 -08006538 return;
6539 }
6540 setLayoutMode(LAYOUT_MODE_UNDEFINED, false);
6541
6542 // apply recursively
6543 for (int i = 0, N = getChildCount(); i < N; i++) {
6544 getChildAt(i).invalidateInheritedLayoutMode(layoutModeOfRoot);
6545 }
6546 }
6547
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006548 /**
Philip Milnecfb631b2012-10-26 10:51:46 -07006549 * Returns the basis of alignment during layout operations on this ViewGroup:
Philip Milne7b757812012-09-19 18:13:44 -07006550 * either {@link #LAYOUT_MODE_CLIP_BOUNDS} or {@link #LAYOUT_MODE_OPTICAL_BOUNDS}.
Philip Milnecfb631b2012-10-26 10:51:46 -07006551 * <p>
6552 * If no layoutMode was explicitly set, either programmatically or in an XML resource,
6553 * the method returns the layoutMode of the view's parent ViewGroup if such a parent exists,
6554 * otherwise the method returns a default value of {@link #LAYOUT_MODE_CLIP_BOUNDS}.
Philip Milne1557fd72012-04-04 23:41:34 -07006555 *
Philip Milnefcc6a0f2012-04-16 16:12:19 -07006556 * @return the layout mode to use during layout operations
Philip Milne1557fd72012-04-04 23:41:34 -07006557 *
6558 * @see #setLayoutMode(int)
6559 */
6560 public int getLayoutMode() {
Philip Milnecfb631b2012-10-26 10:51:46 -07006561 if (mLayoutMode == LAYOUT_MODE_UNDEFINED) {
Philip Milnef091b662013-02-27 11:15:21 -08006562 int inheritedLayoutMode = (mParent instanceof ViewGroup) ?
6563 ((ViewGroup) mParent).getLayoutMode() : LAYOUT_MODE_DEFAULT;
6564 setLayoutMode(inheritedLayoutMode, false);
Philip Milnecfb631b2012-10-26 10:51:46 -07006565 }
Philip Milne1557fd72012-04-04 23:41:34 -07006566 return mLayoutMode;
6567 }
6568
6569 /**
Philip Milnecfb631b2012-10-26 10:51:46 -07006570 * Sets the basis of alignment during the layout of this ViewGroup.
Philip Milne7b757812012-09-19 18:13:44 -07006571 * Valid values are either {@link #LAYOUT_MODE_CLIP_BOUNDS} or
6572 * {@link #LAYOUT_MODE_OPTICAL_BOUNDS}.
Philip Milne1557fd72012-04-04 23:41:34 -07006573 *
Philip Milnefcc6a0f2012-04-16 16:12:19 -07006574 * @param layoutMode the layout mode to use during layout operations
Philip Milne1557fd72012-04-04 23:41:34 -07006575 *
6576 * @see #getLayoutMode()
Scott Main27a85082013-06-10 10:39:48 -07006577 * @attr ref android.R.styleable#ViewGroup_layoutMode
Philip Milne1557fd72012-04-04 23:41:34 -07006578 */
6579 public void setLayoutMode(int layoutMode) {
6580 if (mLayoutMode != layoutMode) {
Philip Milnef091b662013-02-27 11:15:21 -08006581 invalidateInheritedLayoutMode(layoutMode);
6582 setLayoutMode(layoutMode, layoutMode != LAYOUT_MODE_UNDEFINED);
Philip Milne1557fd72012-04-04 23:41:34 -07006583 requestLayout();
6584 }
6585 }
6586
6587 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006588 * Returns a new set of layout parameters based on the supplied attributes set.
6589 *
6590 * @param attrs the attributes to build the layout parameters from
6591 *
6592 * @return an instance of {@link android.view.ViewGroup.LayoutParams} or one
6593 * of its descendants
6594 */
6595 public LayoutParams generateLayoutParams(AttributeSet attrs) {
6596 return new LayoutParams(getContext(), attrs);
6597 }
6598
6599 /**
6600 * Returns a safe set of layout parameters based on the supplied layout params.
6601 * When a ViewGroup is passed a View whose layout params do not pass the test of
6602 * {@link #checkLayoutParams(android.view.ViewGroup.LayoutParams)}, this method
6603 * is invoked. This method should return a new set of layout params suitable for
6604 * this ViewGroup, possibly by copying the appropriate attributes from the
6605 * specified set of layout params.
6606 *
6607 * @param p The layout parameters to convert into a suitable set of layout parameters
6608 * for this ViewGroup.
6609 *
6610 * @return an instance of {@link android.view.ViewGroup.LayoutParams} or one
6611 * of its descendants
6612 */
6613 protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
Chet Haase4610eef2015-12-03 07:38:11 -08006614 return p;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006615 }
6616
6617 /**
6618 * Returns a set of default layout parameters. These parameters are requested
6619 * when the View passed to {@link #addView(View)} has no layout parameters
6620 * already set. If null is returned, an exception is thrown from addView.
6621 *
6622 * @return a set of default layout parameters or null
6623 */
6624 protected LayoutParams generateDefaultLayoutParams() {
6625 return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
6626 }
6627
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006628 @Override
6629 protected void debug(int depth) {
6630 super.debug(depth);
6631 String output;
6632
6633 if (mFocused != null) {
6634 output = debugIndent(depth);
6635 output += "mFocused";
6636 Log.d(VIEW_LOG_TAG, output);
Vadim Tryshev01d8c492016-12-15 11:33:15 -08006637 mFocused.debug(depth + 1);
6638 }
Vadim Tryshev5ca73982017-01-04 17:24:43 -08006639 if (mDefaultFocus != null) {
Vadim Tryshev01d8c492016-12-15 11:33:15 -08006640 output = debugIndent(depth);
Vadim Tryshev5ca73982017-01-04 17:24:43 -08006641 output += "mDefaultFocus";
Vadim Tryshev01d8c492016-12-15 11:33:15 -08006642 Log.d(VIEW_LOG_TAG, output);
Vadim Tryshev5ca73982017-01-04 17:24:43 -08006643 mDefaultFocus.debug(depth + 1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006644 }
Evan Rosky53fcf112017-01-26 14:37:55 -08006645 if (mFocusedInCluster != null) {
6646 output = debugIndent(depth);
6647 output += "mFocusedInCluster";
6648 Log.d(VIEW_LOG_TAG, output);
6649 mFocusedInCluster.debug(depth + 1);
6650 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006651 if (mChildrenCount != 0) {
6652 output = debugIndent(depth);
6653 output += "{";
6654 Log.d(VIEW_LOG_TAG, output);
6655 }
6656 int count = mChildrenCount;
6657 for (int i = 0; i < count; i++) {
6658 View child = mChildren[i];
6659 child.debug(depth + 1);
6660 }
6661
6662 if (mChildrenCount != 0) {
6663 output = debugIndent(depth);
6664 output += "}";
6665 Log.d(VIEW_LOG_TAG, output);
6666 }
6667 }
6668
6669 /**
6670 * Returns the position in the group of the specified child view.
6671 *
6672 * @param child the view for which to get the position
6673 * @return a positive integer representing the position of the view in the
6674 * group, or -1 if the view does not exist in the group
6675 */
6676 public int indexOfChild(View child) {
6677 final int count = mChildrenCount;
6678 final View[] children = mChildren;
6679 for (int i = 0; i < count; i++) {
6680 if (children[i] == child) {
6681 return i;
6682 }
6683 }
6684 return -1;
6685 }
6686
6687 /**
6688 * Returns the number of children in the group.
6689 *
6690 * @return a positive integer representing the number of children in
6691 * the group
6692 */
6693 public int getChildCount() {
6694 return mChildrenCount;
6695 }
6696
6697 /**
6698 * Returns the view at the specified position in the group.
6699 *
6700 * @param index the position at which to get the view from
6701 * @return the view at the specified position or null if the position
6702 * does not exist within the group
6703 */
6704 public View getChildAt(int index) {
Adam Powell3ba8f5d62011-03-07 15:36:33 -08006705 if (index < 0 || index >= mChildrenCount) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006706 return null;
6707 }
Adam Powell3ba8f5d62011-03-07 15:36:33 -08006708 return mChildren[index];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006709 }
6710
6711 /**
6712 * Ask all of the children of this view to measure themselves, taking into
6713 * account both the MeasureSpec requirements for this view and its padding.
6714 * We skip children that are in the GONE state The heavy lifting is done in
6715 * getChildMeasureSpec.
6716 *
6717 * @param widthMeasureSpec The width requirements for this view
6718 * @param heightMeasureSpec The height requirements for this view
6719 */
6720 protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec) {
6721 final int size = mChildrenCount;
6722 final View[] children = mChildren;
6723 for (int i = 0; i < size; ++i) {
6724 final View child = children[i];
6725 if ((child.mViewFlags & VISIBILITY_MASK) != GONE) {
6726 measureChild(child, widthMeasureSpec, heightMeasureSpec);
6727 }
6728 }
6729 }
6730
6731 /**
6732 * Ask one of the children of this view to measure itself, taking into
6733 * account both the MeasureSpec requirements for this view and its padding.
6734 * The heavy lifting is done in getChildMeasureSpec.
6735 *
6736 * @param child The child to measure
6737 * @param parentWidthMeasureSpec The width requirements for this view
6738 * @param parentHeightMeasureSpec The height requirements for this view
6739 */
6740 protected void measureChild(View child, int parentWidthMeasureSpec,
6741 int parentHeightMeasureSpec) {
6742 final LayoutParams lp = child.getLayoutParams();
6743
6744 final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
6745 mPaddingLeft + mPaddingRight, lp.width);
6746 final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
6747 mPaddingTop + mPaddingBottom, lp.height);
6748
6749 child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
6750 }
6751
6752 /**
6753 * Ask one of the children of this view to measure itself, taking into
6754 * account both the MeasureSpec requirements for this view and its padding
6755 * and margins. The child must have MarginLayoutParams The heavy lifting is
6756 * done in getChildMeasureSpec.
6757 *
6758 * @param child The child to measure
6759 * @param parentWidthMeasureSpec The width requirements for this view
6760 * @param widthUsed Extra space that has been used up by the parent
6761 * horizontally (possibly by other children of the parent)
6762 * @param parentHeightMeasureSpec The height requirements for this view
6763 * @param heightUsed Extra space that has been used up by the parent
6764 * vertically (possibly by other children of the parent)
6765 */
6766 protected void measureChildWithMargins(View child,
6767 int parentWidthMeasureSpec, int widthUsed,
6768 int parentHeightMeasureSpec, int heightUsed) {
6769 final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
6770
6771 final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
6772 mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin
6773 + widthUsed, lp.width);
6774 final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
6775 mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin
6776 + heightUsed, lp.height);
6777
6778 child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
6779 }
6780
6781 /**
6782 * Does the hard part of measureChildren: figuring out the MeasureSpec to
6783 * pass to a particular child. This method figures out the right MeasureSpec
6784 * for one dimension (height or width) of one child view.
6785 *
6786 * The goal is to combine information from our MeasureSpec with the
6787 * LayoutParams of the child to get the best possible results. For example,
6788 * if the this view knows its size (because its MeasureSpec has a mode of
6789 * EXACTLY), and the child has indicated in its LayoutParams that it wants
6790 * to be the same size as the parent, the parent should ask the child to
6791 * layout given an exact size.
6792 *
6793 * @param spec The requirements for this view
6794 * @param padding The padding of this view for the current dimension and
6795 * margins, if applicable
6796 * @param childDimension How big the child wants to be in the current
6797 * dimension
6798 * @return a MeasureSpec integer for the child
6799 */
6800 public static int getChildMeasureSpec(int spec, int padding, int childDimension) {
6801 int specMode = MeasureSpec.getMode(spec);
6802 int specSize = MeasureSpec.getSize(spec);
6803
6804 int size = Math.max(0, specSize - padding);
6805
6806 int resultSize = 0;
6807 int resultMode = 0;
6808
6809 switch (specMode) {
6810 // Parent has imposed an exact size on us
6811 case MeasureSpec.EXACTLY:
6812 if (childDimension >= 0) {
6813 resultSize = childDimension;
6814 resultMode = MeasureSpec.EXACTLY;
Romain Guy980a9382010-01-08 15:06:28 -08006815 } else if (childDimension == LayoutParams.MATCH_PARENT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006816 // Child wants to be our size. So be it.
6817 resultSize = size;
6818 resultMode = MeasureSpec.EXACTLY;
6819 } else if (childDimension == LayoutParams.WRAP_CONTENT) {
6820 // Child wants to determine its own size. It can't be
6821 // bigger than us.
6822 resultSize = size;
6823 resultMode = MeasureSpec.AT_MOST;
6824 }
6825 break;
6826
6827 // Parent has imposed a maximum size on us
6828 case MeasureSpec.AT_MOST:
6829 if (childDimension >= 0) {
6830 // Child wants a specific size... so be it
6831 resultSize = childDimension;
6832 resultMode = MeasureSpec.EXACTLY;
Romain Guy980a9382010-01-08 15:06:28 -08006833 } else if (childDimension == LayoutParams.MATCH_PARENT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006834 // Child wants to be our size, but our size is not fixed.
6835 // Constrain child to not be bigger than us.
6836 resultSize = size;
6837 resultMode = MeasureSpec.AT_MOST;
6838 } else if (childDimension == LayoutParams.WRAP_CONTENT) {
6839 // Child wants to determine its own size. It can't be
6840 // bigger than us.
6841 resultSize = size;
6842 resultMode = MeasureSpec.AT_MOST;
6843 }
6844 break;
6845
6846 // Parent asked to see how big we want to be
6847 case MeasureSpec.UNSPECIFIED:
6848 if (childDimension >= 0) {
6849 // Child wants a specific size... let him have it
6850 resultSize = childDimension;
6851 resultMode = MeasureSpec.EXACTLY;
Romain Guy980a9382010-01-08 15:06:28 -08006852 } else if (childDimension == LayoutParams.MATCH_PARENT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006853 // Child wants to be our size... find out how big it should
6854 // be
Adam Powelld5dbf4b2015-06-11 13:19:24 -07006855 resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006856 resultMode = MeasureSpec.UNSPECIFIED;
6857 } else if (childDimension == LayoutParams.WRAP_CONTENT) {
6858 // Child wants to determine its own size.... find out how
6859 // big it should be
Adam Powelld5dbf4b2015-06-11 13:19:24 -07006860 resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006861 resultMode = MeasureSpec.UNSPECIFIED;
6862 }
6863 break;
6864 }
Tor Norbye67568642015-03-31 07:47:23 -07006865 //noinspection ResourceType
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006866 return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
6867 }
6868
6869
6870 /**
6871 * Removes any pending animations for views that have been removed. Call
6872 * this if you don't want animations for exiting views to stack up.
6873 */
6874 public void clearDisappearingChildren() {
John Reckca7a9da2014-03-05 16:29:07 -08006875 final ArrayList<View> disappearingChildren = mDisappearingChildren;
6876 if (disappearingChildren != null) {
6877 final int count = disappearingChildren.size();
6878 for (int i = 0; i < count; i++) {
6879 final View view = disappearingChildren.get(i);
6880 if (view.mAttachInfo != null) {
6881 view.dispatchDetachedFromWindow();
6882 }
6883 view.clearAnimation();
6884 }
6885 disappearingChildren.clear();
Chet Haaseb85967b2012-03-26 14:37:51 -07006886 invalidate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006887 }
6888 }
6889
6890 /**
6891 * Add a view which is removed from mChildren but still needs animation
6892 *
6893 * @param v View to add
6894 */
6895 private void addDisappearingView(View v) {
6896 ArrayList<View> disappearingChildren = mDisappearingChildren;
6897
6898 if (disappearingChildren == null) {
6899 disappearingChildren = mDisappearingChildren = new ArrayList<View>();
6900 }
6901
6902 disappearingChildren.add(v);
6903 }
6904
6905 /**
6906 * Cleanup a view when its animation is done. This may mean removing it from
6907 * the list of disappearing views.
6908 *
6909 * @param view The view whose animation has finished
6910 * @param animation The animation, cannot be null
6911 */
Chet Haase64a48c12012-02-13 16:33:29 -08006912 void finishAnimatingView(final View view, Animation animation) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006913 final ArrayList<View> disappearingChildren = mDisappearingChildren;
6914 if (disappearingChildren != null) {
6915 if (disappearingChildren.contains(view)) {
6916 disappearingChildren.remove(view);
6917
6918 if (view.mAttachInfo != null) {
6919 view.dispatchDetachedFromWindow();
6920 }
6921
6922 view.clearAnimation();
6923 mGroupFlags |= FLAG_INVALIDATE_REQUIRED;
6924 }
6925 }
6926
6927 if (animation != null && !animation.getFillAfter()) {
6928 view.clearAnimation();
6929 }
6930
Dianne Hackborn4702a852012-08-17 15:18:29 -07006931 if ((view.mPrivateFlags & PFLAG_ANIMATION_STARTED) == PFLAG_ANIMATION_STARTED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006932 view.onAnimationEnd();
6933 // Should be performed by onAnimationEnd() but this avoid an infinite loop,
6934 // so we'd rather be safe than sorry
Dianne Hackborn4702a852012-08-17 15:18:29 -07006935 view.mPrivateFlags &= ~PFLAG_ANIMATION_STARTED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006936 // Draw one more frame after the animation is done
6937 mGroupFlags |= FLAG_INVALIDATE_REQUIRED;
6938 }
6939 }
6940
Chet Haaseb20db3e2010-09-10 13:07:30 -07006941 /**
Chet Haaseaceafe62011-08-26 15:44:33 -07006942 * Utility function called by View during invalidation to determine whether a view that
6943 * is invisible or gone should still be invalidated because it is being transitioned (and
6944 * therefore still needs to be drawn).
6945 */
6946 boolean isViewTransitioning(View view) {
6947 return (mTransitioningViews != null && mTransitioningViews.contains(view));
6948 }
6949
6950 /**
Chet Haaseb20db3e2010-09-10 13:07:30 -07006951 * This method tells the ViewGroup that the given View object, which should have this
6952 * ViewGroup as its parent,
6953 * should be kept around (re-displayed when the ViewGroup draws its children) even if it
6954 * is removed from its parent. This allows animations, such as those used by
6955 * {@link android.app.Fragment} and {@link android.animation.LayoutTransition} to animate
6956 * the removal of views. A call to this method should always be accompanied by a later call
6957 * to {@link #endViewTransition(View)}, such as after an animation on the View has finished,
6958 * so that the View finally gets removed.
6959 *
6960 * @param view The View object to be kept visible even if it gets removed from its parent.
6961 */
6962 public void startViewTransition(View view) {
6963 if (view.mParent == this) {
6964 if (mTransitioningViews == null) {
6965 mTransitioningViews = new ArrayList<View>();
6966 }
6967 mTransitioningViews.add(view);
6968 }
6969 }
6970
6971 /**
6972 * This method should always be called following an earlier call to
6973 * {@link #startViewTransition(View)}. The given View is finally removed from its parent
6974 * and will no longer be displayed. Note that this method does not perform the functionality
6975 * of removing a view from its parent; it just discontinues the display of a View that
6976 * has previously been removed.
6977 *
6978 * @return view The View object that has been removed but is being kept around in the visible
6979 * hierarchy by an earlier call to {@link #startViewTransition(View)}.
6980 */
6981 public void endViewTransition(View view) {
6982 if (mTransitioningViews != null) {
6983 mTransitioningViews.remove(view);
6984 final ArrayList<View> disappearingChildren = mDisappearingChildren;
6985 if (disappearingChildren != null && disappearingChildren.contains(view)) {
6986 disappearingChildren.remove(view);
Chet Haase5e25c2c2010-09-16 11:15:56 -07006987 if (mVisibilityChangingChildren != null &&
6988 mVisibilityChangingChildren.contains(view)) {
6989 mVisibilityChangingChildren.remove(view);
6990 } else {
6991 if (view.mAttachInfo != null) {
6992 view.dispatchDetachedFromWindow();
6993 }
6994 if (view.mParent != null) {
6995 view.mParent = null;
6996 }
Chet Haaseb20db3e2010-09-10 13:07:30 -07006997 }
Chet Haaseb85967b2012-03-26 14:37:51 -07006998 invalidate();
Chet Haaseb20db3e2010-09-10 13:07:30 -07006999 }
7000 }
7001 }
7002
Chet Haase21cd1382010-09-01 17:42:29 -07007003 private LayoutTransition.TransitionListener mLayoutTransitionListener =
7004 new LayoutTransition.TransitionListener() {
7005 @Override
7006 public void startTransition(LayoutTransition transition, ViewGroup container,
7007 View view, int transitionType) {
7008 // We only care about disappearing items, since we need special logic to keep
7009 // those items visible after they've been 'removed'
7010 if (transitionType == LayoutTransition.DISAPPEARING) {
Chet Haaseb20db3e2010-09-10 13:07:30 -07007011 startViewTransition(view);
Chet Haase21cd1382010-09-01 17:42:29 -07007012 }
7013 }
7014
7015 @Override
7016 public void endTransition(LayoutTransition transition, ViewGroup container,
7017 View view, int transitionType) {
Chet Haaseb9895022013-04-02 15:10:58 -07007018 if (mLayoutCalledWhileSuppressed && !transition.isChangingLayout()) {
Chet Haase9c087442011-01-12 16:20:16 -08007019 requestLayout();
Chet Haaseb9895022013-04-02 15:10:58 -07007020 mLayoutCalledWhileSuppressed = false;
Chet Haase9c087442011-01-12 16:20:16 -08007021 }
Chet Haase21cd1382010-09-01 17:42:29 -07007022 if (transitionType == LayoutTransition.DISAPPEARING && mTransitioningViews != null) {
Chet Haaseb20db3e2010-09-10 13:07:30 -07007023 endViewTransition(view);
Chet Haase21cd1382010-09-01 17:42:29 -07007024 }
7025 }
7026 };
7027
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007028 /**
Chet Haaseb9895022013-04-02 15:10:58 -07007029 * Tells this ViewGroup to suppress all layout() calls until layout
7030 * suppression is disabled with a later call to suppressLayout(false).
7031 * When layout suppression is disabled, a requestLayout() call is sent
7032 * if layout() was attempted while layout was being suppressed.
7033 *
7034 * @hide
7035 */
Mathew Inwoode5ad5982018-08-17 15:07:52 +01007036 @UnsupportedAppUsage
Chet Haaseb9895022013-04-02 15:10:58 -07007037 public void suppressLayout(boolean suppress) {
7038 mSuppressLayout = suppress;
7039 if (!suppress) {
7040 if (mLayoutCalledWhileSuppressed) {
7041 requestLayout();
7042 mLayoutCalledWhileSuppressed = false;
7043 }
7044 }
7045 }
7046
7047 /**
Chet Haase199acdf2013-07-24 18:40:55 -07007048 * Returns whether layout calls on this container are currently being
7049 * suppressed, due to an earlier call to {@link #suppressLayout(boolean)}.
7050 *
7051 * @return true if layout calls are currently suppressed, false otherwise.
7052 *
7053 * @hide
7054 */
7055 public boolean isLayoutSuppressed() {
7056 return mSuppressLayout;
7057 }
7058
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007059 @Override
7060 public boolean gatherTransparentRegion(Region region) {
7061 // If no transparent regions requested, we are always opaque.
Dianne Hackborn4702a852012-08-17 15:18:29 -07007062 final boolean meOpaque = (mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) == 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007063 if (meOpaque && region == null) {
7064 // The caller doesn't care about the region, so stop now.
7065 return true;
7066 }
7067 super.gatherTransparentRegion(region);
Teng-Hui Zhuf8da30d2016-08-15 10:28:20 -07007068 // Instead of naively traversing the view tree, we have to traverse according to the Z
7069 // order here. We need to go with the same order as dispatchDraw().
7070 // One example is that after surfaceView punch a hole, we will still allow other views drawn
7071 // on top of that hole. In this case, those other views should be able to cut the
7072 // transparent region into smaller area.
7073 final int childrenCount = mChildrenCount;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007074 boolean noneOfTheChildrenAreTransparent = true;
Teng-Hui Zhuf8da30d2016-08-15 10:28:20 -07007075 if (childrenCount > 0) {
7076 final ArrayList<View> preorderedList = buildOrderedChildList();
7077 final boolean customOrder = preorderedList == null
7078 && isChildrenDrawingOrderEnabled();
7079 final View[] children = mChildren;
7080 for (int i = 0; i < childrenCount; i++) {
7081 final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
7082 final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);
7083 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
7084 if (!child.gatherTransparentRegion(region)) {
7085 noneOfTheChildrenAreTransparent = false;
7086 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007087 }
7088 }
Teng-Hui Zhuf8da30d2016-08-15 10:28:20 -07007089 if (preorderedList != null) preorderedList.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007090 }
7091 return meOpaque || noneOfTheChildrenAreTransparent;
7092 }
7093
Alan Viverettebe463f22016-01-21 10:50:10 -05007094 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007095 public void requestTransparentRegion(View child) {
7096 if (child != null) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07007097 child.mPrivateFlags |= View.PFLAG_REQUEST_TRANSPARENT_REGIONS;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007098 if (mParent != null) {
7099 mParent.requestTransparentRegion(this);
7100 }
7101 }
7102 }
Romain Guy8506ab42009-06-11 17:35:47 -07007103
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007104 @Override
Adam Powell46e38fd2014-02-03 10:16:49 -08007105 public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) {
7106 insets = super.dispatchApplyWindowInsets(insets);
Adam Powell0d9fdba2014-06-11 15:33:08 -07007107 if (!insets.isConsumed()) {
Adam Powell46e38fd2014-02-03 10:16:49 -08007108 final int count = getChildCount();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007109 for (int i = 0; i < count; i++) {
Adam Powell46e38fd2014-02-03 10:16:49 -08007110 insets = getChildAt(i).dispatchApplyWindowInsets(insets);
Adam Powell0d9fdba2014-06-11 15:33:08 -07007111 if (insets.isConsumed()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007112 break;
7113 }
7114 }
7115 }
Adam Powell46e38fd2014-02-03 10:16:49 -08007116 return insets;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007117 }
7118
7119 /**
7120 * Returns the animation listener to which layout animation events are
7121 * sent.
7122 *
7123 * @return an {@link android.view.animation.Animation.AnimationListener}
7124 */
7125 public Animation.AnimationListener getLayoutAnimationListener() {
7126 return mAnimationListener;
7127 }
7128
7129 @Override
7130 protected void drawableStateChanged() {
7131 super.drawableStateChanged();
7132
7133 if ((mGroupFlags & FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE) != 0) {
7134 if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0) {
7135 throw new IllegalStateException("addStateFromChildren cannot be enabled if a"
7136 + " child has duplicateParentState set to true");
7137 }
7138
7139 final View[] children = mChildren;
7140 final int count = mChildrenCount;
7141
7142 for (int i = 0; i < count; i++) {
7143 final View child = children[i];
7144 if ((child.mViewFlags & DUPLICATE_PARENT_STATE) != 0) {
7145 child.refreshDrawableState();
7146 }
7147 }
7148 }
7149 }
7150
7151 @Override
Dianne Hackborne2136772010-11-04 15:08:59 -07007152 public void jumpDrawablesToCurrentState() {
7153 super.jumpDrawablesToCurrentState();
7154 final View[] children = mChildren;
7155 final int count = mChildrenCount;
7156 for (int i = 0; i < count; i++) {
7157 children[i].jumpDrawablesToCurrentState();
7158 }
7159 }
7160
7161 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007162 protected int[] onCreateDrawableState(int extraSpace) {
7163 if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) == 0) {
7164 return super.onCreateDrawableState(extraSpace);
7165 }
7166
7167 int need = 0;
7168 int n = getChildCount();
7169 for (int i = 0; i < n; i++) {
7170 int[] childState = getChildAt(i).getDrawableState();
7171
7172 if (childState != null) {
7173 need += childState.length;
7174 }
7175 }
7176
7177 int[] state = super.onCreateDrawableState(extraSpace + need);
7178
7179 for (int i = 0; i < n; i++) {
7180 int[] childState = getChildAt(i).getDrawableState();
7181
7182 if (childState != null) {
7183 state = mergeDrawableStates(state, childState);
7184 }
7185 }
7186
7187 return state;
7188 }
7189
7190 /**
7191 * Sets whether this ViewGroup's drawable states also include
7192 * its children's drawable states. This is used, for example, to
7193 * make a group appear to be focused when its child EditText or button
7194 * is focused.
7195 */
7196 public void setAddStatesFromChildren(boolean addsStates) {
7197 if (addsStates) {
7198 mGroupFlags |= FLAG_ADD_STATES_FROM_CHILDREN;
7199 } else {
7200 mGroupFlags &= ~FLAG_ADD_STATES_FROM_CHILDREN;
7201 }
7202
7203 refreshDrawableState();
7204 }
7205
7206 /**
7207 * Returns whether this ViewGroup's drawable states also include
7208 * its children's drawable states. This is used, for example, to
7209 * make a group appear to be focused when its child EditText or button
7210 * is focused.
7211 */
7212 public boolean addStatesFromChildren() {
7213 return (mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0;
7214 }
7215
7216 /**
Jeff Smitha45746e2012-07-19 14:19:24 -05007217 * If {@link #addStatesFromChildren} is true, refreshes this group's
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007218 * drawable state (to include the states from its children).
7219 */
Alan Viverettebe463f22016-01-21 10:50:10 -05007220 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007221 public void childDrawableStateChanged(View child) {
7222 if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0) {
7223 refreshDrawableState();
7224 }
7225 }
7226
7227 /**
7228 * Specifies the animation listener to which layout animation events must
7229 * be sent. Only
7230 * {@link android.view.animation.Animation.AnimationListener#onAnimationStart(Animation)}
7231 * and
7232 * {@link android.view.animation.Animation.AnimationListener#onAnimationEnd(Animation)}
7233 * are invoked.
7234 *
7235 * @param animationListener the layout animation listener
7236 */
7237 public void setLayoutAnimationListener(Animation.AnimationListener animationListener) {
7238 mAnimationListener = animationListener;
7239 }
7240
7241 /**
Chet Haasecca2c982011-05-20 14:34:18 -07007242 * This method is called by LayoutTransition when there are 'changing' animations that need
7243 * to start after the layout/setup phase. The request is forwarded to the ViewAncestor, who
7244 * starts all pending transitions prior to the drawing phase in the current traversal.
7245 *
7246 * @param transition The LayoutTransition to be started on the next traversal.
7247 *
7248 * @hide
7249 */
7250 public void requestTransitionStart(LayoutTransition transition) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07007251 ViewRootImpl viewAncestor = getViewRootImpl();
Chet Haase1abf7fa2011-08-17 18:31:56 -07007252 if (viewAncestor != null) {
7253 viewAncestor.requestTransitionStart(transition);
7254 }
Chet Haasecca2c982011-05-20 14:34:18 -07007255 }
7256
Fabrice Di Meglio4457e852012-09-18 19:23:12 -07007257 /**
7258 * @hide
7259 */
Fabrice Di Meglio80dc53d2011-06-21 18:36:33 -07007260 @Override
Fabrice Di Meglio09ecb252013-05-03 16:51:55 -07007261 public boolean resolveRtlPropertiesIfNeeded() {
7262 final boolean result = super.resolveRtlPropertiesIfNeeded();
7263 // We dont need to resolve the children RTL properties if nothing has changed for the parent
7264 if (result) {
7265 int count = getChildCount();
7266 for (int i = 0; i < count; i++) {
7267 final View child = getChildAt(i);
7268 if (child.isLayoutDirectionInherited()) {
7269 child.resolveRtlPropertiesIfNeeded();
7270 }
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07007271 }
7272 }
Fabrice Di Meglio09ecb252013-05-03 16:51:55 -07007273 return result;
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07007274 }
7275
7276 /**
7277 * @hide
7278 */
7279 @Override
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07007280 public boolean resolveLayoutDirection() {
7281 final boolean result = super.resolveLayoutDirection();
7282 if (result) {
7283 int count = getChildCount();
7284 for (int i = 0; i < count; i++) {
7285 final View child = getChildAt(i);
7286 if (child.isLayoutDirectionInherited()) {
7287 child.resolveLayoutDirection();
7288 }
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07007289 }
7290 }
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07007291 return result;
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07007292 }
7293
7294 /**
7295 * @hide
7296 */
7297 @Override
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07007298 public boolean resolveTextDirection() {
7299 final boolean result = super.resolveTextDirection();
7300 if (result) {
7301 int count = getChildCount();
7302 for (int i = 0; i < count; i++) {
7303 final View child = getChildAt(i);
7304 if (child.isTextDirectionInherited()) {
7305 child.resolveTextDirection();
7306 }
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07007307 }
7308 }
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07007309 return result;
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07007310 }
7311
7312 /**
7313 * @hide
7314 */
7315 @Override
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07007316 public boolean resolveTextAlignment() {
7317 final boolean result = super.resolveTextAlignment();
7318 if (result) {
7319 int count = getChildCount();
7320 for (int i = 0; i < count; i++) {
7321 final View child = getChildAt(i);
7322 if (child.isTextAlignmentInherited()) {
7323 child.resolveTextAlignment();
7324 }
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07007325 }
7326 }
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07007327 return result;
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07007328 }
7329
7330 /**
7331 * @hide
7332 */
7333 @Override
Mathew Inwoode5ad5982018-08-17 15:07:52 +01007334 @UnsupportedAppUsage
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07007335 public void resolvePadding() {
7336 super.resolvePadding();
7337 int count = getChildCount();
7338 for (int i = 0; i < count; i++) {
7339 final View child = getChildAt(i);
Adam Powell05f35122014-11-10 17:47:37 -08007340 if (child.isLayoutDirectionInherited() && !child.isPaddingResolved()) {
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07007341 child.resolvePadding();
7342 }
7343 }
7344 }
7345
7346 /**
7347 * @hide
7348 */
7349 @Override
7350 protected void resolveDrawables() {
7351 super.resolveDrawables();
7352 int count = getChildCount();
7353 for (int i = 0; i < count; i++) {
7354 final View child = getChildAt(i);
Adam Powell05f35122014-11-10 17:47:37 -08007355 if (child.isLayoutDirectionInherited() && !child.areDrawablesResolved()) {
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07007356 child.resolveDrawables();
7357 }
7358 }
7359 }
7360
Fabrice Di Meglio1e0ed6b2012-10-18 16:06:52 -07007361 /**
7362 * @hide
7363 */
Fabrice Di Megliofcc33482012-10-18 11:11:51 -07007364 @Override
7365 public void resolveLayoutParams() {
7366 super.resolveLayoutParams();
7367 int count = getChildCount();
7368 for (int i = 0; i < count; i++) {
7369 final View child = getChildAt(i);
7370 child.resolveLayoutParams();
7371 }
7372 }
7373
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07007374 /**
7375 * @hide
7376 */
7377 @Override
Mathew Inwoode5ad5982018-08-17 15:07:52 +01007378 @UnsupportedAppUsage
Fabrice Di Meglio4457e852012-09-18 19:23:12 -07007379 public void resetResolvedLayoutDirection() {
7380 super.resetResolvedLayoutDirection();
7381
Fabrice Di Meglio4457e852012-09-18 19:23:12 -07007382 int count = getChildCount();
Fabrice Di Meglio80dc53d2011-06-21 18:36:33 -07007383 for (int i = 0; i < count; i++) {
7384 final View child = getChildAt(i);
Fabrice Di Meglioe56ffdc2012-09-23 14:51:16 -07007385 if (child.isLayoutDirectionInherited()) {
Fabrice Di Meglio7f86c802011-07-01 15:09:24 -07007386 child.resetResolvedLayoutDirection();
Fabrice Di Meglio80dc53d2011-06-21 18:36:33 -07007387 }
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07007388 }
7389 }
7390
7391 /**
7392 * @hide
7393 */
7394 @Override
Mathew Inwoode5ad5982018-08-17 15:07:52 +01007395 @UnsupportedAppUsage
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07007396 public void resetResolvedTextDirection() {
7397 super.resetResolvedTextDirection();
7398
7399 int count = getChildCount();
7400 for (int i = 0; i < count; i++) {
7401 final View child = getChildAt(i);
Fabrice Di Meglio97e146c2012-09-23 15:45:16 -07007402 if (child.isTextDirectionInherited()) {
Fabrice Di Meglio22268862011-06-27 18:13:18 -07007403 child.resetResolvedTextDirection();
7404 }
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07007405 }
7406 }
7407
7408 /**
7409 * @hide
7410 */
7411 @Override
Mathew Inwoode5ad5982018-08-17 15:07:52 +01007412 @UnsupportedAppUsage
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07007413 public void resetResolvedTextAlignment() {
7414 super.resetResolvedTextAlignment();
7415
7416 int count = getChildCount();
7417 for (int i = 0; i < count; i++) {
7418 final View child = getChildAt(i);
Fabrice Di Meglio1a7d4872012-09-23 16:19:58 -07007419 if (child.isTextAlignmentInherited()) {
Fabrice Di Meglio9da0f8a2012-03-13 19:37:57 -07007420 child.resetResolvedTextAlignment();
7421 }
7422 }
7423 }
7424
Fabrice Di Meglio22268862011-06-27 18:13:18 -07007425 /**
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07007426 * @hide
7427 */
7428 @Override
Mathew Inwoode5ad5982018-08-17 15:07:52 +01007429 @UnsupportedAppUsage
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07007430 public void resetResolvedPadding() {
7431 super.resetResolvedPadding();
7432
7433 int count = getChildCount();
7434 for (int i = 0; i < count; i++) {
7435 final View child = getChildAt(i);
7436 if (child.isLayoutDirectionInherited()) {
7437 child.resetResolvedPadding();
7438 }
7439 }
7440 }
7441
7442 /**
7443 * @hide
7444 */
7445 @Override
Mathew Inwoode5ad5982018-08-17 15:07:52 +01007446 @UnsupportedAppUsage
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07007447 protected void resetResolvedDrawables() {
7448 super.resetResolvedDrawables();
7449
7450 int count = getChildCount();
7451 for (int i = 0; i < count; i++) {
7452 final View child = getChildAt(i);
7453 if (child.isLayoutDirectionInherited()) {
7454 child.resetResolvedDrawables();
7455 }
7456 }
7457 }
7458
7459 /**
Patrick Dubroye0a799a2011-05-04 16:19:22 -07007460 * Return true if the pressed state should be delayed for children or descendants of this
7461 * ViewGroup. Generally, this should be done for containers that can scroll, such as a List.
7462 * This prevents the pressed state from appearing when the user is actually trying to scroll
7463 * the content.
7464 *
7465 * The default implementation returns true for compatibility reasons. Subclasses that do
7466 * not scroll should generally override this method and return false.
7467 */
7468 public boolean shouldDelayChildPressedState() {
7469 return true;
7470 }
7471
Adam Powell10ba2772014-04-15 09:46:51 -07007472 /**
7473 * @inheritDoc
7474 */
7475 @Override
7476 public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
7477 return false;
7478 }
7479
7480 /**
7481 * @inheritDoc
7482 */
7483 @Override
7484 public void onNestedScrollAccepted(View child, View target, int axes) {
7485 mNestedScrollAxes = axes;
7486 }
7487
7488 /**
7489 * @inheritDoc
7490 *
7491 * <p>The default implementation of onStopNestedScroll calls
7492 * {@link #stopNestedScroll()} to halt any recursive nested scrolling in progress.</p>
7493 */
7494 @Override
7495 public void onStopNestedScroll(View child) {
7496 // Stop any recursive nested scrolling.
7497 stopNestedScroll();
Adam Powelld4a22d42015-04-16 15:44:10 -07007498 mNestedScrollAxes = 0;
Adam Powell10ba2772014-04-15 09:46:51 -07007499 }
7500
7501 /**
7502 * @inheritDoc
7503 */
7504 @Override
7505 public void onNestedScroll(View target, int dxConsumed, int dyConsumed,
7506 int dxUnconsumed, int dyUnconsumed) {
Chris Banes61d50702016-03-23 13:11:45 +00007507 // Re-dispatch up the tree by default
7508 dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, null);
Adam Powell10ba2772014-04-15 09:46:51 -07007509 }
7510
7511 /**
7512 * @inheritDoc
7513 */
7514 @Override
7515 public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
Chris Banes61d50702016-03-23 13:11:45 +00007516 // Re-dispatch up the tree by default
7517 dispatchNestedPreScroll(dx, dy, consumed, null);
Adam Powell10ba2772014-04-15 09:46:51 -07007518 }
7519
7520 /**
7521 * @inheritDoc
7522 */
7523 @Override
Adam Powellb36e4f92014-05-01 10:23:33 -07007524 public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
Chris Banes61d50702016-03-23 13:11:45 +00007525 // Re-dispatch up the tree by default
7526 return dispatchNestedFling(velocityX, velocityY, consumed);
Adam Powell10ba2772014-04-15 09:46:51 -07007527 }
7528
7529 /**
Adam Powellb72be592014-07-16 21:41:31 -07007530 * @inheritDoc
7531 */
7532 @Override
7533 public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
Chris Banes61d50702016-03-23 13:11:45 +00007534 // Re-dispatch up the tree by default
7535 return dispatchNestedPreFling(velocityX, velocityY);
Adam Powellb72be592014-07-16 21:41:31 -07007536 }
7537
7538 /**
Adam Powell10ba2772014-04-15 09:46:51 -07007539 * Return the current axes of nested scrolling for this ViewGroup.
7540 *
7541 * <p>A ViewGroup returning something other than {@link #SCROLL_AXIS_NONE} is currently
7542 * acting as a nested scrolling parent for one or more descendant views in the hierarchy.</p>
7543 *
7544 * @return Flags indicating the current axes of nested scrolling
7545 * @see #SCROLL_AXIS_HORIZONTAL
7546 * @see #SCROLL_AXIS_VERTICAL
7547 * @see #SCROLL_AXIS_NONE
7548 */
7549 public int getNestedScrollAxes() {
7550 return mNestedScrollAxes;
7551 }
7552
Philip Milned7dd8902012-01-26 16:55:30 -08007553 /** @hide */
7554 protected void onSetLayoutParams(View child, LayoutParams layoutParams) {
Robert Carr5429daa2017-04-03 19:00:26 -07007555 requestLayout();
Philip Milned7dd8902012-01-26 16:55:30 -08007556 }
7557
George Mounte1803372014-02-26 19:00:52 +00007558 /** @hide */
7559 @Override
7560 public void captureTransitioningViews(List<View> transitioningViews) {
7561 if (getVisibility() != View.VISIBLE) {
7562 return;
7563 }
7564 if (isTransitionGroup()) {
7565 transitioningViews.add(this);
7566 } else {
7567 int count = getChildCount();
7568 for (int i = 0; i < count; i++) {
7569 View child = getChildAt(i);
7570 child.captureTransitioningViews(transitioningViews);
7571 }
7572 }
7573 }
7574
7575 /** @hide */
7576 @Override
George Mountabb352a2014-05-09 10:27:20 -07007577 public void findNamedViews(Map<String, View> namedElements) {
George Mountfe361d22014-07-08 17:25:25 -07007578 if (getVisibility() != VISIBLE && mGhostView == null) {
George Mounte1803372014-02-26 19:00:52 +00007579 return;
7580 }
George Mountabb352a2014-05-09 10:27:20 -07007581 super.findNamedViews(namedElements);
George Mounte1803372014-02-26 19:00:52 +00007582 int count = getChildCount();
7583 for (int i = 0; i < count; i++) {
7584 View child = getChildAt(i);
George Mountabb352a2014-05-09 10:27:20 -07007585 child.findNamedViews(namedElements);
George Mounte1803372014-02-26 19:00:52 +00007586 }
7587 }
7588
Evan Rosky4807ae22018-03-22 16:04:15 -07007589 @Override
7590 boolean hasUnhandledKeyListener() {
7591 return (mChildUnhandledKeyListeners > 0) || super.hasUnhandledKeyListener();
7592 }
7593
7594 void incrementChildUnhandledKeyListeners() {
7595 mChildUnhandledKeyListeners += 1;
7596 if (mChildUnhandledKeyListeners == 1) {
7597 if (mParent instanceof ViewGroup) {
7598 ((ViewGroup) mParent).incrementChildUnhandledKeyListeners();
7599 }
7600 }
7601 }
7602
7603 void decrementChildUnhandledKeyListeners() {
7604 mChildUnhandledKeyListeners -= 1;
7605 if (mChildUnhandledKeyListeners == 0) {
7606 if (mParent instanceof ViewGroup) {
7607 ((ViewGroup) mParent).decrementChildUnhandledKeyListeners();
7608 }
7609 }
7610 }
7611
7612 @Override
7613 View dispatchUnhandledKeyEvent(KeyEvent evt) {
7614 if (!hasUnhandledKeyListener()) {
7615 return null;
7616 }
7617 ArrayList<View> orderedViews = buildOrderedChildList();
7618 if (orderedViews != null) {
7619 try {
7620 for (int i = orderedViews.size() - 1; i >= 0; --i) {
7621 View v = orderedViews.get(i);
7622 View consumer = v.dispatchUnhandledKeyEvent(evt);
7623 if (consumer != null) {
7624 return consumer;
7625 }
7626 }
7627 } finally {
7628 orderedViews.clear();
7629 }
7630 } else {
7631 for (int i = getChildCount() - 1; i >= 0; --i) {
7632 View v = getChildAt(i);
7633 View consumer = v.dispatchUnhandledKeyEvent(evt);
7634 if (consumer != null) {
7635 return consumer;
7636 }
7637 }
7638 }
7639 if (onUnhandledKeyEvent(evt)) {
7640 return this;
7641 }
7642 return null;
7643 }
7644
Patrick Dubroye0a799a2011-05-04 16:19:22 -07007645 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007646 * LayoutParams are used by views to tell their parents how they want to be
7647 * laid out. See
7648 * {@link android.R.styleable#ViewGroup_Layout ViewGroup Layout Attributes}
7649 * for a list of all child view attributes that this class supports.
Romain Guy8506ab42009-06-11 17:35:47 -07007650 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007651 * <p>
7652 * The base LayoutParams class just describes how big the view wants to be
7653 * for both width and height. For each dimension, it can specify one of:
7654 * <ul>
Dirk Dougherty75c66da2010-03-25 16:33:33 -07007655 * <li>FILL_PARENT (renamed MATCH_PARENT in API Level 8 and higher), which
7656 * means that the view wants to be as big as its parent (minus padding)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007657 * <li> WRAP_CONTENT, which means that the view wants to be just big enough
7658 * to enclose its content (plus padding)
Dirk Dougherty75c66da2010-03-25 16:33:33 -07007659 * <li> an exact number
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007660 * </ul>
7661 * There are subclasses of LayoutParams for different subclasses of
7662 * ViewGroup. For example, AbsoluteLayout has its own subclass of
Joe Fernandez558459f2011-10-13 16:47:36 -07007663 * LayoutParams which adds an X and Y value.</p>
7664 *
7665 * <div class="special reference">
7666 * <h3>Developer Guides</h3>
7667 * <p>For more information about creating user interface layouts, read the
7668 * <a href="{@docRoot}guide/topics/ui/declaring-layout.html">XML Layouts</a> developer
7669 * guide.</p></div>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007670 *
7671 * @attr ref android.R.styleable#ViewGroup_Layout_layout_height
7672 * @attr ref android.R.styleable#ViewGroup_Layout_layout_width
7673 */
7674 public static class LayoutParams {
7675 /**
Dirk Dougherty75c66da2010-03-25 16:33:33 -07007676 * Special value for the height or width requested by a View.
7677 * FILL_PARENT means that the view wants to be as big as its parent,
7678 * minus the parent's padding, if any. This value is deprecated
7679 * starting in API Level 8 and replaced by {@link #MATCH_PARENT}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007680 */
Romain Guy980a9382010-01-08 15:06:28 -08007681 @SuppressWarnings({"UnusedDeclaration"})
7682 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007683 public static final int FILL_PARENT = -1;
7684
7685 /**
7686 * Special value for the height or width requested by a View.
Gilles Debunnef5c6eff2010-02-09 19:08:36 -08007687 * MATCH_PARENT means that the view wants to be as big as its parent,
Dirk Dougherty75c66da2010-03-25 16:33:33 -07007688 * minus the parent's padding, if any. Introduced in API Level 8.
Romain Guy980a9382010-01-08 15:06:28 -08007689 */
7690 public static final int MATCH_PARENT = -1;
7691
7692 /**
7693 * Special value for the height or width requested by a View.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007694 * WRAP_CONTENT means that the view wants to be just large enough to fit
7695 * its own internal content, taking its own padding into account.
7696 */
7697 public static final int WRAP_CONTENT = -2;
7698
7699 /**
Dirk Dougherty75c66da2010-03-25 16:33:33 -07007700 * Information about how wide the view wants to be. Can be one of the
Mark Dolinerd0646dc2014-08-27 16:04:02 -07007701 * constants FILL_PARENT (replaced by MATCH_PARENT
7702 * in API Level 8) or WRAP_CONTENT, or an exact size.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007703 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07007704 @ViewDebug.ExportedProperty(category = "layout", mapping = {
Romain Guy980a9382010-01-08 15:06:28 -08007705 @ViewDebug.IntToString(from = MATCH_PARENT, to = "MATCH_PARENT"),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007706 @ViewDebug.IntToString(from = WRAP_CONTENT, to = "WRAP_CONTENT")
7707 })
7708 public int width;
7709
7710 /**
Dirk Dougherty75c66da2010-03-25 16:33:33 -07007711 * Information about how tall the view wants to be. Can be one of the
Mark Dolinerd0646dc2014-08-27 16:04:02 -07007712 * constants FILL_PARENT (replaced by MATCH_PARENT
7713 * in API Level 8) or WRAP_CONTENT, or an exact size.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007714 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07007715 @ViewDebug.ExportedProperty(category = "layout", mapping = {
Romain Guy980a9382010-01-08 15:06:28 -08007716 @ViewDebug.IntToString(from = MATCH_PARENT, to = "MATCH_PARENT"),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007717 @ViewDebug.IntToString(from = WRAP_CONTENT, to = "WRAP_CONTENT")
7718 })
7719 public int height;
7720
7721 /**
7722 * Used to animate layouts.
7723 */
7724 public LayoutAnimationController.AnimationParameters layoutAnimationParameters;
7725
7726 /**
7727 * Creates a new set of layout parameters. The values are extracted from
7728 * the supplied attributes set and context. The XML attributes mapped
7729 * to this set of layout parameters are:
7730 *
7731 * <ul>
7732 * <li><code>layout_width</code>: the width, either an exact value,
Dirk Dougherty75c66da2010-03-25 16:33:33 -07007733 * {@link #WRAP_CONTENT}, or {@link #FILL_PARENT} (replaced by
7734 * {@link #MATCH_PARENT} in API Level 8)</li>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007735 * <li><code>layout_height</code>: the height, either an exact value,
Dirk Dougherty75c66da2010-03-25 16:33:33 -07007736 * {@link #WRAP_CONTENT}, or {@link #FILL_PARENT} (replaced by
7737 * {@link #MATCH_PARENT} in API Level 8)</li>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007738 * </ul>
7739 *
7740 * @param c the application environment
7741 * @param attrs the set of attributes from which to extract the layout
7742 * parameters' values
7743 */
7744 public LayoutParams(Context c, AttributeSet attrs) {
7745 TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ViewGroup_Layout);
7746 setBaseAttributes(a,
7747 R.styleable.ViewGroup_Layout_layout_width,
7748 R.styleable.ViewGroup_Layout_layout_height);
7749 a.recycle();
7750 }
7751
7752 /**
7753 * Creates a new set of layout parameters with the specified width
7754 * and height.
7755 *
Dirk Dougherty75c66da2010-03-25 16:33:33 -07007756 * @param width the width, either {@link #WRAP_CONTENT},
7757 * {@link #FILL_PARENT} (replaced by {@link #MATCH_PARENT} in
7758 * API Level 8), or a fixed size in pixels
7759 * @param height the height, either {@link #WRAP_CONTENT},
7760 * {@link #FILL_PARENT} (replaced by {@link #MATCH_PARENT} in
7761 * API Level 8), or a fixed size in pixels
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007762 */
7763 public LayoutParams(int width, int height) {
7764 this.width = width;
7765 this.height = height;
7766 }
7767
7768 /**
7769 * Copy constructor. Clones the width and height values of the source.
7770 *
7771 * @param source The layout params to copy from.
7772 */
7773 public LayoutParams(LayoutParams source) {
7774 this.width = source.width;
7775 this.height = source.height;
7776 }
7777
7778 /**
7779 * Used internally by MarginLayoutParams.
7780 * @hide
7781 */
Mathew Inwoode5ad5982018-08-17 15:07:52 +01007782 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007783 LayoutParams() {
7784 }
7785
7786 /**
Dave Burke579e1402012-10-18 20:41:55 -07007787 * Extracts the layout parameters from the supplied attributes.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007788 *
7789 * @param a the style attributes to extract the parameters from
7790 * @param widthAttr the identifier of the width attribute
7791 * @param heightAttr the identifier of the height attribute
7792 */
7793 protected void setBaseAttributes(TypedArray a, int widthAttr, int heightAttr) {
Dave Burke579e1402012-10-18 20:41:55 -07007794 width = a.getLayoutDimension(widthAttr, "layout_width");
7795 height = a.getLayoutDimension(heightAttr, "layout_height");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007796 }
7797
7798 /**
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007799 * Resolve layout parameters depending on the layout direction. Subclasses that care about
7800 * layoutDirection changes should override this method. The default implementation does
7801 * nothing.
7802 *
7803 * @param layoutDirection the direction of the layout
7804 *
7805 * {@link View#LAYOUT_DIRECTION_LTR}
7806 * {@link View#LAYOUT_DIRECTION_RTL}
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007807 */
Fabrice Di Meglio2918ab62012-10-10 16:39:25 -07007808 public void resolveLayoutDirection(int layoutDirection) {
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007809 }
7810
7811 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007812 * Returns a String representation of this set of layout parameters.
7813 *
7814 * @param output the String to prepend to the internal representation
7815 * @return a String with the following format: output +
7816 * "ViewGroup.LayoutParams={ width=WIDTH, height=HEIGHT }"
Romain Guy8506ab42009-06-11 17:35:47 -07007817 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007818 * @hide
7819 */
7820 public String debug(String output) {
7821 return output + "ViewGroup.LayoutParams={ width="
7822 + sizeToString(width) + ", height=" + sizeToString(height) + " }";
7823 }
7824
7825 /**
Philip Milne10ca24a2012-04-23 15:38:27 -07007826 * Use {@code canvas} to draw suitable debugging annotations for these LayoutParameters.
7827 *
7828 * @param view the view that contains these layout parameters
7829 * @param canvas the canvas on which to draw
Alan Viverette2d7771c2018-01-31 17:04:31 -05007830 *
7831 * @hide
Philip Milne10ca24a2012-04-23 15:38:27 -07007832 */
Philip Milne7b757812012-09-19 18:13:44 -07007833 public void onDebugDraw(View view, Canvas canvas, Paint paint) {
Philip Milne10ca24a2012-04-23 15:38:27 -07007834 }
7835
7836 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007837 * Converts the specified size to a readable String.
7838 *
7839 * @param size the size to convert
7840 * @return a String instance representing the supplied size
Romain Guy8506ab42009-06-11 17:35:47 -07007841 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007842 * @hide
7843 */
7844 protected static String sizeToString(int size) {
7845 if (size == WRAP_CONTENT) {
7846 return "wrap-content";
7847 }
Romain Guy980a9382010-01-08 15:06:28 -08007848 if (size == MATCH_PARENT) {
7849 return "match-parent";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007850 }
7851 return String.valueOf(size);
7852 }
Siva Velusamy0d857b92015-04-22 10:23:56 -07007853
7854 /** @hide */
7855 void encode(@NonNull ViewHierarchyEncoder encoder) {
7856 encoder.beginObject(this);
7857 encodeProperties(encoder);
7858 encoder.endObject();
7859 }
7860
7861 /** @hide */
7862 protected void encodeProperties(@NonNull ViewHierarchyEncoder encoder) {
7863 encoder.addProperty("width", width);
7864 encoder.addProperty("height", height);
7865 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007866 }
7867
7868 /**
7869 * Per-child layout information for layouts that support margins.
7870 * See
7871 * {@link android.R.styleable#ViewGroup_MarginLayout ViewGroup Margin Layout Attributes}
7872 * for a list of all child view attributes that this class supports.
Chet Haase353d3972017-06-29 07:54:19 -07007873 *
7874 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_margin
7875 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginHorizontal
7876 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginVertical
7877 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginLeft
7878 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginTop
7879 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginRight
7880 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginBottom
7881 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
7882 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007883 */
7884 public static class MarginLayoutParams extends ViewGroup.LayoutParams {
7885 /**
Adam Powella7a735f2014-10-09 12:54:52 -07007886 * The left margin in pixels of the child. Margin values should be positive.
Philip Milned7dd8902012-01-26 16:55:30 -08007887 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
7888 * to this field.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007889 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07007890 @ViewDebug.ExportedProperty(category = "layout")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007891 public int leftMargin;
7892
7893 /**
Adam Powella7a735f2014-10-09 12:54:52 -07007894 * The top margin in pixels of the child. Margin values should be positive.
Philip Milned7dd8902012-01-26 16:55:30 -08007895 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
7896 * to this field.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007897 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07007898 @ViewDebug.ExportedProperty(category = "layout")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007899 public int topMargin;
7900
7901 /**
Adam Powella7a735f2014-10-09 12:54:52 -07007902 * The right margin in pixels of the child. Margin values should be positive.
Philip Milned7dd8902012-01-26 16:55:30 -08007903 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
7904 * to this field.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007905 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07007906 @ViewDebug.ExportedProperty(category = "layout")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007907 public int rightMargin;
7908
7909 /**
Adam Powella7a735f2014-10-09 12:54:52 -07007910 * The bottom margin in pixels of the child. Margin values should be positive.
Philip Milned7dd8902012-01-26 16:55:30 -08007911 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
7912 * to this field.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007913 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07007914 @ViewDebug.ExportedProperty(category = "layout")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007915 public int bottomMargin;
7916
7917 /**
Adam Powella7a735f2014-10-09 12:54:52 -07007918 * The start margin in pixels of the child. Margin values should be positive.
Fabrice Di Meglio54546f22012-02-14 16:26:16 -08007919 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
7920 * to this field.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007921 */
7922 @ViewDebug.ExportedProperty(category = "layout")
Mathew Inwoode5ad5982018-08-17 15:07:52 +01007923 @UnsupportedAppUsage
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07007924 private int startMargin = DEFAULT_MARGIN_RELATIVE;
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007925
7926 /**
Adam Powella7a735f2014-10-09 12:54:52 -07007927 * The end margin in pixels of the child. Margin values should be positive.
Fabrice Di Meglio54546f22012-02-14 16:26:16 -08007928 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
7929 * to this field.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007930 */
7931 @ViewDebug.ExportedProperty(category = "layout")
Mathew Inwoode5ad5982018-08-17 15:07:52 +01007932 @UnsupportedAppUsage
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07007933 private int endMargin = DEFAULT_MARGIN_RELATIVE;
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007934
7935 /**
7936 * The default start and end margin.
Fabrice Di Megliof443f982012-07-13 20:24:03 -07007937 * @hide
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007938 */
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07007939 public static final int DEFAULT_MARGIN_RELATIVE = Integer.MIN_VALUE;
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007940
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007941 /**
7942 * Bit 0: layout direction
7943 * Bit 1: layout direction
7944 * Bit 2: left margin undefined
7945 * Bit 3: right margin undefined
7946 * Bit 4: is RTL compatibility mode
7947 * Bit 5: need resolution
7948 *
7949 * Bit 6 to 7 not used
7950 *
7951 * @hide
7952 */
7953 @ViewDebug.ExportedProperty(category = "layout", flagMapping = {
7954 @ViewDebug.FlagToString(mask = LAYOUT_DIRECTION_MASK,
7955 equals = LAYOUT_DIRECTION_MASK, name = "LAYOUT_DIRECTION"),
7956 @ViewDebug.FlagToString(mask = LEFT_MARGIN_UNDEFINED_MASK,
7957 equals = LEFT_MARGIN_UNDEFINED_MASK, name = "LEFT_MARGIN_UNDEFINED_MASK"),
7958 @ViewDebug.FlagToString(mask = RIGHT_MARGIN_UNDEFINED_MASK,
7959 equals = RIGHT_MARGIN_UNDEFINED_MASK, name = "RIGHT_MARGIN_UNDEFINED_MASK"),
7960 @ViewDebug.FlagToString(mask = RTL_COMPATIBILITY_MODE_MASK,
7961 equals = RTL_COMPATIBILITY_MODE_MASK, name = "RTL_COMPATIBILITY_MODE_MASK"),
7962 @ViewDebug.FlagToString(mask = NEED_RESOLUTION_MASK,
7963 equals = NEED_RESOLUTION_MASK, name = "NEED_RESOLUTION_MASK")
Jon Miranda4597e982014-07-29 07:25:49 -07007964 }, formatToHexString = true)
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007965 byte mMarginFlags;
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07007966
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007967 private static final int LAYOUT_DIRECTION_MASK = 0x00000003;
7968 private static final int LEFT_MARGIN_UNDEFINED_MASK = 0x00000004;
7969 private static final int RIGHT_MARGIN_UNDEFINED_MASK = 0x00000008;
7970 private static final int RTL_COMPATIBILITY_MODE_MASK = 0x00000010;
7971 private static final int NEED_RESOLUTION_MASK = 0x00000020;
Fabrice Di Megliof443f982012-07-13 20:24:03 -07007972
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007973 private static final int DEFAULT_MARGIN_RESOLVED = 0;
7974 private static final int UNDEFINED_MARGIN = DEFAULT_MARGIN_RELATIVE;
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07007975
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007976 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007977 * Creates a new set of layout parameters. The values are extracted from
7978 * the supplied attributes set and context.
7979 *
7980 * @param c the application environment
7981 * @param attrs the set of attributes from which to extract the layout
7982 * parameters' values
7983 */
7984 public MarginLayoutParams(Context c, AttributeSet attrs) {
7985 super();
7986
7987 TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ViewGroup_MarginLayout);
7988 setBaseAttributes(a,
7989 R.styleable.ViewGroup_MarginLayout_layout_width,
7990 R.styleable.ViewGroup_MarginLayout_layout_height);
7991
7992 int margin = a.getDimensionPixelSize(
7993 com.android.internal.R.styleable.ViewGroup_MarginLayout_layout_margin, -1);
7994 if (margin >= 0) {
7995 leftMargin = margin;
7996 topMargin = margin;
7997 rightMargin= margin;
7998 bottomMargin = margin;
7999 } else {
Chet Haase40b2de52016-11-28 16:11:42 -08008000 int horizontalMargin = a.getDimensionPixelSize(
8001 R.styleable.ViewGroup_MarginLayout_layout_marginHorizontal, -1);
8002 int verticalMargin = a.getDimensionPixelSize(
8003 R.styleable.ViewGroup_MarginLayout_layout_marginVertical, -1);
8004
8005 if (horizontalMargin >= 0) {
8006 leftMargin = horizontalMargin;
8007 rightMargin = horizontalMargin;
8008 } else {
8009 leftMargin = a.getDimensionPixelSize(
8010 R.styleable.ViewGroup_MarginLayout_layout_marginLeft,
8011 UNDEFINED_MARGIN);
8012 if (leftMargin == UNDEFINED_MARGIN) {
8013 mMarginFlags |= LEFT_MARGIN_UNDEFINED_MASK;
8014 leftMargin = DEFAULT_MARGIN_RESOLVED;
8015 }
8016 rightMargin = a.getDimensionPixelSize(
8017 R.styleable.ViewGroup_MarginLayout_layout_marginRight,
8018 UNDEFINED_MARGIN);
8019 if (rightMargin == UNDEFINED_MARGIN) {
8020 mMarginFlags |= RIGHT_MARGIN_UNDEFINED_MASK;
8021 rightMargin = DEFAULT_MARGIN_RESOLVED;
8022 }
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07008023 }
8024
Chet Haasecb3d0232017-05-24 18:27:14 -07008025 startMargin = a.getDimensionPixelSize(
8026 R.styleable.ViewGroup_MarginLayout_layout_marginStart,
8027 DEFAULT_MARGIN_RELATIVE);
8028 endMargin = a.getDimensionPixelSize(
8029 R.styleable.ViewGroup_MarginLayout_layout_marginEnd,
8030 DEFAULT_MARGIN_RELATIVE);
8031
Chet Haase40b2de52016-11-28 16:11:42 -08008032 if (verticalMargin >= 0) {
8033 topMargin = verticalMargin;
8034 bottomMargin = verticalMargin;
8035 } else {
8036 topMargin = a.getDimensionPixelSize(
8037 R.styleable.ViewGroup_MarginLayout_layout_marginTop,
8038 DEFAULT_MARGIN_RESOLVED);
8039 bottomMargin = a.getDimensionPixelSize(
8040 R.styleable.ViewGroup_MarginLayout_layout_marginBottom,
8041 DEFAULT_MARGIN_RESOLVED);
8042 }
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07008043
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008044 if (isMarginRelative()) {
8045 mMarginFlags |= NEED_RESOLUTION_MASK;
8046 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008047 }
8048
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07008049 final boolean hasRtlSupport = c.getApplicationInfo().hasRtlSupport();
8050 final int targetSdkVersion = c.getApplicationInfo().targetSdkVersion;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008051 if (targetSdkVersion < JELLY_BEAN_MR1 || !hasRtlSupport) {
8052 mMarginFlags |= RTL_COMPATIBILITY_MODE_MASK;
8053 }
8054
8055 // Layout direction is LTR by default
8056 mMarginFlags |= LAYOUT_DIRECTION_LTR;
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07008057
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008058 a.recycle();
8059 }
8060
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008061 public MarginLayoutParams(int width, int height) {
8062 super(width, height);
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07008063
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008064 mMarginFlags |= LEFT_MARGIN_UNDEFINED_MASK;
8065 mMarginFlags |= RIGHT_MARGIN_UNDEFINED_MASK;
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07008066
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008067 mMarginFlags &= ~NEED_RESOLUTION_MASK;
8068 mMarginFlags &= ~RTL_COMPATIBILITY_MODE_MASK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008069 }
8070
8071 /**
8072 * Copy constructor. Clones the width, height and margin values of the source.
8073 *
8074 * @param source The layout params to copy from.
8075 */
8076 public MarginLayoutParams(MarginLayoutParams source) {
8077 this.width = source.width;
8078 this.height = source.height;
8079
8080 this.leftMargin = source.leftMargin;
8081 this.topMargin = source.topMargin;
8082 this.rightMargin = source.rightMargin;
8083 this.bottomMargin = source.bottomMargin;
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07008084 this.startMargin = source.startMargin;
8085 this.endMargin = source.endMargin;
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07008086
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008087 this.mMarginFlags = source.mMarginFlags;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008088 }
8089
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008090 public MarginLayoutParams(LayoutParams source) {
8091 super(source);
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07008092
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008093 mMarginFlags |= LEFT_MARGIN_UNDEFINED_MASK;
8094 mMarginFlags |= RIGHT_MARGIN_UNDEFINED_MASK;
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07008095
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008096 mMarginFlags &= ~NEED_RESOLUTION_MASK;
8097 mMarginFlags &= ~RTL_COMPATIBILITY_MODE_MASK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008098 }
8099
8100 /**
Adam Powelld7600832014-07-01 15:22:50 -07008101 * @hide Used internally.
8102 */
8103 public final void copyMarginsFrom(MarginLayoutParams source) {
8104 this.leftMargin = source.leftMargin;
8105 this.topMargin = source.topMargin;
8106 this.rightMargin = source.rightMargin;
8107 this.bottomMargin = source.bottomMargin;
8108 this.startMargin = source.startMargin;
8109 this.endMargin = source.endMargin;
8110
8111 this.mMarginFlags = source.mMarginFlags;
8112 }
8113
8114 /**
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07008115 * Sets the margins, in pixels. A call to {@link android.view.View#requestLayout()} needs
8116 * to be done so that the new margins are taken into account. Left and right margins may be
8117 * overriden by {@link android.view.View#requestLayout()} depending on layout direction.
Adam Powella7a735f2014-10-09 12:54:52 -07008118 * Margin values should be positive.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008119 *
8120 * @param left the left margin size
8121 * @param top the top margin size
8122 * @param right the right margin size
8123 * @param bottom the bottom margin size
8124 *
8125 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginLeft
8126 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginTop
8127 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginRight
8128 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginBottom
8129 */
8130 public void setMargins(int left, int top, int right, int bottom) {
8131 leftMargin = left;
8132 topMargin = top;
8133 rightMargin = right;
8134 bottomMargin = bottom;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008135 mMarginFlags &= ~LEFT_MARGIN_UNDEFINED_MASK;
8136 mMarginFlags &= ~RIGHT_MARGIN_UNDEFINED_MASK;
8137 if (isMarginRelative()) {
8138 mMarginFlags |= NEED_RESOLUTION_MASK;
8139 } else {
8140 mMarginFlags &= ~NEED_RESOLUTION_MASK;
8141 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008142 }
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07008143
8144 /**
8145 * Sets the relative margins, in pixels. A call to {@link android.view.View#requestLayout()}
8146 * needs to be done so that the new relative margins are taken into account. Left and right
8147 * margins may be overriden by {@link android.view.View#requestLayout()} depending on layout
Adam Powella7a735f2014-10-09 12:54:52 -07008148 * direction. Margin values should be positive.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07008149 *
8150 * @param start the start margin size
8151 * @param top the top margin size
8152 * @param end the right margin size
8153 * @param bottom the bottom margin size
8154 *
8155 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
8156 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginTop
8157 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
8158 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginBottom
8159 *
8160 * @hide
8161 */
Mathew Inwoode5ad5982018-08-17 15:07:52 +01008162 @UnsupportedAppUsage
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07008163 public void setMarginsRelative(int start, int top, int end, int bottom) {
8164 startMargin = start;
8165 topMargin = top;
8166 endMargin = end;
8167 bottomMargin = bottom;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008168 mMarginFlags |= NEED_RESOLUTION_MASK;
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07008169 }
8170
8171 /**
Adam Powella7a735f2014-10-09 12:54:52 -07008172 * Sets the relative start margin. Margin values should be positive.
Fabrice Di Meglioa40627d2012-09-11 16:47:21 -07008173 *
Fabrice Di Meglio61a21772012-09-12 16:33:13 -07008174 * @param start the start margin size
Fabrice Di Meglioa40627d2012-09-11 16:47:21 -07008175 *
8176 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
8177 */
8178 public void setMarginStart(int start) {
8179 startMargin = start;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008180 mMarginFlags |= NEED_RESOLUTION_MASK;
Fabrice Di Meglioa40627d2012-09-11 16:47:21 -07008181 }
8182
8183 /**
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07008184 * Returns the start margin in pixels.
8185 *
8186 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
8187 *
8188 * @return the start margin in pixels.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07008189 */
8190 public int getMarginStart() {
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07008191 if (startMargin != DEFAULT_MARGIN_RELATIVE) return startMargin;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008192 if ((mMarginFlags & NEED_RESOLUTION_MASK) == NEED_RESOLUTION_MASK) {
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07008193 doResolveMargins();
8194 }
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008195 switch(mMarginFlags & LAYOUT_DIRECTION_MASK) {
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07008196 case View.LAYOUT_DIRECTION_RTL:
8197 return rightMargin;
8198 case View.LAYOUT_DIRECTION_LTR:
8199 default:
8200 return leftMargin;
8201 }
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07008202 }
8203
8204 /**
Adam Powella7a735f2014-10-09 12:54:52 -07008205 * Sets the relative end margin. Margin values should be positive.
Fabrice Di Meglioa40627d2012-09-11 16:47:21 -07008206 *
Fabrice Di Meglio61a21772012-09-12 16:33:13 -07008207 * @param end the end margin size
Fabrice Di Meglioa40627d2012-09-11 16:47:21 -07008208 *
8209 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
8210 */
8211 public void setMarginEnd(int end) {
8212 endMargin = end;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008213 mMarginFlags |= NEED_RESOLUTION_MASK;
Fabrice Di Meglioa40627d2012-09-11 16:47:21 -07008214 }
8215
8216 /**
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07008217 * Returns the end margin in pixels.
8218 *
8219 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
8220 *
8221 * @return the end margin in pixels.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07008222 */
8223 public int getMarginEnd() {
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07008224 if (endMargin != DEFAULT_MARGIN_RELATIVE) return endMargin;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008225 if ((mMarginFlags & NEED_RESOLUTION_MASK) == NEED_RESOLUTION_MASK) {
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07008226 doResolveMargins();
8227 }
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008228 switch(mMarginFlags & LAYOUT_DIRECTION_MASK) {
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07008229 case View.LAYOUT_DIRECTION_RTL:
8230 return leftMargin;
8231 case View.LAYOUT_DIRECTION_LTR:
8232 default:
8233 return rightMargin;
8234 }
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07008235 }
8236
8237 /**
8238 * Check if margins are relative.
8239 *
8240 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
8241 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
8242 *
Fabrice Di Megliof443f982012-07-13 20:24:03 -07008243 * @return true if either marginStart or marginEnd has been set.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07008244 */
8245 public boolean isMarginRelative() {
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07008246 return (startMargin != DEFAULT_MARGIN_RELATIVE || endMargin != DEFAULT_MARGIN_RELATIVE);
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07008247 }
8248
8249 /**
Fabrice Di Megliof443f982012-07-13 20:24:03 -07008250 * Set the layout direction
8251 * @param layoutDirection the layout direction.
8252 * Should be either {@link View#LAYOUT_DIRECTION_LTR}
8253 * or {@link View#LAYOUT_DIRECTION_RTL}.
8254 */
8255 public void setLayoutDirection(int layoutDirection) {
8256 if (layoutDirection != View.LAYOUT_DIRECTION_LTR &&
8257 layoutDirection != View.LAYOUT_DIRECTION_RTL) return;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008258 if (layoutDirection != (mMarginFlags & LAYOUT_DIRECTION_MASK)) {
8259 mMarginFlags &= ~LAYOUT_DIRECTION_MASK;
8260 mMarginFlags |= (layoutDirection & LAYOUT_DIRECTION_MASK);
8261 if (isMarginRelative()) {
8262 mMarginFlags |= NEED_RESOLUTION_MASK;
8263 } else {
8264 mMarginFlags &= ~NEED_RESOLUTION_MASK;
8265 }
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07008266 }
Fabrice Di Megliof443f982012-07-13 20:24:03 -07008267 }
8268
8269 /**
8270 * Retuns the layout direction. Can be either {@link View#LAYOUT_DIRECTION_LTR} or
8271 * {@link View#LAYOUT_DIRECTION_RTL}.
8272 *
8273 * @return the layout direction.
8274 */
8275 public int getLayoutDirection() {
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008276 return (mMarginFlags & LAYOUT_DIRECTION_MASK);
Fabrice Di Megliof443f982012-07-13 20:24:03 -07008277 }
8278
8279 /**
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07008280 * This will be called by {@link android.view.View#requestLayout()}. Left and Right margins
Fabrice Di Meglio98aec1c2012-02-13 16:54:05 -08008281 * may be overridden depending on layout direction.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07008282 */
8283 @Override
Fabrice Di Meglio2918ab62012-10-10 16:39:25 -07008284 public void resolveLayoutDirection(int layoutDirection) {
Fabrice Di Megliof443f982012-07-13 20:24:03 -07008285 setLayoutDirection(layoutDirection);
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07008286
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07008287 // No relative margin or pre JB-MR1 case or no need to resolve, just dont do anything
8288 // Will use the left and right margins if no relative margin is defined.
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008289 if (!isMarginRelative() ||
8290 (mMarginFlags & NEED_RESOLUTION_MASK) != NEED_RESOLUTION_MASK) return;
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07008291
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07008292 // Proceed with resolution
8293 doResolveMargins();
8294 }
8295
8296 private void doResolveMargins() {
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008297 if ((mMarginFlags & RTL_COMPATIBILITY_MODE_MASK) == RTL_COMPATIBILITY_MODE_MASK) {
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07008298 // if left or right margins are not defined and if we have some start or end margin
8299 // defined then use those start and end margins.
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008300 if ((mMarginFlags & LEFT_MARGIN_UNDEFINED_MASK) == LEFT_MARGIN_UNDEFINED_MASK
8301 && startMargin > DEFAULT_MARGIN_RELATIVE) {
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07008302 leftMargin = startMargin;
8303 }
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008304 if ((mMarginFlags & RIGHT_MARGIN_UNDEFINED_MASK) == RIGHT_MARGIN_UNDEFINED_MASK
8305 && endMargin > DEFAULT_MARGIN_RELATIVE) {
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07008306 rightMargin = endMargin;
8307 }
8308 } else {
8309 // We have some relative margins (either the start one or the end one or both). So use
8310 // them and override what has been defined for left and right margins. If either start
8311 // or end margin is not defined, just set it to default "0".
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008312 switch(mMarginFlags & LAYOUT_DIRECTION_MASK) {
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07008313 case View.LAYOUT_DIRECTION_RTL:
8314 leftMargin = (endMargin > DEFAULT_MARGIN_RELATIVE) ?
8315 endMargin : DEFAULT_MARGIN_RESOLVED;
8316 rightMargin = (startMargin > DEFAULT_MARGIN_RELATIVE) ?
8317 startMargin : DEFAULT_MARGIN_RESOLVED;
8318 break;
8319 case View.LAYOUT_DIRECTION_LTR:
8320 default:
8321 leftMargin = (startMargin > DEFAULT_MARGIN_RELATIVE) ?
8322 startMargin : DEFAULT_MARGIN_RESOLVED;
8323 rightMargin = (endMargin > DEFAULT_MARGIN_RELATIVE) ?
8324 endMargin : DEFAULT_MARGIN_RESOLVED;
8325 break;
8326 }
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07008327 }
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008328 mMarginFlags &= ~NEED_RESOLUTION_MASK;
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07008329 }
Philip Milne10ca24a2012-04-23 15:38:27 -07008330
Fabrice Di Meglio03b8d3a2012-09-27 17:05:27 -07008331 /**
8332 * @hide
8333 */
8334 public boolean isLayoutRtl() {
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008335 return ((mMarginFlags & LAYOUT_DIRECTION_MASK) == View.LAYOUT_DIRECTION_RTL);
Fabrice Di Megliof443f982012-07-13 20:24:03 -07008336 }
8337
Alan Viverette2d7771c2018-01-31 17:04:31 -05008338 /**
8339 * @hide
8340 */
Philip Milne10ca24a2012-04-23 15:38:27 -07008341 @Override
Philip Milne7b757812012-09-19 18:13:44 -07008342 public void onDebugDraw(View view, Canvas canvas, Paint paint) {
8343 Insets oi = isLayoutModeOptical(view.mParent) ? view.getOpticalInsets() : Insets.NONE;
8344
8345 fillDifference(canvas,
8346 view.getLeft() + oi.left,
8347 view.getTop() + oi.top,
8348 view.getRight() - oi.right,
8349 view.getBottom() - oi.bottom,
8350 leftMargin,
8351 topMargin,
8352 rightMargin,
8353 bottomMargin,
8354 paint);
Philip Milne10ca24a2012-04-23 15:38:27 -07008355 }
Siva Velusamy0d857b92015-04-22 10:23:56 -07008356
8357 /** @hide */
8358 @Override
8359 protected void encodeProperties(@NonNull ViewHierarchyEncoder encoder) {
8360 super.encodeProperties(encoder);
8361 encoder.addProperty("leftMargin", leftMargin);
8362 encoder.addProperty("topMargin", topMargin);
8363 encoder.addProperty("rightMargin", rightMargin);
8364 encoder.addProperty("bottomMargin", bottomMargin);
8365 encoder.addProperty("startMargin", startMargin);
8366 encoder.addProperty("endMargin", endMargin);
8367 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008368 }
Adam Powell2b342f02010-08-18 18:14:13 -07008369
Jeff Brown20e987b2010-08-23 12:01:02 -07008370 /* Describes a touched view and the ids of the pointers that it has captured.
8371 *
8372 * This code assumes that pointer ids are always in the range 0..31 such that
8373 * it can use a bitfield to track which pointer ids are present.
8374 * As it happens, the lower layers of the input dispatch pipeline also use the
8375 * same trick so the assumption should be safe here...
8376 */
8377 private static final class TouchTarget {
8378 private static final int MAX_RECYCLED = 32;
Romain Guy6410c0a2013-06-17 11:21:58 -07008379 private static final Object sRecycleLock = new Object[0];
Jeff Brown20e987b2010-08-23 12:01:02 -07008380 private static TouchTarget sRecycleBin;
8381 private static int sRecycledCount;
Adam Powell2b342f02010-08-18 18:14:13 -07008382
Jeff Brown20e987b2010-08-23 12:01:02 -07008383 public static final int ALL_POINTER_IDS = -1; // all ones
Adam Powell2b342f02010-08-18 18:14:13 -07008384
Jeff Brown20e987b2010-08-23 12:01:02 -07008385 // The touched child view.
Mathew Inwoode5ad5982018-08-17 15:07:52 +01008386 @UnsupportedAppUsage
Jeff Brown20e987b2010-08-23 12:01:02 -07008387 public View child;
8388
8389 // The combined bit mask of pointer ids for all pointers captured by the target.
8390 public int pointerIdBits;
8391
8392 // The next target in the target list.
8393 public TouchTarget next;
8394
Mathew Inwoode5ad5982018-08-17 15:07:52 +01008395 @UnsupportedAppUsage
Jeff Brown20e987b2010-08-23 12:01:02 -07008396 private TouchTarget() {
Adam Powell2b342f02010-08-18 18:14:13 -07008397 }
8398
Alan Viverettea7b85e62016-01-22 10:14:02 -05008399 public static TouchTarget obtain(@NonNull View child, int pointerIdBits) {
8400 if (child == null) {
8401 throw new IllegalArgumentException("child must be non-null");
8402 }
8403
Jeff Brown20e987b2010-08-23 12:01:02 -07008404 final TouchTarget target;
8405 synchronized (sRecycleLock) {
Adam Powell816c3be2010-08-23 18:00:05 -07008406 if (sRecycleBin == null) {
Jeff Brown20e987b2010-08-23 12:01:02 -07008407 target = new TouchTarget();
Adam Powell816c3be2010-08-23 18:00:05 -07008408 } else {
Jeff Brown20e987b2010-08-23 12:01:02 -07008409 target = sRecycleBin;
8410 sRecycleBin = target.next;
8411 sRecycledCount--;
8412 target.next = null;
Adam Powell816c3be2010-08-23 18:00:05 -07008413 }
Adam Powell816c3be2010-08-23 18:00:05 -07008414 }
Jeff Brown20e987b2010-08-23 12:01:02 -07008415 target.child = child;
8416 target.pointerIdBits = pointerIdBits;
8417 return target;
8418 }
Adam Powell816c3be2010-08-23 18:00:05 -07008419
Jeff Brown20e987b2010-08-23 12:01:02 -07008420 public void recycle() {
Alan Viverettea7b85e62016-01-22 10:14:02 -05008421 if (child == null) {
8422 throw new IllegalStateException("already recycled once");
8423 }
8424
Jeff Brown20e987b2010-08-23 12:01:02 -07008425 synchronized (sRecycleLock) {
8426 if (sRecycledCount < MAX_RECYCLED) {
8427 next = sRecycleBin;
8428 sRecycleBin = this;
8429 sRecycledCount += 1;
Patrick Dubroyfb0547d22010-10-19 17:36:18 -07008430 } else {
8431 next = null;
Adam Powell816c3be2010-08-23 18:00:05 -07008432 }
Patrick Dubroyfb0547d22010-10-19 17:36:18 -07008433 child = null;
Adam Powell816c3be2010-08-23 18:00:05 -07008434 }
8435 }
Adam Powell2b342f02010-08-18 18:14:13 -07008436 }
Jeff Brown87b7f802011-06-21 18:35:45 -07008437
8438 /* Describes a hovered view. */
8439 private static final class HoverTarget {
8440 private static final int MAX_RECYCLED = 32;
Romain Guy6410c0a2013-06-17 11:21:58 -07008441 private static final Object sRecycleLock = new Object[0];
Jeff Brown87b7f802011-06-21 18:35:45 -07008442 private static HoverTarget sRecycleBin;
8443 private static int sRecycledCount;
8444
8445 // The hovered child view.
8446 public View child;
8447
8448 // The next target in the target list.
8449 public HoverTarget next;
8450
8451 private HoverTarget() {
8452 }
8453
Alan Viverettea7b85e62016-01-22 10:14:02 -05008454 public static HoverTarget obtain(@NonNull View child) {
8455 if (child == null) {
8456 throw new IllegalArgumentException("child must be non-null");
8457 }
8458
Jeff Brown87b7f802011-06-21 18:35:45 -07008459 final HoverTarget target;
8460 synchronized (sRecycleLock) {
8461 if (sRecycleBin == null) {
8462 target = new HoverTarget();
8463 } else {
8464 target = sRecycleBin;
8465 sRecycleBin = target.next;
Alan Viverettea7b85e62016-01-22 10:14:02 -05008466 sRecycledCount--;
Jeff Brown87b7f802011-06-21 18:35:45 -07008467 target.next = null;
8468 }
8469 }
8470 target.child = child;
8471 return target;
8472 }
8473
8474 public void recycle() {
Alan Viverettea7b85e62016-01-22 10:14:02 -05008475 if (child == null) {
8476 throw new IllegalStateException("already recycled once");
8477 }
8478
Jeff Brown87b7f802011-06-21 18:35:45 -07008479 synchronized (sRecycleLock) {
8480 if (sRecycledCount < MAX_RECYCLED) {
8481 next = sRecycleBin;
8482 sRecycleBin = this;
8483 sRecycledCount += 1;
8484 } else {
8485 next = null;
8486 }
8487 child = null;
8488 }
8489 }
8490 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07008491
8492 /**
Svet Ganov2f8fb1f2017-03-13 00:21:04 -07008493 * Pooled class that to hold the children for autifill.
8494 */
8495 static class ChildListForAutoFill extends ArrayList<View> {
8496 private static final int MAX_POOL_SIZE = 32;
8497
8498 private static final Pools.SimplePool<ChildListForAutoFill> sPool =
8499 new Pools.SimplePool<>(MAX_POOL_SIZE);
8500
8501 public static ChildListForAutoFill obtain() {
8502 ChildListForAutoFill list = sPool.acquire();
8503 if (list == null) {
8504 list = new ChildListForAutoFill();
8505 }
8506 return list;
8507 }
8508
8509 public void recycle() {
8510 clear();
8511 sPool.release(this);
8512 }
8513 }
8514
8515 /**
Svetoslav Ganov42138042012-03-20 11:51:39 -07008516 * Pooled class that orderes the children of a ViewGroup from start
8517 * to end based on how they are laid out and the layout direction.
8518 */
8519 static class ChildListForAccessibility {
8520
8521 private static final int MAX_POOL_SIZE = 32;
8522
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08008523 private static final SynchronizedPool<ChildListForAccessibility> sPool =
8524 new SynchronizedPool<ChildListForAccessibility>(MAX_POOL_SIZE);
Svetoslav Ganov42138042012-03-20 11:51:39 -07008525
8526 private final ArrayList<View> mChildren = new ArrayList<View>();
8527
8528 private final ArrayList<ViewLocationHolder> mHolders = new ArrayList<ViewLocationHolder>();
8529
8530 public static ChildListForAccessibility obtain(ViewGroup parent, boolean sort) {
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08008531 ChildListForAccessibility list = sPool.acquire();
8532 if (list == null) {
8533 list = new ChildListForAccessibility();
Svetoslav Ganov42138042012-03-20 11:51:39 -07008534 }
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08008535 list.init(parent, sort);
8536 return list;
Svetoslav Ganov42138042012-03-20 11:51:39 -07008537 }
8538
8539 public void recycle() {
Svetoslav Ganov42138042012-03-20 11:51:39 -07008540 clear();
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08008541 sPool.release(this);
Svetoslav Ganov42138042012-03-20 11:51:39 -07008542 }
8543
8544 public int getChildCount() {
8545 return mChildren.size();
8546 }
8547
8548 public View getChildAt(int index) {
8549 return mChildren.get(index);
8550 }
8551
Svetoslav Ganov42138042012-03-20 11:51:39 -07008552 private void init(ViewGroup parent, boolean sort) {
8553 ArrayList<View> children = mChildren;
8554 final int childCount = parent.getChildCount();
8555 for (int i = 0; i < childCount; i++) {
8556 View child = parent.getChildAt(i);
8557 children.add(child);
8558 }
8559 if (sort) {
8560 ArrayList<ViewLocationHolder> holders = mHolders;
8561 for (int i = 0; i < childCount; i++) {
8562 View child = children.get(i);
8563 ViewLocationHolder holder = ViewLocationHolder.obtain(parent, child);
8564 holders.add(holder);
8565 }
Svetoslav88e447b2014-10-09 15:49:02 -07008566 sort(holders);
Svetoslav Ganov42138042012-03-20 11:51:39 -07008567 for (int i = 0; i < childCount; i++) {
8568 ViewLocationHolder holder = holders.get(i);
8569 children.set(i, holder.mView);
8570 holder.recycle();
8571 }
8572 holders.clear();
8573 }
8574 }
8575
Svetoslav88e447b2014-10-09 15:49:02 -07008576 private void sort(ArrayList<ViewLocationHolder> holders) {
8577 // This is gross but the least risky solution. The current comparison
8578 // strategy breaks transitivity but produces very good results. Coming
8579 // up with a new strategy requires time which we do not have, so ...
8580 try {
8581 ViewLocationHolder.setComparisonStrategy(
8582 ViewLocationHolder.COMPARISON_STRATEGY_STRIPE);
8583 Collections.sort(holders);
8584 } catch (IllegalArgumentException iae) {
8585 // Note that in practice this occurs extremely rarely in a couple
8586 // of pathological cases.
8587 ViewLocationHolder.setComparisonStrategy(
8588 ViewLocationHolder.COMPARISON_STRATEGY_LOCATION);
8589 Collections.sort(holders);
8590 }
8591 }
8592
Svetoslav Ganov42138042012-03-20 11:51:39 -07008593 private void clear() {
8594 mChildren.clear();
8595 }
8596 }
8597
8598 /**
8599 * Pooled class that holds a View and its location with respect to
8600 * a specified root. This enables sorting of views based on their
8601 * coordinates without recomputing the position relative to the root
8602 * on every comparison.
8603 */
8604 static class ViewLocationHolder implements Comparable<ViewLocationHolder> {
8605
8606 private static final int MAX_POOL_SIZE = 32;
8607
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08008608 private static final SynchronizedPool<ViewLocationHolder> sPool =
8609 new SynchronizedPool<ViewLocationHolder>(MAX_POOL_SIZE);
Svetoslav Ganov42138042012-03-20 11:51:39 -07008610
Svetoslav88e447b2014-10-09 15:49:02 -07008611 public static final int COMPARISON_STRATEGY_STRIPE = 1;
8612
8613 public static final int COMPARISON_STRATEGY_LOCATION = 2;
8614
8615 private static int sComparisonStrategy = COMPARISON_STRATEGY_STRIPE;
8616
Svetoslav Ganov42138042012-03-20 11:51:39 -07008617 private final Rect mLocation = new Rect();
8618
Phil Weaver86b32602018-05-10 18:00:18 -07008619 private ViewGroup mRoot;
8620
Svetoslav Ganov42138042012-03-20 11:51:39 -07008621 public View mView;
8622
8623 private int mLayoutDirection;
8624
8625 public static ViewLocationHolder obtain(ViewGroup root, View view) {
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08008626 ViewLocationHolder holder = sPool.acquire();
8627 if (holder == null) {
8628 holder = new ViewLocationHolder();
Svetoslav Ganov42138042012-03-20 11:51:39 -07008629 }
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08008630 holder.init(root, view);
8631 return holder;
Svetoslav Ganov42138042012-03-20 11:51:39 -07008632 }
8633
Svetoslav88e447b2014-10-09 15:49:02 -07008634 public static void setComparisonStrategy(int strategy) {
8635 sComparisonStrategy = strategy;
8636 }
8637
Svetoslav Ganov42138042012-03-20 11:51:39 -07008638 public void recycle() {
Svetoslav Ganov42138042012-03-20 11:51:39 -07008639 clear();
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08008640 sPool.release(this);
Svetoslav Ganov42138042012-03-20 11:51:39 -07008641 }
8642
8643 @Override
8644 public int compareTo(ViewLocationHolder another) {
8645 // This instance is greater than an invalid argument.
8646 if (another == null) {
8647 return 1;
8648 }
Svetoslav88e447b2014-10-09 15:49:02 -07008649
Phil Weaver86b32602018-05-10 18:00:18 -07008650 int boundsResult = compareBoundsOfTree(this, another);
8651 if (boundsResult != 0) {
8652 return boundsResult;
8653 }
8654
8655 // Just break the tie somehow. The accessibility ids are unique
8656 // and stable, hence this is deterministic tie breaking.
8657 return mView.getAccessibilityViewId() - another.mView.getAccessibilityViewId();
8658 }
8659
8660 /**
8661 * Compare two views based on their bounds. Use the bounds of their children to break ties.
8662 *
8663 * @param holder1 Holder of first view to compare
8664 * @param holder2 Holder of second view to compare. Must have the same root at holder1.
8665 * @return The compare result, with equality if no good comparison was found.
8666 */
8667 private static int compareBoundsOfTree(
8668 ViewLocationHolder holder1, ViewLocationHolder holder2) {
Svetoslav88e447b2014-10-09 15:49:02 -07008669 if (sComparisonStrategy == COMPARISON_STRATEGY_STRIPE) {
8670 // First is above second.
Phil Weaver86b32602018-05-10 18:00:18 -07008671 if (holder1.mLocation.bottom - holder2.mLocation.top <= 0) {
Svetoslav88e447b2014-10-09 15:49:02 -07008672 return -1;
8673 }
8674 // First is below second.
Phil Weaver86b32602018-05-10 18:00:18 -07008675 if (holder1.mLocation.top - holder2.mLocation.bottom >= 0) {
Svetoslav88e447b2014-10-09 15:49:02 -07008676 return 1;
8677 }
8678 }
8679
Svetoslav04cab1b2014-08-25 18:35:57 -07008680 // We are ordering left-to-right, top-to-bottom.
Phil Weaver86b32602018-05-10 18:00:18 -07008681 if (holder1.mLayoutDirection == LAYOUT_DIRECTION_LTR) {
8682 final int leftDifference = holder1.mLocation.left - holder2.mLocation.left;
Svetoslav Ganov42138042012-03-20 11:51:39 -07008683 if (leftDifference != 0) {
8684 return leftDifference;
8685 }
8686 } else { // RTL
Phil Weaver86b32602018-05-10 18:00:18 -07008687 final int rightDifference = holder1.mLocation.right - holder2.mLocation.right;
Svetoslav Ganov42138042012-03-20 11:51:39 -07008688 if (rightDifference != 0) {
8689 return -rightDifference;
8690 }
8691 }
Svetoslav04cab1b2014-08-25 18:35:57 -07008692 // We are ordering left-to-right, top-to-bottom.
Phil Weaver86b32602018-05-10 18:00:18 -07008693 final int topDifference = holder1.mLocation.top - holder2.mLocation.top;
Svetoslav04cab1b2014-08-25 18:35:57 -07008694 if (topDifference != 0) {
8695 return topDifference;
8696 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07008697 // Break tie by height.
Phil Weaver86b32602018-05-10 18:00:18 -07008698 final int heightDiference = holder1.mLocation.height() - holder2.mLocation.height();
Svetoslav Ganov42138042012-03-20 11:51:39 -07008699 if (heightDiference != 0) {
8700 return -heightDiference;
8701 }
8702 // Break tie by width.
Phil Weaver86b32602018-05-10 18:00:18 -07008703 final int widthDifference = holder1.mLocation.width() - holder2.mLocation.width();
8704 if (widthDifference != 0) {
8705 return -widthDifference;
Svetoslav Ganov42138042012-03-20 11:51:39 -07008706 }
Phil Weaver86b32602018-05-10 18:00:18 -07008707
8708 // Find a child of each view with different screen bounds.
8709 final Rect view1Bounds = new Rect();
8710 final Rect view2Bounds = new Rect();
8711 final Rect tempRect = new Rect();
8712 holder1.mView.getBoundsOnScreen(view1Bounds, true);
8713 holder2.mView.getBoundsOnScreen(view2Bounds, true);
8714 final View child1 = holder1.mView.findViewByPredicateTraversal((view) -> {
8715 view.getBoundsOnScreen(tempRect, true);
8716 return !tempRect.equals(view1Bounds);
8717 }, null);
8718 final View child2 = holder2.mView.findViewByPredicateTraversal((view) -> {
8719 view.getBoundsOnScreen(tempRect, true);
8720 return !tempRect.equals(view2Bounds);
8721 }, null);
8722
8723
8724 // Compare the children recursively
8725 if ((child1 != null) && (child2 != null)) {
8726 final ViewLocationHolder childHolder1 =
8727 ViewLocationHolder.obtain(holder1.mRoot, child1);
8728 final ViewLocationHolder childHolder2 =
8729 ViewLocationHolder.obtain(holder1.mRoot, child2);
8730 return compareBoundsOfTree(childHolder1, childHolder2);
8731 }
8732
8733 // If only one has a child, use that one
8734 if (child1 != null) {
8735 return 1;
8736 }
8737
8738 if (child2 != null) {
8739 return -1;
8740 }
8741
8742 // Give up
8743 return 0;
Svetoslav Ganov42138042012-03-20 11:51:39 -07008744 }
8745
8746 private void init(ViewGroup root, View view) {
8747 Rect viewLocation = mLocation;
8748 view.getDrawingRect(viewLocation);
8749 root.offsetDescendantRectToMyCoords(view, viewLocation);
8750 mView = view;
Phil Weaver86b32602018-05-10 18:00:18 -07008751 mRoot = root;
Fabrice Di Meglioe56ffdc2012-09-23 14:51:16 -07008752 mLayoutDirection = root.getLayoutDirection();
Svetoslav Ganov42138042012-03-20 11:51:39 -07008753 }
8754
8755 private void clear() {
8756 mView = null;
8757 mLocation.set(0, 0, 0, 0);
8758 }
8759 }
Romain Guycbc67742012-04-27 16:12:57 -07008760
Romain Guy6410c0a2013-06-17 11:21:58 -07008761 private static void drawRect(Canvas canvas, Paint paint, int x1, int y1, int x2, int y2) {
Romain Guycbc67742012-04-27 16:12:57 -07008762 if (sDebugLines== null) {
Romain Guy6410c0a2013-06-17 11:21:58 -07008763 // TODO: This won't work with multiple UI threads in a single process
Romain Guycbc67742012-04-27 16:12:57 -07008764 sDebugLines = new float[16];
8765 }
8766
Romain Guycbc67742012-04-27 16:12:57 -07008767 sDebugLines[0] = x1;
8768 sDebugLines[1] = y1;
8769 sDebugLines[2] = x2;
8770 sDebugLines[3] = y1;
8771
8772 sDebugLines[4] = x2;
8773 sDebugLines[5] = y1;
8774 sDebugLines[6] = x2;
Philip Milne7b757812012-09-19 18:13:44 -07008775 sDebugLines[7] = y2;
Romain Guycbc67742012-04-27 16:12:57 -07008776
Philip Milne7b757812012-09-19 18:13:44 -07008777 sDebugLines[8] = x2;
Romain Guycbc67742012-04-27 16:12:57 -07008778 sDebugLines[9] = y2;
8779 sDebugLines[10] = x1;
8780 sDebugLines[11] = y2;
8781
Philip Milne7b757812012-09-19 18:13:44 -07008782 sDebugLines[12] = x1;
8783 sDebugLines[13] = y2;
Romain Guycbc67742012-04-27 16:12:57 -07008784 sDebugLines[14] = x1;
8785 sDebugLines[15] = y1;
8786
Philip Milne7b757812012-09-19 18:13:44 -07008787 canvas.drawLines(sDebugLines, paint);
Romain Guycbc67742012-04-27 16:12:57 -07008788 }
Siva Velusamy0d857b92015-04-22 10:23:56 -07008789
8790 /** @hide */
8791 @Override
Mathew Inwoode5ad5982018-08-17 15:07:52 +01008792 @UnsupportedAppUsage
Siva Velusamy0d857b92015-04-22 10:23:56 -07008793 protected void encodeProperties(@NonNull ViewHierarchyEncoder encoder) {
8794 super.encodeProperties(encoder);
8795
8796 encoder.addProperty("focus:descendantFocusability", getDescendantFocusability());
8797 encoder.addProperty("drawing:clipChildren", getClipChildren());
8798 encoder.addProperty("drawing:clipToPadding", getClipToPadding());
8799 encoder.addProperty("drawing:childrenDrawingOrderEnabled", isChildrenDrawingOrderEnabled());
8800 encoder.addProperty("drawing:persistentDrawingCache", getPersistentDrawingCache());
8801
8802 int n = getChildCount();
8803 encoder.addProperty("meta:__childCount__", (short)n);
8804 for (int i = 0; i < n; i++) {
8805 encoder.addPropertyKey("meta:__child__" + i);
8806 getChildAt(i).encode(encoder);
8807 }
8808 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008809}