blob: 4dc20d4fad6dd1ecf06cf252de0c893b18d1a33e [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 Inwooda570dee2018-08-17 14:56:00 +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;
Jorim Jaggi02a741f2018-12-12 17:40:19 -080054import android.view.WindowInsetsAnimationListener.InsetsAnimation;
svetoslavganov75986cf2009-05-14 22:28:01 -070055import android.view.accessibility.AccessibilityEvent;
Phil Weaver4d3eec412016-09-01 16:28:34 -070056import android.view.accessibility.AccessibilityManager;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070057import android.view.accessibility.AccessibilityNodeInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058import android.view.animation.Animation;
59import android.view.animation.AnimationUtils;
60import android.view.animation.LayoutAnimationController;
61import android.view.animation.Transformation;
Felipe Lemefe05a522018-01-23 15:57:49 -080062import android.view.autofill.Helper;
Ashley Rose55f9f922019-01-28 19:29:36 -050063import android.view.inspector.InspectableProperty;
64import android.view.inspector.InspectableProperty.EnumMap;
Chet Haasecb3d0232017-05-24 18:27:14 -070065
Romain Guy0211a0a2011-02-14 16:34:59 -080066import com.android.internal.R;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080067
68import java.util.ArrayList;
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -080069import java.util.Collection;
Svetoslav Ganov42138042012-03-20 11:51:39 -070070import java.util.Collections;
Christopher Tate86cab1b2011-01-13 20:28:55 -080071import java.util.HashSet;
George Mounte1803372014-02-26 19:00:52 +000072import java.util.List;
73import java.util.Map;
Paul Duffinca4964c2017-02-07 15:04:10 +000074import java.util.function.Predicate;
Keisuke Kuroyanagid85bc502016-01-21 14:50:38 +090075
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080076/**
77 * <p>
78 * A <code>ViewGroup</code> is a special view that can contain other views
79 * (called children.) The view group is the base class for layouts and views
80 * containers. This class also defines the
81 * {@link android.view.ViewGroup.LayoutParams} class which serves as the base
82 * class for layouts parameters.
83 * </p>
84 *
85 * <p>
86 * Also see {@link LayoutParams} for layout attributes.
87 * </p>
Romain Guyd6a463a2009-05-21 23:10:10 -070088 *
Joe Fernandez558459f2011-10-13 16:47:36 -070089 * <div class="special reference">
90 * <h3>Developer Guides</h3>
91 * <p>For more information about creating user interface layouts, read the
92 * <a href="{@docRoot}guide/topics/ui/declaring-layout.html">XML Layouts</a> developer
93 * guide.</p></div>
94 *
Dianne Hackborn7caab0f2013-03-06 13:47:04 -080095 * <p>Here is a complete implementation of a custom ViewGroup that implements
96 * a simple {@link android.widget.FrameLayout} along with the ability to stack
97 * children in left and right gutters.</p>
98 *
99 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/CustomLayout.java
100 * Complete}
101 *
102 * <p>If you are implementing XML layout attributes as shown in the example, this is the
103 * corresponding definition for them that would go in <code>res/values/attrs.xml</code>:</p>
104 *
105 * {@sample development/samples/ApiDemos/res/values/attrs.xml CustomLayout}
106 *
107 * <p>Finally the layout manager can be used in an XML layout like so:</p>
108 *
109 * {@sample development/samples/ApiDemos/res/layout/custom_layout.xml Complete}
110 *
Romain Guyd6a463a2009-05-21 23:10:10 -0700111 * @attr ref android.R.styleable#ViewGroup_clipChildren
112 * @attr ref android.R.styleable#ViewGroup_clipToPadding
113 * @attr ref android.R.styleable#ViewGroup_layoutAnimation
114 * @attr ref android.R.styleable#ViewGroup_animationCache
115 * @attr ref android.R.styleable#ViewGroup_persistentDrawingCache
116 * @attr ref android.R.styleable#ViewGroup_alwaysDrawnWithCache
117 * @attr ref android.R.styleable#ViewGroup_addStatesFromChildren
118 * @attr ref android.R.styleable#ViewGroup_descendantFocusability
Chet Haase13cc1202010-09-03 15:39:20 -0700119 * @attr ref android.R.styleable#ViewGroup_animateLayoutChanges
Scott Main27a85082013-06-10 10:39:48 -0700120 * @attr ref android.R.styleable#ViewGroup_splitMotionEvents
121 * @attr ref android.R.styleable#ViewGroup_layoutMode
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800122 */
Tor Norbye83c68962015-03-10 20:55:31 -0700123@UiThread
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800124public abstract class ViewGroup extends View implements ViewParent, ViewManager {
Adam Powell539ee872012-02-03 19:00:49 -0800125 private static final String TAG = "ViewGroup";
Chet Haase21cd1382010-09-01 17:42:29 -0700126
Mathew Inwooda570dee2018-08-17 14:56:00 +0100127 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800128 private static final boolean DBG = false;
Gilles Debunnecea45132011-11-24 02:19:27 +0100129
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800130 /**
131 * Views which have been hidden or removed which need to be animated on
132 * their way out.
133 * This field should be made private, so it is hidden from the SDK.
134 * {@hide}
135 */
Mathew Inwooda570dee2018-08-17 14:56:00 +0100136 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800137 protected ArrayList<View> mDisappearingChildren;
138
139 /**
140 * Listener used to propagate events indicating when children are added
141 * and/or removed from a view group.
142 * This field should be made private, so it is hidden from the SDK.
143 * {@hide}
144 */
Mathew Inwooda570dee2018-08-17 14:56:00 +0100145 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800146 protected OnHierarchyChangeListener mOnHierarchyChangeListener;
147
148 // The view contained within this ViewGroup that has or contains focus.
Mathew Inwood31755f92018-12-20 13:53:36 +0000149 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800150 private View mFocused;
Vadim Tryshev5ca73982017-01-04 17:24:43 -0800151 // The view contained within this ViewGroup (excluding nested keyboard navigation clusters)
152 // that is or contains a default-focus view.
153 private View mDefaultFocus;
Evan Rosky53fcf112017-01-26 14:37:55 -0800154 // The last child of this ViewGroup which held focus within the current cluster
Evan Rosky6c286be2017-04-19 17:23:32 -0700155 View mFocusedInCluster;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800156
Chet Haase48460322010-06-11 14:22:25 -0700157 /**
158 * A Transformation used when drawing children, to
159 * apply on the child being drawn.
160 */
Romain Guyf6991302013-06-05 17:19:01 -0700161 private Transformation mChildTransformation;
Chet Haase48460322010-06-11 14:22:25 -0700162
163 /**
164 * Used to track the current invalidation region.
165 */
Chet Haase64a48c12012-02-13 16:33:29 -0800166 RectF mInvalidateRegion;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800167
Chet Haase48460322010-06-11 14:22:25 -0700168 /**
169 * A Transformation used to calculate a correct
170 * invalidation area when the application is autoscaled.
171 */
Chet Haase64a48c12012-02-13 16:33:29 -0800172 Transformation mInvalidationTransformation;
Chet Haase48460322010-06-11 14:22:25 -0700173
Vadim Tryshevef128112016-09-16 14:05:53 -0700174 // Current frontmost child that can accept drag and lies under the drag location.
175 // Used only to generate ENTER/EXIT events for pre-Nougat aps.
176 private View mCurrentDragChild;
177
Christopher Tate86cab1b2011-01-13 20:28:55 -0800178 // Metadata about the ongoing drag
Vadim Tryshev1a68dc92015-07-20 17:01:50 -0700179 private DragEvent mCurrentDragStartEvent;
180 private boolean mIsInterestedInDrag;
181 private HashSet<View> mChildrenInterestedInDrag;
Christopher Tatea53146c2010-09-07 11:57:52 -0700182
183 // Used during drag dispatch
Romain Guy6410c0a2013-06-17 11:21:58 -0700184 private PointF mLocalPoint;
Christopher Tatea53146c2010-09-07 11:57:52 -0700185
Alan Viveretteb942b6f2014-12-08 10:37:39 -0800186 // Lazily-created holder for point computations.
187 private float[] mTempPoint;
188
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800189 // Layout animation
190 private LayoutAnimationController mLayoutAnimationController;
191 private Animation.AnimationListener mAnimationListener;
192
Jeff Brown20e987b2010-08-23 12:01:02 -0700193 // First touch target in the linked list of touch targets.
Mathew Inwooda570dee2018-08-17 14:56:00 +0100194 @UnsupportedAppUsage
Jeff Brown20e987b2010-08-23 12:01:02 -0700195 private TouchTarget mFirstTouchTarget;
196
Joe Onorato03ab0c72011-01-06 15:46:27 -0800197 // For debugging only. You can see these in hierarchyviewer.
Romain Guye95003e2011-01-09 13:53:06 -0800198 @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
Joe Onorato03ab0c72011-01-06 15:46:27 -0800199 @ViewDebug.ExportedProperty(category = "events")
200 private long mLastTouchDownTime;
201 @ViewDebug.ExportedProperty(category = "events")
202 private int mLastTouchDownIndex = -1;
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 mLastTouchDownX;
Romain Guye95003e2011-01-09 13:53:06 -0800206 @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
Joe Onorato03ab0c72011-01-06 15:46:27 -0800207 @ViewDebug.ExportedProperty(category = "events")
208 private float mLastTouchDownY;
209
Jeff Brown87b7f802011-06-21 18:35:45 -0700210 // First hover target in the linked list of hover targets.
211 // The hover targets are children which have received ACTION_HOVER_ENTER.
212 // They might not have actually handled the hover event, but we will
213 // continue sending hover events to them as long as the pointer remains over
214 // their bounds and the view group does not intercept hover.
215 private HoverTarget mFirstHoverTarget;
Jeff Browna032cc02011-03-07 16:56:21 -0800216
Jeff Brown10b62902011-06-20 16:40:37 -0700217 // True if the view group itself received a hover event.
218 // It might not have actually handled the hover event.
219 private boolean mHoveredSelf;
220
Vladislav Kaznacheevf847ee32016-11-21 14:11:00 -0800221 // The child capable of showing a tooltip and currently under the pointer.
222 private View mTooltipHoverTarget;
223
224 // True if the view group is capable of showing a tooltip and the pointer is directly
225 // over the view group but not one of its child views.
226 private boolean mTooltipHoveredSelf;
227
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800228 /**
229 * Internal flags.
Romain Guy8506ab42009-06-11 17:35:47 -0700230 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800231 * This field should be made private, so it is hidden from the SDK.
232 * {@hide}
233 */
Romain Guy2440e672012-08-07 14:43:43 -0700234 @ViewDebug.ExportedProperty(flagMapping = {
235 @ViewDebug.FlagToString(mask = FLAG_CLIP_CHILDREN, equals = FLAG_CLIP_CHILDREN,
236 name = "CLIP_CHILDREN"),
237 @ViewDebug.FlagToString(mask = FLAG_CLIP_TO_PADDING, equals = FLAG_CLIP_TO_PADDING,
238 name = "CLIP_TO_PADDING"),
239 @ViewDebug.FlagToString(mask = FLAG_PADDING_NOT_NULL, equals = FLAG_PADDING_NOT_NULL,
240 name = "PADDING_NOT_NULL")
Jon Miranda4597e982014-07-29 07:25:49 -0700241 }, formatToHexString = true)
Mathew Inwooda570dee2018-08-17 14:56:00 +0100242 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800243 protected int mGroupFlags;
244
Philip Milne7b757812012-09-19 18:13:44 -0700245 /**
246 * Either {@link #LAYOUT_MODE_CLIP_BOUNDS} or {@link #LAYOUT_MODE_OPTICAL_BOUNDS}.
Philip Milne1557fd72012-04-04 23:41:34 -0700247 */
Philip Milnecfb631b2012-10-26 10:51:46 -0700248 private int mLayoutMode = LAYOUT_MODE_UNDEFINED;
Philip Milne1557fd72012-04-04 23:41:34 -0700249
Romain Guy33f6beb2012-02-16 19:24:51 -0800250 /**
251 * NOTE: If you change the flags below make sure to reflect the changes
252 * the DisplayList class
253 */
Filip Gruszczynskia33bdf32015-11-19 18:22:16 -0800254
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800255 // When set, ViewGroup invalidates only the child's rectangle
256 // Set by default
Chet Haase64a48c12012-02-13 16:33:29 -0800257 static final int FLAG_CLIP_CHILDREN = 0x1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800258
259 // When set, ViewGroup excludes the padding area from the invalidate rectangle
260 // Set by default
261 private static final int FLAG_CLIP_TO_PADDING = 0x2;
262
263 // When set, dispatchDraw() will invoke invalidate(); this is set by drawChild() when
264 // a child needs to be invalidated and FLAG_OPTIMIZE_INVALIDATE is set
Chet Haase64a48c12012-02-13 16:33:29 -0800265 static final int FLAG_INVALIDATE_REQUIRED = 0x4;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800266
267 // When set, dispatchDraw() will run the layout animation and unset the flag
268 private static final int FLAG_RUN_ANIMATION = 0x8;
269
270 // When set, there is either no layout animation on the ViewGroup or the layout
271 // animation is over
272 // Set by default
Chet Haase64a48c12012-02-13 16:33:29 -0800273 static final int FLAG_ANIMATION_DONE = 0x10;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800274
275 // If set, this ViewGroup has padding; if unset there is no padding and we don't need
276 // to clip it, even if FLAG_CLIP_TO_PADDING is set
277 private static final int FLAG_PADDING_NOT_NULL = 0x20;
278
Chris Craik5a6bbae2015-04-10 17:41:34 -0700279 /** @deprecated - functionality removed */
Aurimas Liutikas514c5ef2016-05-24 15:22:55 -0700280 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800281 private static final int FLAG_ANIMATION_CACHE = 0x40;
282
283 // When set, this ViewGroup converts calls to invalidate(Rect) to invalidate() during a
284 // layout animation; this avoid clobbering the hierarchy
285 // Automatically set when the layout animation starts, depending on the animation's
286 // characteristics
Chet Haase64a48c12012-02-13 16:33:29 -0800287 static final int FLAG_OPTIMIZE_INVALIDATE = 0x80;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800288
289 // When set, the next call to drawChild() will clear mChildTransformation's matrix
Chet Haase64a48c12012-02-13 16:33:29 -0800290 static final int FLAG_CLEAR_TRANSFORMATION = 0x100;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800291
292 // When set, this ViewGroup invokes mAnimationListener.onAnimationEnd() and removes
293 // the children's Bitmap caches if necessary
294 // This flag is set when the layout animation is over (after FLAG_ANIMATION_DONE is set)
295 private static final int FLAG_NOTIFY_ANIMATION_LISTENER = 0x200;
296
297 /**
298 * When set, the drawing method will call {@link #getChildDrawingOrder(int, int)}
299 * to get the index of the child to draw for that iteration.
Filip Gruszczynskia33bdf32015-11-19 18:22:16 -0800300 *
Romain Guy293451e2009-11-04 13:59:48 -0800301 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800302 */
Mathew Inwooda570dee2018-08-17 14:56:00 +0100303 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800304 protected static final int FLAG_USE_CHILD_DRAWING_ORDER = 0x400;
Romain Guy8506ab42009-06-11 17:35:47 -0700305
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800306 /**
307 * When set, this ViewGroup supports static transformations on children; this causes
308 * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} to be
309 * invoked when a child is drawn.
310 *
311 * Any subclass overriding
312 * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} should
313 * set this flags in {@link #mGroupFlags}.
Romain Guy8506ab42009-06-11 17:35:47 -0700314 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800315 * {@hide}
316 */
Mathew Inwooda570dee2018-08-17 14:56:00 +0100317 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800318 protected static final int FLAG_SUPPORT_STATIC_TRANSFORMATIONS = 0x800;
319
John Reckfb5899d2014-08-15 18:51:27 -0700320 // UNUSED FLAG VALUE: 0x1000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800321
322 /**
323 * When set, this ViewGroup's drawable states also include those
324 * of its children.
325 */
326 private static final int FLAG_ADD_STATES_FROM_CHILDREN = 0x2000;
327
Chris Craik5a6bbae2015-04-10 17:41:34 -0700328 /** @deprecated functionality removed */
Aurimas Liutikas514c5ef2016-05-24 15:22:55 -0700329 @Deprecated
Chris Craik5a6bbae2015-04-10 17:41:34 -0700330 private static final int FLAG_ALWAYS_DRAWN_WITH_CACHE = 0x4000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800331
Chris Craik5a6bbae2015-04-10 17:41:34 -0700332 /** @deprecated functionality removed */
Aurimas Liutikas514c5ef2016-05-24 15:22:55 -0700333 @Deprecated
Chris Craik5a6bbae2015-04-10 17:41:34 -0700334 private static final int FLAG_CHILDREN_DRAWN_WITH_CACHE = 0x8000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800335
336 /**
337 * When set, this group will go through its list of children to notify them of
338 * any drawable state change.
339 */
340 private static final int FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE = 0x10000;
341
342 private static final int FLAG_MASK_FOCUSABILITY = 0x60000;
343
344 /**
345 * This view will get focus before any of its descendants.
346 */
347 public static final int FOCUS_BEFORE_DESCENDANTS = 0x20000;
348
349 /**
350 * This view will get focus only if none of its descendants want it.
351 */
352 public static final int FOCUS_AFTER_DESCENDANTS = 0x40000;
353
354 /**
355 * This view will block any of its descendants from getting focus, even
356 * if they are focusable.
357 */
358 public static final int FOCUS_BLOCK_DESCENDANTS = 0x60000;
359
360 /**
361 * Used to map between enum in attrubutes and flag values.
362 */
363 private static final int[] DESCENDANT_FOCUSABILITY_FLAGS =
364 {FOCUS_BEFORE_DESCENDANTS, FOCUS_AFTER_DESCENDANTS,
365 FOCUS_BLOCK_DESCENDANTS};
366
367 /**
368 * When set, this ViewGroup should not intercept touch events.
Adam Powell110486f2010-06-22 17:14:44 -0700369 * {@hide}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800370 */
Mathew Inwooda570dee2018-08-17 14:56:00 +0100371 @UnsupportedAppUsage
Adam Powell110486f2010-06-22 17:14:44 -0700372 protected static final int FLAG_DISALLOW_INTERCEPT = 0x80000;
Romain Guy8506ab42009-06-11 17:35:47 -0700373
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800374 /**
Adam Powell2b342f02010-08-18 18:14:13 -0700375 * When set, this ViewGroup will split MotionEvents to multiple child Views when appropriate.
376 */
Adam Powellf37df072010-09-17 16:22:49 -0700377 private static final int FLAG_SPLIT_MOTION_EVENTS = 0x200000;
Adam Powell2b342f02010-08-18 18:14:13 -0700378
379 /**
Adam Powell4b867882011-09-16 12:59:46 -0700380 * When set, this ViewGroup will not dispatch onAttachedToWindow calls
381 * to children when adding new views. This is used to prevent multiple
382 * onAttached calls when a ViewGroup adds children in its own onAttached method.
383 */
384 private static final int FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW = 0x400000;
385
386 /**
Philip Milnecfb631b2012-10-26 10:51:46 -0700387 * When true, indicates that a layoutMode has been explicitly set, either with
388 * an explicit call to {@link #setLayoutMode(int)} in code or from an XML resource.
389 * This distinguishes the situation in which a layout mode was inherited from
390 * one of the ViewGroup's ancestors and cached locally.
391 */
392 private static final int FLAG_LAYOUT_MODE_WAS_EXPLICITLY_SET = 0x800000;
393
Chris Craikb49f4462014-03-20 12:44:20 -0700394 static final int FLAG_IS_TRANSITION_GROUP = 0x1000000;
Chris Craikd863a102013-12-19 13:31:15 -0800395
Chris Craikb49f4462014-03-20 12:44:20 -0700396 static final int FLAG_IS_TRANSITION_GROUP_SET = 0x2000000;
George Mount0a778ed2013-12-13 13:35:36 -0800397
Chris Craikd863a102013-12-19 13:31:15 -0800398 /**
Adam Powellff0d2982014-07-10 20:34:14 -0700399 * When set, focus will not be permitted to enter this group if a touchscreen is present.
400 */
401 static final int FLAG_TOUCHSCREEN_BLOCKS_FOCUS = 0x4000000;
402
403 /**
Clara Bayarri4423d912015-03-02 19:42:48 +0000404 * When true, indicates that a call to startActionModeForChild was made with the type parameter
405 * and should not be ignored. This helps in backwards compatibility with the existing method
406 * without a type.
407 *
408 * @see #startActionModeForChild(View, android.view.ActionMode.Callback)
409 * @see #startActionModeForChild(View, android.view.ActionMode.Callback, int)
410 */
411 private static final int FLAG_START_ACTION_MODE_FOR_CHILD_IS_TYPED = 0x8000000;
412
413 /**
414 * When true, indicates that a call to startActionModeForChild was made without the type
415 * parameter. This helps in backwards compatibility with the existing method
416 * without a type.
417 *
418 * @see #startActionModeForChild(View, android.view.ActionMode.Callback)
419 * @see #startActionModeForChild(View, android.view.ActionMode.Callback, int)
420 */
421 private static final int FLAG_START_ACTION_MODE_FOR_CHILD_IS_NOT_TYPED = 0x10000000;
422
423 /**
Adam Powell2af189a2016-02-05 15:52:02 -0800424 * When set, indicates that a call to showContextMenuForChild was made with explicit
425 * coordinates within the initiating child view.
426 */
427 private static final int FLAG_SHOW_CONTEXT_MENU_WITH_COORDS = 0x20000000;
428
429 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800430 * Indicates which types of drawing caches are to be kept in memory.
431 * This field should be made private, so it is hidden from the SDK.
432 * {@hide}
433 */
Mathew Inwooda570dee2018-08-17 14:56:00 +0100434 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800435 protected int mPersistentDrawingCache;
436
437 /**
438 * Used to indicate that no drawing cache should be kept in memory.
John Reck949cfe12017-10-09 13:27:03 -0700439 *
440 * @deprecated The view drawing cache was largely made obsolete with the introduction of
441 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache
442 * layers are largely unnecessary and can easily result in a net loss in performance due to the
443 * cost of creating and updating the layer. In the rare cases where caching layers are useful,
444 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware
445 * rendering. For software-rendered snapshots of a small part of the View hierarchy or
446 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or
447 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these
448 * software-rendered usages are discouraged and have compatibility issues with hardware-only
449 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE}
450 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback
451 * reports or unit testing the {@link PixelCopy} API is recommended.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800452 */
John Reck949cfe12017-10-09 13:27:03 -0700453 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800454 public static final int PERSISTENT_NO_CACHE = 0x0;
455
456 /**
457 * Used to indicate that the animation drawing cache should be kept in memory.
John Reck949cfe12017-10-09 13:27:03 -0700458 *
459 * @deprecated The view drawing cache was largely made obsolete with the introduction of
460 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache
461 * layers are largely unnecessary and can easily result in a net loss in performance due to the
462 * cost of creating and updating the layer. In the rare cases where caching layers are useful,
463 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware
464 * rendering. For software-rendered snapshots of a small part of the View hierarchy or
465 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or
466 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these
467 * software-rendered usages are discouraged and have compatibility issues with hardware-only
468 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE}
469 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback
470 * reports or unit testing the {@link PixelCopy} API is recommended.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800471 */
John Reck949cfe12017-10-09 13:27:03 -0700472 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800473 public static final int PERSISTENT_ANIMATION_CACHE = 0x1;
474
475 /**
476 * Used to indicate that the scrolling drawing cache should be kept in memory.
John Reck949cfe12017-10-09 13:27:03 -0700477 *
478 * @deprecated The view drawing cache was largely made obsolete with the introduction of
479 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache
480 * layers are largely unnecessary and can easily result in a net loss in performance due to the
481 * cost of creating and updating the layer. In the rare cases where caching layers are useful,
482 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware
483 * rendering. For software-rendered snapshots of a small part of the View hierarchy or
484 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or
485 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these
486 * software-rendered usages are discouraged and have compatibility issues with hardware-only
487 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE}
488 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback
489 * reports or unit testing the {@link PixelCopy} API is recommended.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800490 */
John Reck949cfe12017-10-09 13:27:03 -0700491 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800492 public static final int PERSISTENT_SCROLLING_CACHE = 0x2;
493
494 /**
495 * Used to indicate that all drawing caches should be kept in memory.
John Reck949cfe12017-10-09 13:27:03 -0700496 *
497 * @deprecated The view drawing cache was largely made obsolete with the introduction of
498 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache
499 * layers are largely unnecessary and can easily result in a net loss in performance due to the
500 * cost of creating and updating the layer. In the rare cases where caching layers are useful,
501 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware
502 * rendering. For software-rendered snapshots of a small part of the View hierarchy or
503 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or
504 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these
505 * software-rendered usages are discouraged and have compatibility issues with hardware-only
506 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE}
507 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback
508 * reports or unit testing the {@link PixelCopy} API is recommended.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800509 */
John Reck949cfe12017-10-09 13:27:03 -0700510 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800511 public static final int PERSISTENT_ALL_CACHES = 0x3;
512
Philip Milne1557fd72012-04-04 23:41:34 -0700513 // Layout Modes
514
Philip Milnecfb631b2012-10-26 10:51:46 -0700515 private static final int LAYOUT_MODE_UNDEFINED = -1;
516
Philip Milne1557fd72012-04-04 23:41:34 -0700517 /**
518 * This constant is a {@link #setLayoutMode(int) layoutMode}.
Philip Milne7a23b492012-04-24 22:12:36 -0700519 * Clip bounds are the raw values of {@link #getLeft() left}, {@link #getTop() top},
Philip Milne1557fd72012-04-04 23:41:34 -0700520 * {@link #getRight() right} and {@link #getBottom() bottom}.
521 */
Philip Milne7b757812012-09-19 18:13:44 -0700522 public static final int LAYOUT_MODE_CLIP_BOUNDS = 0;
Philip Milne1557fd72012-04-04 23:41:34 -0700523
524 /**
525 * This constant is a {@link #setLayoutMode(int) layoutMode}.
Philip Milne7a23b492012-04-24 22:12:36 -0700526 * Optical bounds describe where a widget appears to be. They sit inside the clip
527 * bounds which need to cover a larger area to allow other effects,
528 * such as shadows and glows, to be drawn.
Philip Milne1557fd72012-04-04 23:41:34 -0700529 */
Philip Milne7b757812012-09-19 18:13:44 -0700530 public static final int LAYOUT_MODE_OPTICAL_BOUNDS = 1;
531
532 /** @hide */
Philip Milnecfb631b2012-10-26 10:51:46 -0700533 public static int LAYOUT_MODE_DEFAULT = LAYOUT_MODE_CLIP_BOUNDS;
Philip Milne1557fd72012-04-04 23:41:34 -0700534
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800535 /**
536 * We clip to padding when FLAG_CLIP_TO_PADDING and FLAG_PADDING_NOT_NULL
537 * are set at the same time.
538 */
539 protected static final int CLIP_TO_PADDING_MASK = FLAG_CLIP_TO_PADDING | FLAG_PADDING_NOT_NULL;
540
541 // Index of the child's left position in the mLocation array
542 private static final int CHILD_LEFT_INDEX = 0;
543 // Index of the child's top position in the mLocation array
544 private static final int CHILD_TOP_INDEX = 1;
545
546 // Child views of this ViewGroup
Mihai Popa831c1a92018-10-15 15:40:23 +0100547 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800548 private View[] mChildren;
549 // Number of valid children in the mChildren array, the rest should be null or not
550 // considered as children
Mihai Popa831c1a92018-10-15 15:40:23 +0100551 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800552 private int mChildrenCount;
553
Chet Haaseb9895022013-04-02 15:10:58 -0700554 // Whether layout calls are currently being suppressed, controlled by calls to
555 // suppressLayout()
556 boolean mSuppressLayout = false;
557
558 // Whether any layout calls have actually been suppressed while mSuppressLayout
559 // has been true. This tracks whether we need to issue a requestLayout() when
560 // layout is later re-enabled.
561 private boolean mLayoutCalledWhileSuppressed = false;
562
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800563 private static final int ARRAY_INITIAL_CAPACITY = 12;
564 private static final int ARRAY_CAPACITY_INCREMENT = 12;
565
Romain Guycbc67742012-04-27 16:12:57 -0700566 private static float[] sDebugLines;
Philip Milne604f4402012-04-24 19:27:11 -0700567
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800568 // Used to draw cached views
Chet Haase64a48c12012-02-13 16:33:29 -0800569 Paint mCachePaint;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800570
Chet Haase21cd1382010-09-01 17:42:29 -0700571 // Used to animate add/remove changes in layout
572 private LayoutTransition mTransition;
573
574 // The set of views that are currently being transitioned. This list is used to track views
575 // being removed that should not actually be removed from the parent yet because they are
576 // being animated.
577 private ArrayList<View> mTransitioningViews;
578
Chet Haase5e25c2c2010-09-16 11:15:56 -0700579 // List of children changing visibility. This is used to potentially keep rendering
580 // views during a transition when they otherwise would have become gone/invisible
581 private ArrayList<View> mVisibilityChangingChildren;
582
Chris Craikab008f02014-05-23 17:55:03 -0700583 // Temporary holder of presorted children, only used for
584 // input/software draw dispatch for correctly Z ordering.
585 private ArrayList<View> mPreSortedChildren;
586
Adam Powell539ee872012-02-03 19:00:49 -0800587 // Indicates how many of this container's child subtrees contain transient state
588 @ViewDebug.ExportedProperty(category = "layout")
589 private int mChildCountWithTransientState = 0;
590
Adam Powell10ba2772014-04-15 09:46:51 -0700591 /**
592 * Currently registered axes for nested scrolling. Flag set consisting of
593 * {@link #SCROLL_AXIS_HORIZONTAL} {@link #SCROLL_AXIS_VERTICAL} or {@link #SCROLL_AXIS_NONE}
594 * for null.
595 */
596 private int mNestedScrollAxes;
597
Chet Haasec633d2f2015-04-07 10:29:39 -0700598 // Used to manage the list of transient views, added by addTransientView()
599 private List<Integer> mTransientIndices = null;
600 private List<View> mTransientViews = null;
601
Evan Rosky4807ae22018-03-22 16:04:15 -0700602 /**
603 * Keeps track of how many child views have UnhandledKeyEventListeners. This should only be
604 * updated on the UI thread so shouldn't require explicit synchronization.
605 */
606 int mChildUnhandledKeyListeners = 0;
Chet Haasec633d2f2015-04-07 10:29:39 -0700607
Clara Bayarri4423d912015-03-02 19:42:48 +0000608 /**
609 * Empty ActionMode used as a sentinel in recursive entries to startActionModeForChild.
610 *
611 * @see #startActionModeForChild(View, android.view.ActionMode.Callback)
612 * @see #startActionModeForChild(View, android.view.ActionMode.Callback, int)
613 */
614 private static final ActionMode SENTINEL_ACTION_MODE = new ActionMode() {
615 @Override
616 public void setTitle(CharSequence title) {}
617
618 @Override
619 public void setTitle(int resId) {}
620
621 @Override
622 public void setSubtitle(CharSequence subtitle) {}
623
624 @Override
625 public void setSubtitle(int resId) {}
626
627 @Override
628 public void setCustomView(View view) {}
629
630 @Override
631 public void invalidate() {}
632
633 @Override
634 public void finish() {}
635
636 @Override
637 public Menu getMenu() {
638 return null;
639 }
640
641 @Override
642 public CharSequence getTitle() {
643 return null;
644 }
645
646 @Override
647 public CharSequence getSubtitle() {
648 return null;
649 }
650
651 @Override
652 public View getCustomView() {
653 return null;
654 }
655
656 @Override
657 public MenuInflater getMenuInflater() {
658 return null;
659 }
660 };
661
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800662 public ViewGroup(Context context) {
Alan Viveretted6479ec2013-09-10 17:03:02 -0700663 this(context, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800664 }
665
666 public ViewGroup(Context context, AttributeSet attrs) {
Alan Viveretted6479ec2013-09-10 17:03:02 -0700667 this(context, attrs, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800668 }
669
Alan Viverette617feb92013-09-09 18:09:13 -0700670 public ViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {
Alan Viveretted6479ec2013-09-10 17:03:02 -0700671 this(context, attrs, defStyleAttr, 0);
Alan Viverette617feb92013-09-09 18:09:13 -0700672 }
673
674 public ViewGroup(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
675 super(context, attrs, defStyleAttr, defStyleRes);
Felipe Lemed04a6972017-03-02 12:56:18 -0800676
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800677 initViewGroup();
Alan Viveretted6479ec2013-09-10 17:03:02 -0700678 initFromAttributes(context, attrs, defStyleAttr, defStyleRes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800679 }
680
681 private void initViewGroup() {
682 // ViewGroup doesn't draw by default
Philip Milne10ca24a2012-04-23 15:38:27 -0700683 if (!debugDraw()) {
684 setFlags(WILL_NOT_DRAW, DRAW_MASK);
685 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800686 mGroupFlags |= FLAG_CLIP_CHILDREN;
687 mGroupFlags |= FLAG_CLIP_TO_PADDING;
688 mGroupFlags |= FLAG_ANIMATION_DONE;
Chris Craikf6ce8fd2015-05-11 15:33:11 -0700689 mGroupFlags |= FLAG_ANIMATION_CACHE;
690 mGroupFlags |= FLAG_ALWAYS_DRAWN_WITH_CACHE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800691
Jeff Brown995e7742010-12-22 16:59:36 -0800692 if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB) {
693 mGroupFlags |= FLAG_SPLIT_MOTION_EVENTS;
694 }
695
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800696 setDescendantFocusability(FOCUS_BEFORE_DESCENDANTS);
697
698 mChildren = new View[ARRAY_INITIAL_CAPACITY];
699 mChildrenCount = 0;
700
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800701 mPersistentDrawingCache = PERSISTENT_SCROLLING_CACHE;
702 }
703
Alan Viveretted6479ec2013-09-10 17:03:02 -0700704 private void initFromAttributes(
705 Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
Aurimas Liutikasab324cf2019-02-07 16:46:38 -0800706 final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ViewGroup,
707 defStyleAttr, defStyleRes);
708 saveAttributeDataForStyleable(context, R.styleable.ViewGroup, attrs, a, defStyleAttr,
Filip Gruszczyńskib50cea02014-03-05 17:54:58 -0800709 defStyleRes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800710
711 final int N = a.getIndexCount();
712 for (int i = 0; i < N; i++) {
713 int attr = a.getIndex(i);
714 switch (attr) {
715 case R.styleable.ViewGroup_clipChildren:
716 setClipChildren(a.getBoolean(attr, true));
717 break;
718 case R.styleable.ViewGroup_clipToPadding:
719 setClipToPadding(a.getBoolean(attr, true));
720 break;
721 case R.styleable.ViewGroup_animationCache:
722 setAnimationCacheEnabled(a.getBoolean(attr, true));
723 break;
724 case R.styleable.ViewGroup_persistentDrawingCache:
725 setPersistentDrawingCache(a.getInt(attr, PERSISTENT_SCROLLING_CACHE));
726 break;
727 case R.styleable.ViewGroup_addStatesFromChildren:
728 setAddStatesFromChildren(a.getBoolean(attr, false));
729 break;
730 case R.styleable.ViewGroup_alwaysDrawnWithCache:
731 setAlwaysDrawnWithCacheEnabled(a.getBoolean(attr, true));
732 break;
733 case R.styleable.ViewGroup_layoutAnimation:
734 int id = a.getResourceId(attr, -1);
735 if (id > 0) {
736 setLayoutAnimation(AnimationUtils.loadLayoutAnimation(mContext, id));
737 }
738 break;
739 case R.styleable.ViewGroup_descendantFocusability:
740 setDescendantFocusability(DESCENDANT_FOCUSABILITY_FLAGS[a.getInt(attr, 0)]);
741 break;
Adam Powell2b342f02010-08-18 18:14:13 -0700742 case R.styleable.ViewGroup_splitMotionEvents:
743 setMotionEventSplittingEnabled(a.getBoolean(attr, false));
744 break;
Chet Haase13cc1202010-09-03 15:39:20 -0700745 case R.styleable.ViewGroup_animateLayoutChanges:
746 boolean animateLayoutChanges = a.getBoolean(attr, false);
747 if (animateLayoutChanges) {
748 setLayoutTransition(new LayoutTransition());
749 }
750 break;
Philip Milne7b757812012-09-19 18:13:44 -0700751 case R.styleable.ViewGroup_layoutMode:
Philip Milnecfb631b2012-10-26 10:51:46 -0700752 setLayoutMode(a.getInt(attr, LAYOUT_MODE_UNDEFINED));
Philip Milne7b757812012-09-19 18:13:44 -0700753 break;
George Mount0a778ed2013-12-13 13:35:36 -0800754 case R.styleable.ViewGroup_transitionGroup:
755 setTransitionGroup(a.getBoolean(attr, false));
756 break;
Adam Powellff0d2982014-07-10 20:34:14 -0700757 case R.styleable.ViewGroup_touchscreenBlocksFocus:
758 setTouchscreenBlocksFocus(a.getBoolean(attr, false));
759 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800760 }
761 }
762
763 a.recycle();
764 }
765
766 /**
767 * Gets the descendant focusability of this view group. The descendant
768 * focusability defines the relationship between this view group and its
769 * descendants when looking for a view to take focus in
770 * {@link #requestFocus(int, android.graphics.Rect)}.
771 *
772 * @return one of {@link #FOCUS_BEFORE_DESCENDANTS}, {@link #FOCUS_AFTER_DESCENDANTS},
773 * {@link #FOCUS_BLOCK_DESCENDANTS}.
774 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -0700775 @ViewDebug.ExportedProperty(category = "focus", mapping = {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800776 @ViewDebug.IntToString(from = FOCUS_BEFORE_DESCENDANTS, to = "FOCUS_BEFORE_DESCENDANTS"),
777 @ViewDebug.IntToString(from = FOCUS_AFTER_DESCENDANTS, to = "FOCUS_AFTER_DESCENDANTS"),
778 @ViewDebug.IntToString(from = FOCUS_BLOCK_DESCENDANTS, to = "FOCUS_BLOCK_DESCENDANTS")
779 })
Ashley Rose55f9f922019-01-28 19:29:36 -0500780 @InspectableProperty(enumMapping = {
781 @EnumMap(value = FOCUS_BEFORE_DESCENDANTS, name = "beforeDescendants"),
782 @EnumMap(value = FOCUS_AFTER_DESCENDANTS, name = "afterDescendants"),
783 @EnumMap(value = FOCUS_BLOCK_DESCENDANTS, name = "blocksDescendants")
784 })
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800785 public int getDescendantFocusability() {
786 return mGroupFlags & FLAG_MASK_FOCUSABILITY;
787 }
788
789 /**
790 * Set the descendant focusability of this view group. This defines the relationship
791 * between this view group and its descendants when looking for a view to
792 * take focus in {@link #requestFocus(int, android.graphics.Rect)}.
793 *
794 * @param focusability one of {@link #FOCUS_BEFORE_DESCENDANTS}, {@link #FOCUS_AFTER_DESCENDANTS},
795 * {@link #FOCUS_BLOCK_DESCENDANTS}.
796 */
797 public void setDescendantFocusability(int focusability) {
798 switch (focusability) {
799 case FOCUS_BEFORE_DESCENDANTS:
800 case FOCUS_AFTER_DESCENDANTS:
801 case FOCUS_BLOCK_DESCENDANTS:
802 break;
803 default:
804 throw new IllegalArgumentException("must be one of FOCUS_BEFORE_DESCENDANTS, "
805 + "FOCUS_AFTER_DESCENDANTS, FOCUS_BLOCK_DESCENDANTS");
806 }
807 mGroupFlags &= ~FLAG_MASK_FOCUSABILITY;
808 mGroupFlags |= (focusability & FLAG_MASK_FOCUSABILITY);
809 }
810
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800811 @Override
812 void handleFocusGainInternal(int direction, Rect previouslyFocusedRect) {
813 if (mFocused != null) {
Alan Viverette223622a2013-12-17 13:29:02 -0800814 mFocused.unFocus(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800815 mFocused = null;
Evan Rosky53fcf112017-01-26 14:37:55 -0800816 mFocusedInCluster = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800817 }
818 super.handleFocusGainInternal(direction, previouslyFocusedRect);
819 }
820
Alan Viverettebe463f22016-01-21 10:50:10 -0500821 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800822 public void requestChildFocus(View child, View focused) {
823 if (DBG) {
824 System.out.println(this + " requestChildFocus()");
825 }
826 if (getDescendantFocusability() == FOCUS_BLOCK_DESCENDANTS) {
827 return;
828 }
829
830 // Unfocus us, if necessary
Alan Viverette223622a2013-12-17 13:29:02 -0800831 super.unFocus(focused);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800832
833 // We had a previous notion of who had focus. Clear it.
834 if (mFocused != child) {
835 if (mFocused != null) {
Alan Viverette223622a2013-12-17 13:29:02 -0800836 mFocused.unFocus(focused);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800837 }
838
839 mFocused = child;
840 }
841 if (mParent != null) {
842 mParent.requestChildFocus(this, focused);
843 }
844 }
845
Vadim Tryshev5ca73982017-01-04 17:24:43 -0800846 void setDefaultFocus(View child) {
Evan Rosky53fcf112017-01-26 14:37:55 -0800847 // Stop at any higher view which is explicitly focused-by-default
848 if (mDefaultFocus != null && mDefaultFocus.isFocusedByDefault()) {
Vadim Tryshev5ca73982017-01-04 17:24:43 -0800849 return;
Vadim Tryshev01d8c492016-12-15 11:33:15 -0800850 }
Vadim Tryshev5ca73982017-01-04 17:24:43 -0800851
852 mDefaultFocus = child;
853
854 if (mParent instanceof ViewGroup) {
855 ((ViewGroup) mParent).setDefaultFocus(this);
856 }
857 }
858
859 /**
Evan Rosky53fcf112017-01-26 14:37:55 -0800860 * Clears the default-focus chain from {@param child} up to the first parent which has another
861 * default-focusable branch below it or until there is no default-focus chain.
862 *
863 * @param child
Vadim Tryshev5ca73982017-01-04 17:24:43 -0800864 */
Evan Rosky53fcf112017-01-26 14:37:55 -0800865 void clearDefaultFocus(View child) {
866 // Stop at any higher view which is explicitly focused-by-default
867 if (mDefaultFocus != child && mDefaultFocus != null
868 && mDefaultFocus.isFocusedByDefault()) {
869 return;
870 }
871
872 mDefaultFocus = null;
873
874 // Search child siblings for default focusables.
875 for (int i = 0; i < mChildrenCount; ++i) {
876 View sibling = mChildren[i];
877 if (sibling.isFocusedByDefault()) {
878 mDefaultFocus = sibling;
879 return;
880 } else if (mDefaultFocus == null && sibling.hasDefaultFocus()) {
881 mDefaultFocus = sibling;
882 }
883 }
884
885 if (mParent instanceof ViewGroup) {
886 ((ViewGroup) mParent).clearDefaultFocus(this);
887 }
888 }
889
890 @Override
891 boolean hasDefaultFocus() {
892 return mDefaultFocus != null || super.hasDefaultFocus();
893 }
894
Evan Rosky0e8a6832017-04-10 12:35:15 -0700895 /**
896 * Removes {@code child} (and associated focusedInCluster chain) from the cluster containing
897 * it.
898 * <br>
899 * This is intended to be run on {@code child}'s immediate parent. This is necessary because
900 * the chain is sometimes cleared after {@code child} has been detached.
901 */
902 void clearFocusedInCluster(View child) {
Evan Rosky53fcf112017-01-26 14:37:55 -0800903 if (mFocusedInCluster != child) {
Vadim Tryshev5ca73982017-01-04 17:24:43 -0800904 return;
905 }
Evan Rosky5b20e092017-07-13 18:04:39 -0700906 clearFocusedInCluster();
907 }
908
909 /**
910 * Removes the focusedInCluster chain from this up to the cluster containing it.
911 */
912 void clearFocusedInCluster() {
Evan Rosky0e8a6832017-04-10 12:35:15 -0700913 View top = findKeyboardNavigationCluster();
914 ViewParent parent = this;
915 do {
916 ((ViewGroup) parent).mFocusedInCluster = null;
Evan Rosky6c286be2017-04-19 17:23:32 -0700917 if (parent == top) {
918 break;
919 }
Evan Rosky0e8a6832017-04-10 12:35:15 -0700920 parent = parent.getParent();
Evan Rosky6c286be2017-04-19 17:23:32 -0700921 } while (parent instanceof ViewGroup);
Vadim Tryshev5ca73982017-01-04 17:24:43 -0800922 }
923
924 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800925 public void focusableViewAvailable(View v) {
926 if (mParent != null
927 // shortcut: don't report a new focusable view if we block our descendants from
Evan Rosky2ae1bf52017-05-11 11:18:45 -0700928 // getting focus or if we're not visible
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800929 && (getDescendantFocusability() != FOCUS_BLOCK_DESCENDANTS)
Evan Rosky2ae1bf52017-05-11 11:18:45 -0700930 && ((mViewFlags & VISIBILITY_MASK) == VISIBLE)
Adam Powell88c11752014-07-21 17:19:16 -0700931 && (isFocusableInTouchMode() || !shouldBlockFocusForTouchscreen())
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800932 // shortcut: don't report a new focusable view if we already are focused
933 // (and we don't prefer our descendants)
934 //
935 // note: knowing that mFocused is non-null is not a good enough reason
936 // to break the traversal since in that case we'd actually have to find
937 // the focused view and make sure it wasn't FOCUS_AFTER_DESCENDANTS and
Joe Onoratoc6cc0f82011-04-12 11:53:13 -0700938 // an ancestor of v; this will get checked for at ViewAncestor
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800939 && !(isFocused() && getDescendantFocusability() != FOCUS_AFTER_DESCENDANTS)) {
940 mParent.focusableViewAvailable(v);
941 }
942 }
943
Alan Viverettebe463f22016-01-21 10:50:10 -0500944 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800945 public boolean showContextMenuForChild(View originalView) {
Adam Powell2af189a2016-02-05 15:52:02 -0800946 if (isShowingContextMenuWithCoords()) {
947 // We're being called for compatibility. Return false and let the version
948 // with coordinates recurse up.
949 return false;
950 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800951 return mParent != null && mParent.showContextMenuForChild(originalView);
952 }
953
Adam Powell2af189a2016-02-05 15:52:02 -0800954 /**
955 * @hide used internally for compatibility with existing app code only
956 */
957 public final boolean isShowingContextMenuWithCoords() {
958 return (mGroupFlags & FLAG_SHOW_CONTEXT_MENU_WITH_COORDS) != 0;
959 }
960
Oren Blasberged391262015-09-01 12:12:51 -0700961 @Override
962 public boolean showContextMenuForChild(View originalView, float x, float y) {
Adam Powell2af189a2016-02-05 15:52:02 -0800963 try {
964 mGroupFlags |= FLAG_SHOW_CONTEXT_MENU_WITH_COORDS;
965 if (showContextMenuForChild(originalView)) {
966 return true;
967 }
968 } finally {
969 mGroupFlags &= ~FLAG_SHOW_CONTEXT_MENU_WITH_COORDS;
970 }
Oren Blasberged391262015-09-01 12:12:51 -0700971 return mParent != null && mParent.showContextMenuForChild(originalView, x, y);
972 }
973
Clara Bayarri4423d912015-03-02 19:42:48 +0000974 @Override
Adam Powell6e346362010-07-23 10:18:23 -0700975 public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback) {
Clara Bayarri4423d912015-03-02 19:42:48 +0000976 if ((mGroupFlags & FLAG_START_ACTION_MODE_FOR_CHILD_IS_TYPED) == 0) {
977 // This is the original call.
978 try {
979 mGroupFlags |= FLAG_START_ACTION_MODE_FOR_CHILD_IS_NOT_TYPED;
980 return startActionModeForChild(originalView, callback, ActionMode.TYPE_PRIMARY);
981 } finally {
982 mGroupFlags &= ~FLAG_START_ACTION_MODE_FOR_CHILD_IS_NOT_TYPED;
983 }
984 } else {
985 // We are being called from the new method with type.
986 return SENTINEL_ACTION_MODE;
987 }
988 }
989
Clara Bayarri4423d912015-03-02 19:42:48 +0000990 @Override
991 public ActionMode startActionModeForChild(
992 View originalView, ActionMode.Callback callback, int type) {
Adam Powelle9fd6d22015-06-01 11:26:32 -0700993 if ((mGroupFlags & FLAG_START_ACTION_MODE_FOR_CHILD_IS_NOT_TYPED) == 0
994 && type == ActionMode.TYPE_PRIMARY) {
Clara Bayarri4423d912015-03-02 19:42:48 +0000995 ActionMode mode;
996 try {
997 mGroupFlags |= FLAG_START_ACTION_MODE_FOR_CHILD_IS_TYPED;
998 mode = startActionModeForChild(originalView, callback);
999 } finally {
1000 mGroupFlags &= ~FLAG_START_ACTION_MODE_FOR_CHILD_IS_TYPED;
1001 }
1002 if (mode != SENTINEL_ACTION_MODE) {
1003 return mode;
1004 }
1005 }
1006 if (mParent != null) {
1007 try {
1008 return mParent.startActionModeForChild(originalView, callback, type);
1009 } catch (AbstractMethodError ame) {
1010 // Custom view parents might not implement this method.
1011 return mParent.startActionModeForChild(originalView, callback);
1012 }
1013 }
1014 return null;
Adam Powell6e346362010-07-23 10:18:23 -07001015 }
1016
1017 /**
Clara Bayarrid5bf3ed2015-03-27 17:32:45 +00001018 * @hide
1019 */
1020 @Override
1021 public boolean dispatchActivityResult(
1022 String who, int requestCode, int resultCode, Intent data) {
1023 if (super.dispatchActivityResult(who, requestCode, resultCode, data)) {
1024 return true;
1025 }
1026 int childCount = getChildCount();
1027 for (int i = 0; i < childCount; i++) {
1028 View child = getChildAt(i);
1029 if (child.dispatchActivityResult(who, requestCode, resultCode, data)) {
1030 return true;
1031 }
1032 }
1033 return false;
1034 }
1035
1036 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001037 * Find the nearest view in the specified direction that wants to take
1038 * focus.
1039 *
1040 * @param focused The view that currently has focus
1041 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and
1042 * FOCUS_RIGHT, or 0 for not applicable.
1043 */
Alan Viverettebe463f22016-01-21 10:50:10 -05001044 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001045 public View focusSearch(View focused, int direction) {
Vadim Tryshevb5ced222017-01-17 19:31:35 -08001046 if (isRootNamespace()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001047 // root namespace means we should consider ourselves the top of the
1048 // tree for focus searching; otherwise we could be focus searching
Vadim Tryshev418b1fc2016-11-28 18:26:24 -08001049 // into other tabs. see LocalActivityManager and TabHost for more info.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001050 return FocusFinder.getInstance().findNextFocus(this, focused, direction);
1051 } else if (mParent != null) {
1052 return mParent.focusSearch(focused, direction);
1053 }
1054 return null;
1055 }
1056
Alan Viverettebe463f22016-01-21 10:50:10 -05001057 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001058 public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
1059 return false;
1060 }
1061
Svetoslav Ganov42138042012-03-20 11:51:39 -07001062 @Override
Svetoslav Ganov736c2752011-04-22 18:30:36 -07001063 public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07001064 ViewParent parent = mParent;
Svetoslav Ganov736c2752011-04-22 18:30:36 -07001065 if (parent == null) {
1066 return false;
1067 }
1068 final boolean propagate = onRequestSendAccessibilityEvent(child, event);
1069 if (!propagate) {
1070 return false;
1071 }
1072 return parent.requestSendAccessibilityEvent(this, event);
1073 }
1074
1075 /**
1076 * Called when a child has requested sending an {@link AccessibilityEvent} and
1077 * gives an opportunity to its parent to augment the event.
Svetoslav Ganov031d9c12011-09-09 16:41:13 -07001078 * <p>
Adam Powell2fcbbd02011-09-28 18:56:43 -07001079 * If an {@link android.view.View.AccessibilityDelegate} has been specified via calling
1080 * {@link android.view.View#setAccessibilityDelegate(android.view.View.AccessibilityDelegate)} its
1081 * {@link android.view.View.AccessibilityDelegate#onRequestSendAccessibilityEvent(ViewGroup, View, AccessibilityEvent)}
Svetoslav Ganov031d9c12011-09-09 16:41:13 -07001082 * is responsible for handling this call.
1083 * </p>
Svetoslav Ganov736c2752011-04-22 18:30:36 -07001084 *
1085 * @param child The child which requests sending the event.
1086 * @param event The event to be sent.
1087 * @return True if the event should be sent.
1088 *
1089 * @see #requestSendAccessibilityEvent(View, AccessibilityEvent)
1090 */
1091 public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
Svetoslav Ganov031d9c12011-09-09 16:41:13 -07001092 if (mAccessibilityDelegate != null) {
1093 return mAccessibilityDelegate.onRequestSendAccessibilityEvent(this, child, event);
1094 } else {
1095 return onRequestSendAccessibilityEventInternal(child, event);
1096 }
1097 }
1098
1099 /**
1100 * @see #onRequestSendAccessibilityEvent(View, AccessibilityEvent)
1101 *
1102 * Note: Called from the default {@link View.AccessibilityDelegate}.
Alan Viverettea54956a2015-01-07 16:05:02 -08001103 *
1104 * @hide
Svetoslav Ganov031d9c12011-09-09 16:41:13 -07001105 */
Alan Viverettea54956a2015-01-07 16:05:02 -08001106 public boolean onRequestSendAccessibilityEventInternal(View child, AccessibilityEvent event) {
Svetoslav Ganov736c2752011-04-22 18:30:36 -07001107 return true;
1108 }
1109
1110 /**
Adam Powell539ee872012-02-03 19:00:49 -08001111 * Called when a child view has changed whether or not it is tracking transient state.
Adam Powell539ee872012-02-03 19:00:49 -08001112 */
Alan Viverettebe463f22016-01-21 10:50:10 -05001113 @Override
Adam Powell539ee872012-02-03 19:00:49 -08001114 public void childHasTransientStateChanged(View child, boolean childHasTransientState) {
1115 final boolean oldHasTransientState = hasTransientState();
1116 if (childHasTransientState) {
1117 mChildCountWithTransientState++;
1118 } else {
1119 mChildCountWithTransientState--;
1120 }
1121
1122 final boolean newHasTransientState = hasTransientState();
1123 if (mParent != null && oldHasTransientState != newHasTransientState) {
1124 try {
1125 mParent.childHasTransientStateChanged(this, newHasTransientState);
1126 } catch (AbstractMethodError e) {
1127 Log.e(TAG, mParent.getClass().getSimpleName() +
1128 " does not fully implement ViewParent", e);
1129 }
1130 }
1131 }
1132
Adam Powell539ee872012-02-03 19:00:49 -08001133 @Override
1134 public boolean hasTransientState() {
1135 return mChildCountWithTransientState > 0 || super.hasTransientState();
1136 }
1137
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001138 @Override
1139 public boolean dispatchUnhandledMove(View focused, int direction) {
1140 return mFocused != null &&
1141 mFocused.dispatchUnhandledMove(focused, direction);
1142 }
1143
Alan Viverettebe463f22016-01-21 10:50:10 -05001144 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001145 public void clearChildFocus(View child) {
1146 if (DBG) {
1147 System.out.println(this + " clearChildFocus()");
1148 }
1149
1150 mFocused = null;
1151 if (mParent != null) {
1152 mParent.clearChildFocus(this);
1153 }
1154 }
1155
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001156 @Override
1157 public void clearFocus() {
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08001158 if (DBG) {
1159 System.out.println(this + " clearFocus()");
1160 }
1161 if (mFocused == null) {
1162 super.clearFocus();
1163 } else {
Svetoslav Ganovb552d892012-06-02 14:35:02 -07001164 View focused = mFocused;
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08001165 mFocused = null;
Svetoslav Ganovb552d892012-06-02 14:35:02 -07001166 focused.clearFocus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001167 }
1168 }
1169
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001170 @Override
Alan Viverette223622a2013-12-17 13:29:02 -08001171 void unFocus(View focused) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001172 if (DBG) {
1173 System.out.println(this + " unFocus()");
1174 }
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08001175 if (mFocused == null) {
Alan Viverette223622a2013-12-17 13:29:02 -08001176 super.unFocus(focused);
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08001177 } else {
Alan Viverette223622a2013-12-17 13:29:02 -08001178 mFocused.unFocus(focused);
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08001179 mFocused = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001180 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001181 }
1182
1183 /**
1184 * Returns the focused child of this view, if any. The child may have focus
1185 * or contain focus.
1186 *
1187 * @return the focused child or null.
1188 */
1189 public View getFocusedChild() {
1190 return mFocused;
1191 }
1192
Adam Powell88c11752014-07-21 17:19:16 -07001193 View getDeepestFocusedChild() {
1194 View v = this;
1195 while (v != null) {
1196 if (v.isFocused()) {
1197 return v;
1198 }
1199 v = v instanceof ViewGroup ? ((ViewGroup) v).getFocusedChild() : null;
1200 }
1201 return null;
1202 }
1203
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001204 /**
1205 * Returns true if this view has or contains focus
1206 *
1207 * @return true if this view has or contains focus
1208 */
1209 @Override
1210 public boolean hasFocus() {
Dianne Hackborn4702a852012-08-17 15:18:29 -07001211 return (mPrivateFlags & PFLAG_FOCUSED) != 0 || mFocused != null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001212 }
1213
1214 /*
1215 * (non-Javadoc)
1216 *
1217 * @see android.view.View#findFocus()
1218 */
1219 @Override
1220 public View findFocus() {
1221 if (DBG) {
1222 System.out.println("Find focus in " + this + ": flags="
1223 + isFocused() + ", child=" + mFocused);
1224 }
1225
1226 if (isFocused()) {
1227 return this;
1228 }
1229
1230 if (mFocused != null) {
1231 return mFocused.findFocus();
1232 }
1233 return null;
1234 }
1235
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001236 @Override
Adam Powell0f552f42017-02-03 11:50:42 -08001237 boolean hasFocusable(boolean allowAutoFocus, boolean dispatchExplicit) {
Alan Viverette7485a9b2017-02-27 11:55:53 -05001238 // This should probably be super.hasFocusable, but that would change
1239 // behavior. Historically, we have not checked the ancestor views for
1240 // shouldBlockFocusForTouchscreen() in ViewGroup.hasFocusable.
1241
1242 // Invisible and gone views are never focusable.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001243 if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) {
1244 return false;
1245 }
1246
Alan Viverette7485a9b2017-02-27 11:55:53 -05001247 // Only use effective focusable value when allowed.
1248 if ((allowAutoFocus || getFocusable() != FOCUSABLE_AUTO) && isFocusable()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001249 return true;
1250 }
1251
Alan Viverette7485a9b2017-02-27 11:55:53 -05001252 // Determine whether we have a focused descendant.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001253 final int descendantFocusability = getDescendantFocusability();
Adam Powell88c11752014-07-21 17:19:16 -07001254 if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) {
Evan Rosky2ae1bf52017-05-11 11:18:45 -07001255 return hasFocusableChild(dispatchExplicit);
1256 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001257
Evan Rosky2ae1bf52017-05-11 11:18:45 -07001258 return false;
1259 }
Adam Powell0f552f42017-02-03 11:50:42 -08001260
Evan Rosky2ae1bf52017-05-11 11:18:45 -07001261 boolean hasFocusableChild(boolean dispatchExplicit) {
1262 // Determine whether we have a focusable descendant.
1263 final int count = mChildrenCount;
1264 final View[] children = mChildren;
1265
1266 for (int i = 0; i < count; i++) {
1267 final View child = children[i];
1268
1269 // In case the subclass has overridden has[Explicit]Focusable, dispatch
1270 // to the expected one for each child even though we share logic here.
1271 if ((dispatchExplicit && child.hasExplicitFocusable())
1272 || (!dispatchExplicit && child.hasFocusable())) {
1273 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001274 }
1275 }
1276
1277 return false;
1278 }
1279
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001280 @Override
svetoslavganov75986cf2009-05-14 22:28:01 -07001281 public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001282 final int focusableCount = views.size();
1283
1284 final int descendantFocusability = getDescendantFocusability();
Evan Rosky18b886e2017-02-15 13:26:51 -08001285 final boolean blockFocusForTouchscreen = shouldBlockFocusForTouchscreen();
1286 final boolean focusSelf = (isFocusableInTouchMode() || !blockFocusForTouchscreen);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001287
Evan Rosky3b94bf52017-01-10 17:05:28 -08001288 if (descendantFocusability == FOCUS_BLOCK_DESCENDANTS) {
1289 if (focusSelf) {
1290 super.addFocusables(views, direction, focusableMode);
Adam Powell88c11752014-07-21 17:19:16 -07001291 }
Evan Rosky3b94bf52017-01-10 17:05:28 -08001292 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001293 }
1294
Evan Rosky18b886e2017-02-15 13:26:51 -08001295 if (blockFocusForTouchscreen) {
Evan Rosky3b94bf52017-01-10 17:05:28 -08001296 focusableMode |= FOCUSABLES_TOUCH_MODE;
1297 }
1298
1299 if ((descendantFocusability == FOCUS_BEFORE_DESCENDANTS) && focusSelf) {
1300 super.addFocusables(views, direction, focusableMode);
1301 }
1302
1303 int count = 0;
1304 final View[] children = new View[mChildrenCount];
1305 for (int i = 0; i < mChildrenCount; ++i) {
1306 View child = mChildren[i];
1307 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
1308 children[count++] = child;
1309 }
1310 }
Evan Roskyd114e0f2017-03-23 11:20:04 -07001311 FocusFinder.sort(children, 0, count, this, isLayoutRtl());
Evan Rosky3b94bf52017-01-10 17:05:28 -08001312 for (int i = 0; i < count; ++i) {
1313 children[i].addFocusables(views, direction, focusableMode);
1314 }
1315
1316 // When set to FOCUS_AFTER_DESCENDANTS, we only add ourselves if
1317 // there aren't any focusable descendants. this is
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001318 // to avoid the focus search finding layouts when a more precise search
1319 // among the focusable children would be more interesting.
Evan Rosky3b94bf52017-01-10 17:05:28 -08001320 if ((descendantFocusability == FOCUS_AFTER_DESCENDANTS) && focusSelf
1321 && focusableCount == views.size()) {
svetoslavganov75986cf2009-05-14 22:28:01 -07001322 super.addFocusables(views, direction, focusableMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001323 }
1324 }
1325
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08001326 @Override
Vadim Tryshevb5ced222017-01-17 19:31:35 -08001327 public void addKeyboardNavigationClusters(Collection<View> views, int direction) {
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08001328 final int focusableCount = views.size();
1329
Evan Rosky18b886e2017-02-15 13:26:51 -08001330 if (isKeyboardNavigationCluster()) {
1331 // Cluster-navigation can enter a touchscreenBlocksFocus cluster, so temporarily
1332 // disable touchscreenBlocksFocus to evaluate whether it contains focusables.
1333 final boolean blockedFocus = getTouchscreenBlocksFocus();
1334 try {
1335 setTouchscreenBlocksFocusNoRefocus(false);
1336 super.addKeyboardNavigationClusters(views, direction);
1337 } finally {
1338 setTouchscreenBlocksFocusNoRefocus(blockedFocus);
1339 }
1340 } else {
1341 super.addKeyboardNavigationClusters(views, direction);
1342 }
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08001343
1344 if (focusableCount != views.size()) {
Vadim Tryshev311a5b52017-01-05 18:54:11 -08001345 // No need to look for groups inside a group.
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08001346 return;
1347 }
1348
1349 if (getDescendantFocusability() == FOCUS_BLOCK_DESCENDANTS) {
1350 return;
1351 }
1352
Evan Roskybd10c522017-03-27 15:50:38 -07001353 int count = 0;
1354 final View[] visibleChildren = new View[mChildrenCount];
1355 for (int i = 0; i < mChildrenCount; ++i) {
1356 final View child = mChildren[i];
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08001357 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
Evan Roskybd10c522017-03-27 15:50:38 -07001358 visibleChildren[count++] = child;
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08001359 }
1360 }
Evan Roskyd114e0f2017-03-23 11:20:04 -07001361 FocusFinder.sort(visibleChildren, 0, count, this, isLayoutRtl());
Evan Roskybd10c522017-03-27 15:50:38 -07001362 for (int i = 0; i < count; ++i) {
1363 visibleChildren[i].addKeyboardNavigationClusters(views, direction);
1364 }
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08001365 }
1366
Adam Powellff0d2982014-07-10 20:34:14 -07001367 /**
1368 * Set whether this ViewGroup should ignore focus requests for itself and its children.
1369 * If this option is enabled and the ViewGroup or a descendant currently has focus, focus
1370 * will proceed forward.
1371 *
1372 * @param touchscreenBlocksFocus true to enable blocking focus in the presence of a touchscreen
1373 */
1374 public void setTouchscreenBlocksFocus(boolean touchscreenBlocksFocus) {
1375 if (touchscreenBlocksFocus) {
1376 mGroupFlags |= FLAG_TOUCHSCREEN_BLOCKS_FOCUS;
Evan Rosky0e8a6832017-04-10 12:35:15 -07001377 if (hasFocus() && !isKeyboardNavigationCluster()) {
Adam Powell88c11752014-07-21 17:19:16 -07001378 final View focusedChild = getDeepestFocusedChild();
1379 if (!focusedChild.isFocusableInTouchMode()) {
1380 final View newFocus = focusSearch(FOCUS_FORWARD);
1381 if (newFocus != null) {
1382 newFocus.requestFocus();
1383 }
Adam Powellff0d2982014-07-10 20:34:14 -07001384 }
1385 }
1386 } else {
1387 mGroupFlags &= ~FLAG_TOUCHSCREEN_BLOCKS_FOCUS;
1388 }
1389 }
1390
Evan Rosky18b886e2017-02-15 13:26:51 -08001391 private void setTouchscreenBlocksFocusNoRefocus(boolean touchscreenBlocksFocus) {
1392 if (touchscreenBlocksFocus) {
1393 mGroupFlags |= FLAG_TOUCHSCREEN_BLOCKS_FOCUS;
1394 } else {
1395 mGroupFlags &= ~FLAG_TOUCHSCREEN_BLOCKS_FOCUS;
1396 }
1397 }
1398
Adam Powellff0d2982014-07-10 20:34:14 -07001399 /**
1400 * Check whether this ViewGroup should ignore focus requests for itself and its children.
1401 */
Evan Roskyecb63fc2017-04-13 16:57:18 -07001402 @ViewDebug.ExportedProperty(category = "focus")
Ashley Rose55f9f922019-01-28 19:29:36 -05001403 @InspectableProperty
Adam Powellff0d2982014-07-10 20:34:14 -07001404 public boolean getTouchscreenBlocksFocus() {
1405 return (mGroupFlags & FLAG_TOUCHSCREEN_BLOCKS_FOCUS) != 0;
1406 }
1407
1408 boolean shouldBlockFocusForTouchscreen() {
Evan Rosky18b886e2017-02-15 13:26:51 -08001409 // There is a special case for keyboard-navigation clusters. We allow cluster navigation
1410 // to jump into blockFocusForTouchscreen ViewGroups which are clusters. Once in the
1411 // cluster, focus is free to move around within it.
Adam Powellff0d2982014-07-10 20:34:14 -07001412 return getTouchscreenBlocksFocus() &&
Evan Rosky18b886e2017-02-15 13:26:51 -08001413 mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN)
Evan Rosky0e8a6832017-04-10 12:35:15 -07001414 && !(isKeyboardNavigationCluster()
1415 && (hasFocus() || (findKeyboardNavigationCluster() != this)));
Adam Powellff0d2982014-07-10 20:34:14 -07001416 }
1417
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001418 @Override
Svetoslav Ganovea515ae2011-09-14 18:15:32 -07001419 public void findViewsWithText(ArrayList<View> outViews, CharSequence text, int flags) {
1420 super.findViewsWithText(outViews, text, flags);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001421 final int childrenCount = mChildrenCount;
1422 final View[] children = mChildren;
1423 for (int i = 0; i < childrenCount; i++) {
1424 View child = children[i];
Svetoslav Ganovea515ae2011-09-14 18:15:32 -07001425 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE
Dianne Hackborn4702a852012-08-17 15:18:29 -07001426 && (child.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
Svetoslav Ganovea515ae2011-09-14 18:15:32 -07001427 child.findViewsWithText(outViews, text, flags);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001428 }
1429 }
1430 }
1431
Svetoslav5b578da2013-05-08 14:23:32 -07001432 /** @hide */
Svetoslav Ganov2cdedff2011-10-03 14:18:42 -07001433 @Override
Svetoslav5b578da2013-05-08 14:23:32 -07001434 public View findViewByAccessibilityIdTraversal(int accessibilityId) {
Svetoslav Ganov2cdedff2011-10-03 14:18:42 -07001435 View foundView = super.findViewByAccessibilityIdTraversal(accessibilityId);
1436 if (foundView != null) {
1437 return foundView;
1438 }
Svetoslav6cc46272015-06-03 11:38:30 -07001439
1440 if (getAccessibilityNodeProvider() != null) {
1441 return null;
1442 }
1443
Svetoslav Ganov2cdedff2011-10-03 14:18:42 -07001444 final int childrenCount = mChildrenCount;
1445 final View[] children = mChildren;
1446 for (int i = 0; i < childrenCount; i++) {
1447 View child = children[i];
1448 foundView = child.findViewByAccessibilityIdTraversal(accessibilityId);
1449 if (foundView != null) {
1450 return foundView;
1451 }
1452 }
Svetoslav6cc46272015-06-03 11:38:30 -07001453
Svetoslav Ganov2cdedff2011-10-03 14:18:42 -07001454 return null;
1455 }
1456
Phil Weaver846cda932017-06-15 10:10:06 -07001457 /** @hide */
1458 @Override
1459 public View findViewByAutofillIdTraversal(int autofillId) {
1460 View foundView = super.findViewByAutofillIdTraversal(autofillId);
1461 if (foundView != null) {
1462 return foundView;
1463 }
1464
1465 final int childrenCount = mChildrenCount;
1466 final View[] children = mChildren;
1467 for (int i = 0; i < childrenCount; i++) {
1468 View child = children[i];
1469 foundView = child.findViewByAutofillIdTraversal(autofillId);
1470 if (foundView != null) {
1471 return foundView;
1472 }
1473 }
1474
1475 return null;
1476 }
1477
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001478 @Override
1479 public void dispatchWindowFocusChanged(boolean hasFocus) {
1480 super.dispatchWindowFocusChanged(hasFocus);
1481 final int count = mChildrenCount;
1482 final View[] children = mChildren;
1483 for (int i = 0; i < count; i++) {
1484 children[i].dispatchWindowFocusChanged(hasFocus);
1485 }
1486 }
1487
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001488 @Override
1489 public void addTouchables(ArrayList<View> views) {
1490 super.addTouchables(views);
1491
1492 final int count = mChildrenCount;
1493 final View[] children = mChildren;
1494
1495 for (int i = 0; i < count; i++) {
1496 final View child = children[i];
1497 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
1498 child.addTouchables(views);
1499 }
1500 }
1501 }
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001502
1503 /**
1504 * @hide
1505 */
1506 @Override
Mathew Inwooda570dee2018-08-17 14:56:00 +01001507 @UnsupportedAppUsage
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001508 public void makeOptionalFitsSystemWindows() {
1509 super.makeOptionalFitsSystemWindows();
1510 final int count = mChildrenCount;
1511 final View[] children = mChildren;
1512 for (int i = 0; i < count; i++) {
1513 children[i].makeOptionalFitsSystemWindows();
1514 }
1515 }
1516
Romain Guy43c9cdf2010-01-27 13:53:55 -08001517 @Override
1518 public void dispatchDisplayHint(int hint) {
1519 super.dispatchDisplayHint(hint);
1520 final int count = mChildrenCount;
1521 final View[] children = mChildren;
1522 for (int i = 0; i < count; i++) {
1523 children[i].dispatchDisplayHint(hint);
1524 }
1525 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001526
1527 /**
Chet Haase0d299362012-01-26 10:51:48 -08001528 * Called when a view's visibility has changed. Notify the parent to take any appropriate
1529 * action.
1530 *
1531 * @param child The view whose visibility has changed
1532 * @param oldVisibility The previous visibility value (GONE, INVISIBLE, or VISIBLE).
1533 * @param newVisibility The new visibility value (GONE, INVISIBLE, or VISIBLE).
Chet Haase5e25c2c2010-09-16 11:15:56 -07001534 * @hide
Chet Haase5e25c2c2010-09-16 11:15:56 -07001535 */
Mathew Inwooda570dee2018-08-17 14:56:00 +01001536 @UnsupportedAppUsage
Chet Haase0d299362012-01-26 10:51:48 -08001537 protected void onChildVisibilityChanged(View child, int oldVisibility, int newVisibility) {
Chet Haase5e25c2c2010-09-16 11:15:56 -07001538 if (mTransition != null) {
Chet Haase0d299362012-01-26 10:51:48 -08001539 if (newVisibility == VISIBLE) {
1540 mTransition.showChild(this, child, oldVisibility);
Chet Haase5e25c2c2010-09-16 11:15:56 -07001541 } else {
Chet Haase0d299362012-01-26 10:51:48 -08001542 mTransition.hideChild(this, child, newVisibility);
Chet Haase5e25c2c2010-09-16 11:15:56 -07001543 if (mTransitioningViews != null && mTransitioningViews.contains(child)) {
Chet Haaseddbb3462012-06-19 13:54:29 -07001544 // Only track this on disappearing views - appearing views are already visible
1545 // and don't need special handling during drawChild()
1546 if (mVisibilityChangingChildren == null) {
1547 mVisibilityChangingChildren = new ArrayList<View>();
1548 }
1549 mVisibilityChangingChildren.add(child);
Chet Haase5e25c2c2010-09-16 11:15:56 -07001550 addDisappearingView(child);
1551 }
1552 }
1553 }
Christopher Tate86cab1b2011-01-13 20:28:55 -08001554
1555 // in all cases, for drags
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001556 if (newVisibility == VISIBLE && mCurrentDragStartEvent != null) {
1557 if (!mChildrenInterestedInDrag.contains(child)) {
1558 notifyChildOfDragStart(child);
Christopher Tate86cab1b2011-01-13 20:28:55 -08001559 }
1560 }
Chet Haase5e25c2c2010-09-16 11:15:56 -07001561 }
1562
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001563 @Override
Adam Powell326d8082009-12-09 15:10:07 -08001564 protected void dispatchVisibilityChanged(View changedView, int visibility) {
1565 super.dispatchVisibilityChanged(changedView, visibility);
1566 final int count = mChildrenCount;
1567 final View[] children = mChildren;
1568 for (int i = 0; i < count; i++) {
1569 children[i].dispatchVisibilityChanged(changedView, visibility);
1570 }
1571 }
1572
Adam Powell326d8082009-12-09 15:10:07 -08001573 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001574 public void dispatchWindowVisibilityChanged(int visibility) {
1575 super.dispatchWindowVisibilityChanged(visibility);
1576 final int count = mChildrenCount;
1577 final View[] children = mChildren;
1578 for (int i = 0; i < count; i++) {
1579 children[i].dispatchWindowVisibilityChanged(visibility);
1580 }
1581 }
1582
Dianne Hackborne36d6e22010-02-17 19:46:25 -08001583 @Override
Adam Powell9c146bf2016-03-15 17:35:00 -07001584 boolean dispatchVisibilityAggregated(boolean isVisible) {
1585 isVisible = super.dispatchVisibilityAggregated(isVisible);
Adam Powell41d96902016-03-15 14:43:19 -07001586 final int count = mChildrenCount;
1587 final View[] children = mChildren;
1588 for (int i = 0; i < count; i++) {
Adam Powell9c146bf2016-03-15 17:35:00 -07001589 // Only dispatch to visible children. Not visible children and their subtrees already
1590 // know that they aren't visible and that's not going to change as a result of
1591 // whatever triggered this dispatch.
1592 if (children[i].getVisibility() == VISIBLE) {
1593 children[i].dispatchVisibilityAggregated(isVisible);
Adam Powell41d96902016-03-15 14:43:19 -07001594 }
1595 }
Adam Powell9c146bf2016-03-15 17:35:00 -07001596 return isVisible;
Adam Powell41d96902016-03-15 14:43:19 -07001597 }
1598
1599 @Override
Dianne Hackborne36d6e22010-02-17 19:46:25 -08001600 public void dispatchConfigurationChanged(Configuration newConfig) {
1601 super.dispatchConfigurationChanged(newConfig);
1602 final int count = mChildrenCount;
1603 final View[] children = mChildren;
1604 for (int i = 0; i < count; i++) {
1605 children[i].dispatchConfigurationChanged(newConfig);
1606 }
1607 }
Filip Gruszczynskia33bdf32015-11-19 18:22:16 -08001608
Alan Viverettebe463f22016-01-21 10:50:10 -05001609 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001610 public void recomputeViewAttributes(View child) {
Joe Onorato664644d2011-01-23 17:53:23 -08001611 if (mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) {
1612 ViewParent parent = mParent;
1613 if (parent != null) parent.recomputeViewAttributes(this);
1614 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001615 }
Romain Guy8506ab42009-06-11 17:35:47 -07001616
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001617 @Override
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001618 void dispatchCollectViewAttributes(AttachInfo attachInfo, int visibility) {
1619 if ((visibility & VISIBILITY_MASK) == VISIBLE) {
1620 super.dispatchCollectViewAttributes(attachInfo, visibility);
1621 final int count = mChildrenCount;
1622 final View[] children = mChildren;
1623 for (int i = 0; i < count; i++) {
1624 final View child = children[i];
1625 child.dispatchCollectViewAttributes(attachInfo,
1626 visibility | (child.mViewFlags&VISIBILITY_MASK));
1627 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001628 }
1629 }
1630
Alan Viverettebe463f22016-01-21 10:50:10 -05001631 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001632 public void bringChildToFront(View child) {
Alan Viverette77bb6f12015-02-11 17:24:33 -08001633 final int index = indexOfChild(child);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001634 if (index >= 0) {
1635 removeFromArray(index);
1636 addInArray(child, mChildrenCount);
1637 child.mParent = this;
Chet Haasecb96db82013-09-04 10:21:46 -07001638 requestLayout();
1639 invalidate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001640 }
1641 }
1642
Romain Guy6410c0a2013-06-17 11:21:58 -07001643 private PointF getLocalPoint() {
1644 if (mLocalPoint == null) mLocalPoint = new PointF();
1645 return mLocalPoint;
1646 }
1647
Vadim Tryshevef128112016-09-16 14:05:53 -07001648 @Override
1649 boolean dispatchDragEnterExitInPreN(DragEvent event) {
1650 if (event.mAction == DragEvent.ACTION_DRAG_EXITED && mCurrentDragChild != null) {
1651 // The drag exited a sub-tree of views; notify of the exit all descendants that are in
1652 // entered state.
1653 // We don't need this recursive delivery for ENTERED events because they get generated
1654 // from the recursive delivery of LOCATION/DROP events, and hence, don't need their own
1655 // recursion.
1656 mCurrentDragChild.dispatchDragEnterExitInPreN(event);
1657 mCurrentDragChild = null;
1658 }
1659 return mIsInterestedInDrag && super.dispatchDragEnterExitInPreN(event);
1660 }
1661
Steve Block8a7259b2012-03-01 11:24:41 +00001662 // TODO: Write real docs
Christopher Tatea53146c2010-09-07 11:57:52 -07001663 @Override
1664 public boolean dispatchDragEvent(DragEvent event) {
1665 boolean retval = false;
1666 final float tx = event.mX;
1667 final float ty = event.mY;
Vadim Trysheva61efa42016-09-28 15:15:52 -07001668 final ClipData td = event.mClipData;
Christopher Tatea53146c2010-09-07 11:57:52 -07001669
Christopher Tatea53146c2010-09-07 11:57:52 -07001670 // Dispatch down the view hierarchy
Romain Guy6410c0a2013-06-17 11:21:58 -07001671 final PointF localPoint = getLocalPoint();
1672
Christopher Tatea53146c2010-09-07 11:57:52 -07001673 switch (event.mAction) {
1674 case DragEvent.ACTION_DRAG_STARTED: {
Vadim Tryshevef128112016-09-16 14:05:53 -07001675 // Clear the state to recalculate which views we drag over.
1676 mCurrentDragChild = null;
1677
Christopher Tate86cab1b2011-01-13 20:28:55 -08001678 // Set up our tracking of drag-started notifications
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001679 mCurrentDragStartEvent = DragEvent.obtain(event);
1680 if (mChildrenInterestedInDrag == null) {
1681 mChildrenInterestedInDrag = new HashSet<View>();
Christopher Tate86cab1b2011-01-13 20:28:55 -08001682 } else {
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001683 mChildrenInterestedInDrag.clear();
Christopher Tate86cab1b2011-01-13 20:28:55 -08001684 }
1685
Christopher Tatea53146c2010-09-07 11:57:52 -07001686 // Now dispatch down to our children, caching the responses
Christopher Tatea53146c2010-09-07 11:57:52 -07001687 final int count = mChildrenCount;
1688 final View[] children = mChildren;
1689 for (int i = 0; i < count; i++) {
Christopher Tate2c095f32010-10-04 14:13:40 -07001690 final View child = children[i];
Christopher Tate3d4bf172011-03-28 16:16:46 -07001691 child.mPrivateFlags2 &= ~View.DRAG_MASK;
Christopher Tate2c095f32010-10-04 14:13:40 -07001692 if (child.getVisibility() == VISIBLE) {
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001693 if (notifyChildOfDragStart(children[i])) {
1694 retval = true;
Christopher Tate2c095f32010-10-04 14:13:40 -07001695 }
Christopher Tatea53146c2010-09-07 11:57:52 -07001696 }
1697 }
1698
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001699 // Notify itself of the drag start.
1700 mIsInterestedInDrag = super.dispatchDragEvent(event);
1701 if (mIsInterestedInDrag) {
Christopher Tatea53146c2010-09-07 11:57:52 -07001702 retval = true;
1703 }
Yorke Lee0394b212016-03-10 18:20:04 -08001704
1705 if (!retval) {
1706 // Neither us nor any of our children are interested in this drag, so stop tracking
1707 // the current drag event.
1708 mCurrentDragStartEvent.recycle();
1709 mCurrentDragStartEvent = null;
1710 }
Christopher Tatea53146c2010-09-07 11:57:52 -07001711 } break;
1712
1713 case DragEvent.ACTION_DRAG_ENDED: {
Christopher Tate86cab1b2011-01-13 20:28:55 -08001714 // Release the bookkeeping now that the drag lifecycle has ended
Vadim Tryshev15177892015-12-18 08:01:00 -08001715 final HashSet<View> childrenInterestedInDrag = mChildrenInterestedInDrag;
1716 if (childrenInterestedInDrag != null) {
1717 for (View child : childrenInterestedInDrag) {
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001718 // If a child was interested in the ongoing drag, it's told that it's over
1719 if (child.dispatchDragEvent(event)) {
1720 retval = true;
1721 }
Christopher Tate1fc014f2011-01-19 12:56:26 -08001722 }
Vadim Tryshev15177892015-12-18 08:01:00 -08001723 childrenInterestedInDrag.clear();
1724 }
1725 if (mCurrentDragStartEvent != null) {
1726 mCurrentDragStartEvent.recycle();
1727 mCurrentDragStartEvent = null;
Christopher Tate1fc014f2011-01-19 12:56:26 -08001728 }
Christopher Tate86cab1b2011-01-13 20:28:55 -08001729
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001730 if (mIsInterestedInDrag) {
1731 if (super.dispatchDragEvent(event)) {
1732 retval = true;
1733 }
1734 mIsInterestedInDrag = false;
Christopher Tatea53146c2010-09-07 11:57:52 -07001735 }
1736 } break;
1737
Vadim Tryshev1edc6daf2016-09-15 16:19:15 -07001738 case DragEvent.ACTION_DRAG_LOCATION:
1739 case DragEvent.ACTION_DROP: {
Christopher Tatea53146c2010-09-07 11:57:52 -07001740 // Find the [possibly new] drag target
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001741 View target = findFrontmostDroppableChildAt(event.mX, event.mY, localPoint);
Vadim Tryshevef128112016-09-16 14:05:53 -07001742
1743 if (target != mCurrentDragChild) {
Vadim Tryshev45bee6b2016-09-19 11:00:37 -07001744 if (sCascadedDragDrop) {
Vadim Tryshevef128112016-09-16 14:05:53 -07001745 // For pre-Nougat apps, make sure that the whole hierarchy of views that contain
1746 // the drag location is kept in the state between ENTERED and EXITED events.
1747 // (Starting with N, only the innermost view will be in that state).
1748
1749 final int action = event.mAction;
1750 // Position should not be available for ACTION_DRAG_ENTERED and
1751 // ACTION_DRAG_EXITED.
1752 event.mX = 0;
1753 event.mY = 0;
Vadim Trysheva61efa42016-09-28 15:15:52 -07001754 event.mClipData = null;
Vadim Tryshevef128112016-09-16 14:05:53 -07001755
1756 if (mCurrentDragChild != null) {
1757 event.mAction = DragEvent.ACTION_DRAG_EXITED;
1758 mCurrentDragChild.dispatchDragEnterExitInPreN(event);
1759 }
1760
1761 if (target != null) {
1762 event.mAction = DragEvent.ACTION_DRAG_ENTERED;
1763 target.dispatchDragEnterExitInPreN(event);
1764 }
1765
1766 event.mAction = action;
1767 event.mX = tx;
1768 event.mY = ty;
Vadim Trysheva61efa42016-09-28 15:15:52 -07001769 event.mClipData = td;
Vadim Tryshevef128112016-09-16 14:05:53 -07001770 }
1771 mCurrentDragChild = target;
1772 }
1773
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001774 if (target == null && mIsInterestedInDrag) {
1775 target = this;
1776 }
Christopher Tatea53146c2010-09-07 11:57:52 -07001777
Vadim Tryshev1edc6daf2016-09-15 16:19:15 -07001778 // Dispatch the actual drag notice, localized into the target coordinates.
Christopher Tatea53146c2010-09-07 11:57:52 -07001779 if (target != null) {
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001780 if (target != this) {
1781 event.mX = localPoint.x;
1782 event.mY = localPoint.y;
Christopher Tatea53146c2010-09-07 11:57:52 -07001783
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001784 retval = target.dispatchDragEvent(event);
Christopher Tatea53146c2010-09-07 11:57:52 -07001785
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001786 event.mX = tx;
1787 event.mY = ty;
Vadim Tryshev1edc6daf2016-09-15 16:19:15 -07001788
Vadim Tryshev45bee6b2016-09-19 11:00:37 -07001789 if (mIsInterestedInDrag) {
1790 final boolean eventWasConsumed;
1791 if (sCascadedDragDrop) {
1792 eventWasConsumed = retval;
1793 } else {
1794 eventWasConsumed = event.mEventHandlerWasCalled;
1795 }
1796
1797 if (!eventWasConsumed) {
1798 retval = super.dispatchDragEvent(event);
1799 }
Vadim Tryshev1edc6daf2016-09-15 16:19:15 -07001800 }
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001801 } else {
1802 retval = super.dispatchDragEvent(event);
1803 }
Christopher Tatea53146c2010-09-07 11:57:52 -07001804 }
1805 } break;
Christopher Tatea53146c2010-09-07 11:57:52 -07001806 }
1807
Christopher Tatea53146c2010-09-07 11:57:52 -07001808 return retval;
1809 }
1810
1811 // Find the frontmost child view that lies under the given point, and calculate
1812 // the position within its own local coordinate system.
1813 View findFrontmostDroppableChildAt(float x, float y, PointF outLocalPoint) {
Christopher Tatea53146c2010-09-07 11:57:52 -07001814 final int count = mChildrenCount;
1815 final View[] children = mChildren;
1816 for (int i = count - 1; i >= 0; i--) {
1817 final View child = children[i];
Christopher Tate3d4bf172011-03-28 16:16:46 -07001818 if (!child.canAcceptDrag()) {
Christopher Tatea53146c2010-09-07 11:57:52 -07001819 continue;
1820 }
1821
Christopher Tate2c095f32010-10-04 14:13:40 -07001822 if (isTransformedTouchPointInView(x, y, child, outLocalPoint)) {
Christopher Tatea53146c2010-09-07 11:57:52 -07001823 return child;
1824 }
1825 }
1826 return null;
1827 }
1828
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001829 boolean notifyChildOfDragStart(View child) {
1830 // The caller guarantees that the child is not in mChildrenInterestedInDrag yet.
1831
Christopher Tate86cab1b2011-01-13 20:28:55 -08001832 if (ViewDebug.DEBUG_DRAG) {
1833 Log.d(View.VIEW_LOG_TAG, "Sending drag-started to view: " + child);
1834 }
1835
Vladislav Kaznacheevc2449702016-05-16 12:57:15 -07001836 final float tx = mCurrentDragStartEvent.mX;
1837 final float ty = mCurrentDragStartEvent.mY;
1838
1839 final float[] point = getTempPoint();
1840 point[0] = tx;
1841 point[1] = ty;
1842 transformPointToViewLocal(point, child);
1843
1844 mCurrentDragStartEvent.mX = point[0];
1845 mCurrentDragStartEvent.mY = point[1];
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001846 final boolean canAccept = child.dispatchDragEvent(mCurrentDragStartEvent);
Vladislav Kaznacheevc2449702016-05-16 12:57:15 -07001847 mCurrentDragStartEvent.mX = tx;
1848 mCurrentDragStartEvent.mY = ty;
Vadim Tryshev1edc6daf2016-09-15 16:19:15 -07001849 mCurrentDragStartEvent.mEventHandlerWasCalled = false;
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001850 if (canAccept) {
1851 mChildrenInterestedInDrag.add(child);
1852 if (!child.canAcceptDrag()) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07001853 child.mPrivateFlags2 |= View.PFLAG2_DRAG_CAN_ACCEPT;
Christopher Tate3d4bf172011-03-28 16:16:46 -07001854 child.refreshDrawableState();
1855 }
Christopher Tate86cab1b2011-01-13 20:28:55 -08001856 }
Christopher Tate3d4bf172011-03-28 16:16:46 -07001857 return canAccept;
Christopher Tate86cab1b2011-01-13 20:28:55 -08001858 }
1859
Joe Onorato664644d2011-01-23 17:53:23 -08001860 @Override
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001861 public void dispatchWindowSystemUiVisiblityChanged(int visible) {
1862 super.dispatchWindowSystemUiVisiblityChanged(visible);
1863
1864 final int count = mChildrenCount;
1865 final View[] children = mChildren;
1866 for (int i=0; i <count; i++) {
1867 final View child = children[i];
1868 child.dispatchWindowSystemUiVisiblityChanged(visible);
1869 }
1870 }
1871
1872 @Override
Joe Onorato664644d2011-01-23 17:53:23 -08001873 public void dispatchSystemUiVisibilityChanged(int visible) {
1874 super.dispatchSystemUiVisibilityChanged(visible);
1875
1876 final int count = mChildrenCount;
1877 final View[] children = mChildren;
1878 for (int i=0; i <count; i++) {
1879 final View child = children[i];
1880 child.dispatchSystemUiVisibilityChanged(visible);
1881 }
1882 }
1883
Dianne Hackborn9a230e02011-10-06 11:51:27 -07001884 @Override
Dianne Hackborncf675782012-05-10 15:07:24 -07001885 boolean updateLocalSystemUiVisibility(int localValue, int localChanges) {
1886 boolean changed = super.updateLocalSystemUiVisibility(localValue, localChanges);
Dianne Hackborn9a230e02011-10-06 11:51:27 -07001887
1888 final int count = mChildrenCount;
1889 final View[] children = mChildren;
1890 for (int i=0; i <count; i++) {
1891 final View child = children[i];
Dianne Hackborncf675782012-05-10 15:07:24 -07001892 changed |= child.updateLocalSystemUiVisibility(localValue, localChanges);
Dianne Hackborn9a230e02011-10-06 11:51:27 -07001893 }
Dianne Hackborncf675782012-05-10 15:07:24 -07001894 return changed;
Dianne Hackborn9a230e02011-10-06 11:51:27 -07001895 }
1896
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001897 @Override
1898 public boolean dispatchKeyEventPreIme(KeyEvent event) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07001899 if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
1900 == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001901 return super.dispatchKeyEventPreIme(event);
Dianne Hackborn4702a852012-08-17 15:18:29 -07001902 } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
1903 == PFLAG_HAS_BOUNDS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001904 return mFocused.dispatchKeyEventPreIme(event);
1905 }
1906 return false;
1907 }
1908
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001909 @Override
1910 public boolean dispatchKeyEvent(KeyEvent event) {
Jeff Brown21bc5c92011-02-28 18:27:14 -08001911 if (mInputEventConsistencyVerifier != null) {
1912 mInputEventConsistencyVerifier.onKeyEvent(event, 1);
1913 }
1914
Dianne Hackborn4702a852012-08-17 15:18:29 -07001915 if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
1916 == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001917 if (super.dispatchKeyEvent(event)) {
1918 return true;
1919 }
Dianne Hackborn4702a852012-08-17 15:18:29 -07001920 } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
1921 == PFLAG_HAS_BOUNDS) {
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001922 if (mFocused.dispatchKeyEvent(event)) {
1923 return true;
1924 }
1925 }
1926
1927 if (mInputEventConsistencyVerifier != null) {
1928 mInputEventConsistencyVerifier.onUnhandledEvent(event, 1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001929 }
1930 return false;
1931 }
1932
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001933 @Override
1934 public boolean dispatchKeyShortcutEvent(KeyEvent event) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07001935 if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
1936 == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001937 return super.dispatchKeyShortcutEvent(event);
Dianne Hackborn4702a852012-08-17 15:18:29 -07001938 } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
1939 == PFLAG_HAS_BOUNDS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001940 return mFocused.dispatchKeyShortcutEvent(event);
1941 }
1942 return false;
1943 }
1944
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001945 @Override
1946 public boolean dispatchTrackballEvent(MotionEvent event) {
Jeff Brown21bc5c92011-02-28 18:27:14 -08001947 if (mInputEventConsistencyVerifier != null) {
1948 mInputEventConsistencyVerifier.onTrackballEvent(event, 1);
1949 }
1950
Dianne Hackborn4702a852012-08-17 15:18:29 -07001951 if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
1952 == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001953 if (super.dispatchTrackballEvent(event)) {
1954 return true;
1955 }
Dianne Hackborn4702a852012-08-17 15:18:29 -07001956 } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
1957 == PFLAG_HAS_BOUNDS) {
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001958 if (mFocused.dispatchTrackballEvent(event)) {
1959 return true;
1960 }
1961 }
1962
1963 if (mInputEventConsistencyVerifier != null) {
1964 mInputEventConsistencyVerifier.onUnhandledEvent(event, 1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001965 }
1966 return false;
1967 }
1968
Jun Mukai1db53972015-09-11 18:08:31 -07001969 @Override
Vladislav Kaznacheev3787de12016-12-21 10:36:35 -08001970 public boolean dispatchCapturedPointerEvent(MotionEvent event) {
1971 if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
1972 == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
1973 if (super.dispatchCapturedPointerEvent(event)) {
1974 return true;
1975 }
1976 } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
1977 == PFLAG_HAS_BOUNDS) {
1978 if (mFocused.dispatchCapturedPointerEvent(event)) {
1979 return true;
1980 }
1981 }
1982 return false;
1983 }
1984
1985 @Override
1986 public void dispatchPointerCaptureChanged(boolean hasCapture) {
1987 exitHoverTargets();
1988
1989 super.dispatchPointerCaptureChanged(hasCapture);
1990 final int count = mChildrenCount;
1991 final View[] children = mChildren;
1992 for (int i = 0; i < count; i++) {
1993 children[i].dispatchPointerCaptureChanged(hasCapture);
1994 }
1995 }
1996
1997 @Override
Michael Wrighte051f6f2016-05-13 17:44:16 +01001998 public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) {
1999 final float x = event.getX(pointerIndex);
2000 final float y = event.getY(pointerIndex);
Keisuke Kuroyanagid85bc502016-01-21 14:50:38 +09002001 if (isOnScrollbarThumb(x, y) || isDraggingScrollBar()) {
Michael Wrighte051f6f2016-05-13 17:44:16 +01002002 return PointerIcon.getSystemIcon(mContext, PointerIcon.TYPE_ARROW);
Keisuke Kuroyanagid85bc502016-01-21 14:50:38 +09002003 }
Jun Mukai1db53972015-09-11 18:08:31 -07002004 // Check what the child under the pointer says about the pointer.
2005 final int childrenCount = mChildrenCount;
2006 if (childrenCount != 0) {
2007 final ArrayList<View> preorderedList = buildOrderedChildList();
2008 final boolean customOrder = preorderedList == null
2009 && isChildrenDrawingOrderEnabled();
2010 final View[] children = mChildren;
2011 for (int i = childrenCount - 1; i >= 0; i--) {
Alan Viverettea7b85e62016-01-22 10:14:02 -05002012 final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
2013 final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);
Vladislav Kaznacheev3d5cfc02017-01-05 17:50:38 -08002014 if (!canViewReceivePointerEvents(child)
2015 || !isTransformedTouchPointInView(x, y, child, null)) {
2016 continue;
2017 }
2018 final PointerIcon pointerIcon =
2019 dispatchResolvePointerIcon(event, pointerIndex, child);
2020 if (pointerIcon != null) {
2021 if (preorderedList != null) preorderedList.clear();
2022 return pointerIcon;
Jun Mukai1db53972015-09-11 18:08:31 -07002023 }
2024 }
Chris Craikfc563772016-05-04 13:34:30 -07002025 if (preorderedList != null) preorderedList.clear();
Jun Mukai1db53972015-09-11 18:08:31 -07002026 }
2027
2028 // The pointer is not a child or the child has no preferences, returning the default
2029 // implementation.
Michael Wrighte051f6f2016-05-13 17:44:16 +01002030 return super.onResolvePointerIcon(event, pointerIndex);
2031 }
2032
2033 private PointerIcon dispatchResolvePointerIcon(MotionEvent event, int pointerIndex,
2034 View child) {
2035 final PointerIcon pointerIcon;
2036 if (!child.hasIdentityMatrix()) {
2037 MotionEvent transformedEvent = getTransformedMotionEvent(event, child);
2038 pointerIcon = child.onResolvePointerIcon(transformedEvent, pointerIndex);
2039 transformedEvent.recycle();
2040 } else {
2041 final float offsetX = mScrollX - child.mLeft;
2042 final float offsetY = mScrollY - child.mTop;
2043 event.offsetLocation(offsetX, offsetY);
2044 pointerIcon = child.onResolvePointerIcon(event, pointerIndex);
2045 event.offsetLocation(-offsetX, -offsetY);
2046 }
2047 return pointerIcon;
Jun Mukai1db53972015-09-11 18:08:31 -07002048 }
2049
Alan Viverettea7b85e62016-01-22 10:14:02 -05002050 private int getAndVerifyPreorderedIndex(int childrenCount, int i, boolean customOrder) {
2051 final int childIndex;
2052 if (customOrder) {
2053 final int childIndex1 = getChildDrawingOrder(childrenCount, i);
2054 if (childIndex1 >= childrenCount) {
2055 throw new IndexOutOfBoundsException("getChildDrawingOrder() "
2056 + "returned invalid index " + childIndex1
2057 + " (child count is " + childrenCount + ")");
2058 }
2059 childIndex = childIndex1;
2060 } else {
2061 childIndex = i;
2062 }
2063 return childIndex;
2064 }
2065
Romain Guya9489272011-06-22 20:58:11 -07002066 @SuppressWarnings({"ConstantConditions"})
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002067 @Override
Jeff Browna032cc02011-03-07 16:56:21 -08002068 protected boolean dispatchHoverEvent(MotionEvent event) {
Jeff Browna032cc02011-03-07 16:56:21 -08002069 final int action = event.getAction();
Jeff Browna032cc02011-03-07 16:56:21 -08002070
Jeff Brown10b62902011-06-20 16:40:37 -07002071 // First check whether the view group wants to intercept the hover event.
2072 final boolean interceptHover = onInterceptHoverEvent(event);
2073 event.setAction(action); // restore action in case it was changed
2074
Jeff Brown87b7f802011-06-21 18:35:45 -07002075 MotionEvent eventNoHistory = event;
2076 boolean handled = false;
2077
2078 // Send events to the hovered children and build a new list of hover targets until
2079 // one is found that handles the event.
2080 HoverTarget firstOldHoverTarget = mFirstHoverTarget;
2081 mFirstHoverTarget = null;
Jeff Brown10b62902011-06-20 16:40:37 -07002082 if (!interceptHover && action != MotionEvent.ACTION_HOVER_EXIT) {
Jeff Browna032cc02011-03-07 16:56:21 -08002083 final float x = event.getX();
2084 final float y = event.getY();
Jeff Brown33bbfd22011-02-24 20:55:35 -08002085 final int childrenCount = mChildrenCount;
2086 if (childrenCount != 0) {
Chris Craikab008f02014-05-23 17:55:03 -07002087 final ArrayList<View> preorderedList = buildOrderedChildList();
2088 final boolean customOrder = preorderedList == null
2089 && isChildrenDrawingOrderEnabled();
Jeff Brown33bbfd22011-02-24 20:55:35 -08002090 final View[] children = mChildren;
Jeff Brown87b7f802011-06-21 18:35:45 -07002091 HoverTarget lastHoverTarget = null;
Jeff Brown33bbfd22011-02-24 20:55:35 -08002092 for (int i = childrenCount - 1; i >= 0; i--) {
Alan Viverettea7b85e62016-01-22 10:14:02 -05002093 final int childIndex = getAndVerifyPreorderedIndex(
2094 childrenCount, i, customOrder);
2095 final View child = getAndVerifyPreorderedView(
2096 preorderedList, children, childIndex);
Jeff Brown87b7f802011-06-21 18:35:45 -07002097 if (!canViewReceivePointerEvents(child)
2098 || !isTransformedTouchPointInView(x, y, child, null)) {
2099 continue;
2100 }
2101
2102 // Obtain a hover target for this child. Dequeue it from the
2103 // old hover target list if the child was previously hovered.
2104 HoverTarget hoverTarget = firstOldHoverTarget;
2105 final boolean wasHovered;
2106 for (HoverTarget predecessor = null; ;) {
2107 if (hoverTarget == null) {
2108 hoverTarget = HoverTarget.obtain(child);
2109 wasHovered = false;
2110 break;
2111 }
2112
2113 if (hoverTarget.child == child) {
2114 if (predecessor != null) {
2115 predecessor.next = hoverTarget.next;
2116 } else {
2117 firstOldHoverTarget = hoverTarget.next;
2118 }
2119 hoverTarget.next = null;
2120 wasHovered = true;
2121 break;
2122 }
2123
2124 predecessor = hoverTarget;
2125 hoverTarget = hoverTarget.next;
2126 }
2127
2128 // Enqueue the hover target onto the new hover target list.
2129 if (lastHoverTarget != null) {
2130 lastHoverTarget.next = hoverTarget;
2131 } else {
Jeff Brown87b7f802011-06-21 18:35:45 -07002132 mFirstHoverTarget = hoverTarget;
2133 }
Sangkyu Lee8725f362013-03-13 09:38:45 +09002134 lastHoverTarget = hoverTarget;
Jeff Brown87b7f802011-06-21 18:35:45 -07002135
2136 // Dispatch the event to the child.
2137 if (action == MotionEvent.ACTION_HOVER_ENTER) {
2138 if (!wasHovered) {
2139 // Send the enter as is.
2140 handled |= dispatchTransformedGenericPointerEvent(
2141 event, child); // enter
2142 }
2143 } else if (action == MotionEvent.ACTION_HOVER_MOVE) {
2144 if (!wasHovered) {
2145 // Synthesize an enter from a move.
2146 eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory);
2147 eventNoHistory.setAction(MotionEvent.ACTION_HOVER_ENTER);
2148 handled |= dispatchTransformedGenericPointerEvent(
2149 eventNoHistory, child); // enter
2150 eventNoHistory.setAction(action);
2151
2152 handled |= dispatchTransformedGenericPointerEvent(
2153 eventNoHistory, child); // move
2154 } else {
2155 // Send the move as is.
2156 handled |= dispatchTransformedGenericPointerEvent(event, child);
2157 }
2158 }
2159 if (handled) {
Jeff Brown10b62902011-06-20 16:40:37 -07002160 break;
Jeff Brown33bbfd22011-02-24 20:55:35 -08002161 }
Jeff Brown10b62902011-06-20 16:40:37 -07002162 }
Chris Craikab008f02014-05-23 17:55:03 -07002163 if (preorderedList != null) preorderedList.clear();
Jeff Brown10b62902011-06-20 16:40:37 -07002164 }
2165 }
Jeff Brown33bbfd22011-02-24 20:55:35 -08002166
Jeff Brown87b7f802011-06-21 18:35:45 -07002167 // Send exit events to all previously hovered children that are no longer hovered.
2168 while (firstOldHoverTarget != null) {
2169 final View child = firstOldHoverTarget.child;
Jeff Brown10b62902011-06-20 16:40:37 -07002170
Jeff Brown87b7f802011-06-21 18:35:45 -07002171 // Exit the old hovered child.
2172 if (action == MotionEvent.ACTION_HOVER_EXIT) {
2173 // Send the exit as is.
2174 handled |= dispatchTransformedGenericPointerEvent(
2175 event, child); // exit
2176 } else {
2177 // Synthesize an exit from a move or enter.
2178 // Ignore the result because hover focus has moved to a different view.
2179 if (action == MotionEvent.ACTION_HOVER_MOVE) {
Vladislav Kaznacheev5a77c372016-10-10 16:11:15 -07002180 final boolean hoverExitPending = event.isHoverExitPending();
2181 event.setHoverExitPending(true);
Jeff Brown10b62902011-06-20 16:40:37 -07002182 dispatchTransformedGenericPointerEvent(
Jeff Brown87b7f802011-06-21 18:35:45 -07002183 event, child); // move
Vladislav Kaznacheev5a77c372016-10-10 16:11:15 -07002184 event.setHoverExitPending(hoverExitPending);
Jeff Brown10b62902011-06-20 16:40:37 -07002185 }
Jeff Brown87b7f802011-06-21 18:35:45 -07002186 eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory);
2187 eventNoHistory.setAction(MotionEvent.ACTION_HOVER_EXIT);
2188 dispatchTransformedGenericPointerEvent(
2189 eventNoHistory, child); // exit
2190 eventNoHistory.setAction(action);
Jeff Brown10b62902011-06-20 16:40:37 -07002191 }
2192
Jeff Brown87b7f802011-06-21 18:35:45 -07002193 final HoverTarget nextOldHoverTarget = firstOldHoverTarget.next;
2194 firstOldHoverTarget.recycle();
2195 firstOldHoverTarget = nextOldHoverTarget;
Jeff Brown10b62902011-06-20 16:40:37 -07002196 }
2197
Vladislav Kaznacheev5a77c372016-10-10 16:11:15 -07002198 // Send events to the view group itself if no children have handled it and the view group
2199 // itself is not currently being hover-exited.
2200 boolean newHoveredSelf = !handled &&
2201 (action != MotionEvent.ACTION_HOVER_EXIT) && !event.isHoverExitPending();
Jeff Brown10b62902011-06-20 16:40:37 -07002202 if (newHoveredSelf == mHoveredSelf) {
2203 if (newHoveredSelf) {
2204 // Send event to the view group as before.
2205 handled |= super.dispatchHoverEvent(event);
2206 }
2207 } else {
2208 if (mHoveredSelf) {
2209 // Exit the view group.
2210 if (action == MotionEvent.ACTION_HOVER_EXIT) {
2211 // Send the exit as is.
2212 handled |= super.dispatchHoverEvent(event); // exit
2213 } else {
2214 // Synthesize an exit from a move or enter.
2215 // Ignore the result because hover focus is moving to a different view.
2216 if (action == MotionEvent.ACTION_HOVER_MOVE) {
2217 super.dispatchHoverEvent(event); // move
2218 }
2219 eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory);
2220 eventNoHistory.setAction(MotionEvent.ACTION_HOVER_EXIT);
2221 super.dispatchHoverEvent(eventNoHistory); // exit
2222 eventNoHistory.setAction(action);
2223 }
2224 mHoveredSelf = false;
2225 }
2226
2227 if (newHoveredSelf) {
2228 // Enter the view group.
2229 if (action == MotionEvent.ACTION_HOVER_ENTER) {
2230 // Send the enter as is.
2231 handled |= super.dispatchHoverEvent(event); // enter
2232 mHoveredSelf = true;
2233 } else if (action == MotionEvent.ACTION_HOVER_MOVE) {
2234 // Synthesize an enter from a move.
2235 eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory);
2236 eventNoHistory.setAction(MotionEvent.ACTION_HOVER_ENTER);
2237 handled |= super.dispatchHoverEvent(eventNoHistory); // enter
2238 eventNoHistory.setAction(action);
2239
2240 handled |= super.dispatchHoverEvent(eventNoHistory); // move
2241 mHoveredSelf = true;
Jeff Brown33bbfd22011-02-24 20:55:35 -08002242 }
2243 }
Jeff Brown33bbfd22011-02-24 20:55:35 -08002244 }
2245
Jeff Browna032cc02011-03-07 16:56:21 -08002246 // Recycle the copy of the event that we made.
2247 if (eventNoHistory != event) {
2248 eventNoHistory.recycle();
2249 }
2250
Jeff Browna032cc02011-03-07 16:56:21 -08002251 // Done.
2252 return handled;
2253 }
2254
Jeff Brown59a422e2012-04-19 15:19:19 -07002255 private void exitHoverTargets() {
2256 if (mHoveredSelf || mFirstHoverTarget != null) {
2257 final long now = SystemClock.uptimeMillis();
2258 MotionEvent event = MotionEvent.obtain(now, now,
2259 MotionEvent.ACTION_HOVER_EXIT, 0.0f, 0.0f, 0);
2260 event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
2261 dispatchHoverEvent(event);
2262 event.recycle();
2263 }
2264 }
2265
2266 private void cancelHoverTarget(View view) {
2267 HoverTarget predecessor = null;
2268 HoverTarget target = mFirstHoverTarget;
2269 while (target != null) {
2270 final HoverTarget next = target.next;
2271 if (target.child == view) {
2272 if (predecessor == null) {
2273 mFirstHoverTarget = next;
2274 } else {
2275 predecessor.next = next;
2276 }
2277 target.recycle();
2278
2279 final long now = SystemClock.uptimeMillis();
2280 MotionEvent event = MotionEvent.obtain(now, now,
2281 MotionEvent.ACTION_HOVER_EXIT, 0.0f, 0.0f, 0);
2282 event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
2283 view.dispatchHoverEvent(event);
2284 event.recycle();
2285 return;
2286 }
2287 predecessor = target;
2288 target = next;
2289 }
2290 }
2291
Vladislav Kaznacheevf847ee32016-11-21 14:11:00 -08002292 @Override
2293 boolean dispatchTooltipHoverEvent(MotionEvent event) {
2294 final int action = event.getAction();
2295 switch (action) {
2296 case MotionEvent.ACTION_HOVER_ENTER:
2297 break;
2298
2299 case MotionEvent.ACTION_HOVER_MOVE:
2300 View newTarget = null;
2301
2302 // Check what the child under the pointer says about the tooltip.
2303 final int childrenCount = mChildrenCount;
2304 if (childrenCount != 0) {
2305 final float x = event.getX();
2306 final float y = event.getY();
2307
2308 final ArrayList<View> preorderedList = buildOrderedChildList();
2309 final boolean customOrder = preorderedList == null
2310 && isChildrenDrawingOrderEnabled();
2311 final View[] children = mChildren;
2312 for (int i = childrenCount - 1; i >= 0; i--) {
2313 final int childIndex =
2314 getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
2315 final View child =
2316 getAndVerifyPreorderedView(preorderedList, children, childIndex);
Vladislav Kaznacheev943cf0e2017-01-06 09:52:51 -08002317 if (!canViewReceivePointerEvents(child)
2318 || !isTransformedTouchPointInView(x, y, child, null)) {
2319 continue;
2320 }
2321 if (dispatchTooltipHoverEvent(event, child)) {
2322 newTarget = child;
Vladislav Kaznacheevf847ee32016-11-21 14:11:00 -08002323 break;
2324 }
2325 }
2326 if (preorderedList != null) preorderedList.clear();
2327 }
2328
2329 if (mTooltipHoverTarget != newTarget) {
2330 if (mTooltipHoverTarget != null) {
2331 event.setAction(MotionEvent.ACTION_HOVER_EXIT);
2332 mTooltipHoverTarget.dispatchTooltipHoverEvent(event);
2333 event.setAction(action);
2334 }
2335 mTooltipHoverTarget = newTarget;
2336 }
2337
2338 if (mTooltipHoverTarget != null) {
2339 if (mTooltipHoveredSelf) {
2340 mTooltipHoveredSelf = false;
2341 event.setAction(MotionEvent.ACTION_HOVER_EXIT);
2342 super.dispatchTooltipHoverEvent(event);
2343 event.setAction(action);
2344 }
2345 return true;
2346 }
2347
2348 mTooltipHoveredSelf = super.dispatchTooltipHoverEvent(event);
2349 return mTooltipHoveredSelf;
2350
2351 case MotionEvent.ACTION_HOVER_EXIT:
2352 if (mTooltipHoverTarget != null) {
2353 mTooltipHoverTarget.dispatchTooltipHoverEvent(event);
2354 mTooltipHoverTarget = null;
2355 } else if (mTooltipHoveredSelf) {
2356 super.dispatchTooltipHoverEvent(event);
2357 mTooltipHoveredSelf = false;
2358 }
2359 break;
2360 }
2361 return false;
2362 }
2363
2364 private boolean dispatchTooltipHoverEvent(MotionEvent event, View child) {
2365 final boolean result;
2366 if (!child.hasIdentityMatrix()) {
2367 MotionEvent transformedEvent = getTransformedMotionEvent(event, child);
2368 result = child.dispatchTooltipHoverEvent(transformedEvent);
2369 transformedEvent.recycle();
2370 } else {
2371 final float offsetX = mScrollX - child.mLeft;
2372 final float offsetY = mScrollY - child.mTop;
2373 event.offsetLocation(offsetX, offsetY);
2374 result = child.dispatchTooltipHoverEvent(event);
2375 event.offsetLocation(-offsetX, -offsetY);
2376 }
2377 return result;
2378 }
2379
2380 private void exitTooltipHoverTargets() {
2381 if (mTooltipHoveredSelf || mTooltipHoverTarget != null) {
2382 final long now = SystemClock.uptimeMillis();
2383 MotionEvent event = MotionEvent.obtain(now, now,
2384 MotionEvent.ACTION_HOVER_EXIT, 0.0f, 0.0f, 0);
2385 event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
2386 dispatchTooltipHoverEvent(event);
2387 event.recycle();
2388 }
2389 }
2390
Jeff Brown87b7f802011-06-21 18:35:45 -07002391 /** @hide */
2392 @Override
2393 protected boolean hasHoveredChild() {
2394 return mFirstHoverTarget != null;
2395 }
2396
Dieter Hsufa1b8de2018-08-22 10:35:58 +08002397 /** @hide */
2398 @Override
2399 protected boolean pointInHoveredChild(MotionEvent event) {
2400 if (mFirstHoverTarget != null) {
2401 return isTransformedTouchPointInView(event.getX(), event.getY(),
2402 mFirstHoverTarget.child, null);
2403 }
2404 return false;
2405 }
2406
Svetoslav Ganov42138042012-03-20 11:51:39 -07002407 @Override
Adam Powellcf392d12015-06-25 14:48:45 -07002408 public void addChildrenForAccessibility(ArrayList<View> outChildren) {
Svetoslav762621c2015-06-01 17:21:59 -07002409 if (getAccessibilityNodeProvider() != null) {
2410 return;
2411 }
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07002412 ChildListForAccessibility children = ChildListForAccessibility.obtain(this, true);
2413 try {
2414 final int childrenCount = children.getChildCount();
2415 for (int i = 0; i < childrenCount; i++) {
2416 View child = children.getChildAt(i);
Svetoslav Ganovc406be92012-05-11 16:12:32 -07002417 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07002418 if (child.includeForAccessibility()) {
Adam Powellcf392d12015-06-25 14:48:45 -07002419 outChildren.add(child);
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07002420 } else {
Adam Powellcf392d12015-06-25 14:48:45 -07002421 child.addChildrenForAccessibility(outChildren);
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07002422 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07002423 }
2424 }
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07002425 } finally {
2426 children.recycle();
Svetoslav Ganov42138042012-03-20 11:51:39 -07002427 }
2428 }
2429
2430 /**
Jeff Brown10b62902011-06-20 16:40:37 -07002431 * Implement this method to intercept hover events before they are handled
2432 * by child views.
2433 * <p>
2434 * This method is called before dispatching a hover event to a child of
2435 * the view group or to the view group's own {@link #onHoverEvent} to allow
2436 * the view group a chance to intercept the hover event.
2437 * This method can also be used to watch all pointer motions that occur within
2438 * the bounds of the view group even when the pointer is hovering over
2439 * a child of the view group rather than over the view group itself.
2440 * </p><p>
2441 * The view group can prevent its children from receiving hover events by
2442 * implementing this method and returning <code>true</code> to indicate
2443 * that it would like to intercept hover events. The view group must
2444 * continuously return <code>true</code> from {@link #onInterceptHoverEvent}
2445 * for as long as it wishes to continue intercepting hover events from
2446 * its children.
2447 * </p><p>
2448 * Interception preserves the invariant that at most one view can be
2449 * hovered at a time by transferring hover focus from the currently hovered
2450 * child to the view group or vice-versa as needed.
2451 * </p><p>
2452 * If this method returns <code>true</code> and a child is already hovered, then the
2453 * child view will first receive a hover exit event and then the view group
2454 * itself will receive a hover enter event in {@link #onHoverEvent}.
2455 * Likewise, if this method had previously returned <code>true</code> to intercept hover
2456 * events and instead returns <code>false</code> while the pointer is hovering
2457 * within the bounds of one of a child, then the view group will first receive a
2458 * hover exit event in {@link #onHoverEvent} and then the hovered child will
2459 * receive a hover enter event.
2460 * </p><p>
Keisuke Kuroyanagid85bc502016-01-21 14:50:38 +09002461 * The default implementation handles mouse hover on the scroll bars.
Jeff Brown10b62902011-06-20 16:40:37 -07002462 * </p>
2463 *
2464 * @param event The motion event that describes the hover.
2465 * @return True if the view group would like to intercept the hover event
2466 * and prevent its children from receiving it.
2467 */
2468 public boolean onInterceptHoverEvent(MotionEvent event) {
Keisuke Kuroyanagid85bc502016-01-21 14:50:38 +09002469 if (event.isFromSource(InputDevice.SOURCE_MOUSE)) {
2470 final int action = event.getAction();
2471 final float x = event.getX();
2472 final float y = event.getY();
2473 if ((action == MotionEvent.ACTION_HOVER_MOVE
2474 || action == MotionEvent.ACTION_HOVER_ENTER) && isOnScrollbar(x, y)) {
2475 return true;
2476 }
2477 }
Svetoslav Ganov736c2752011-04-22 18:30:36 -07002478 return false;
2479 }
2480
Jeff Browna032cc02011-03-07 16:56:21 -08002481 private static MotionEvent obtainMotionEventNoHistoryOrSelf(MotionEvent event) {
2482 if (event.getHistorySize() == 0) {
2483 return event;
2484 }
2485 return MotionEvent.obtainNoHistory(event);
2486 }
2487
Jeff Browna032cc02011-03-07 16:56:21 -08002488 @Override
2489 protected boolean dispatchGenericPointerEvent(MotionEvent event) {
2490 // Send the event to the child under the pointer.
2491 final int childrenCount = mChildrenCount;
2492 if (childrenCount != 0) {
Jeff Browna032cc02011-03-07 16:56:21 -08002493 final float x = event.getX();
2494 final float y = event.getY();
2495
Chris Craikab008f02014-05-23 17:55:03 -07002496 final ArrayList<View> preorderedList = buildOrderedChildList();
2497 final boolean customOrder = preorderedList == null
2498 && isChildrenDrawingOrderEnabled();
2499 final View[] children = mChildren;
Jeff Browna032cc02011-03-07 16:56:21 -08002500 for (int i = childrenCount - 1; i >= 0; i--) {
Alan Viverettea7b85e62016-01-22 10:14:02 -05002501 final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
2502 final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);
Jeff Browna032cc02011-03-07 16:56:21 -08002503 if (!canViewReceivePointerEvents(child)
2504 || !isTransformedTouchPointInView(x, y, child, null)) {
2505 continue;
2506 }
2507
2508 if (dispatchTransformedGenericPointerEvent(event, child)) {
Chris Craikab008f02014-05-23 17:55:03 -07002509 if (preorderedList != null) preorderedList.clear();
Jeff Browna032cc02011-03-07 16:56:21 -08002510 return true;
2511 }
2512 }
Chris Craikab008f02014-05-23 17:55:03 -07002513 if (preorderedList != null) preorderedList.clear();
Jeff Browna032cc02011-03-07 16:56:21 -08002514 }
2515
2516 // No child handled the event. Send it to this view group.
2517 return super.dispatchGenericPointerEvent(event);
2518 }
2519
Jeff Browna032cc02011-03-07 16:56:21 -08002520 @Override
2521 protected boolean dispatchGenericFocusedEvent(MotionEvent event) {
Jeff Brown33bbfd22011-02-24 20:55:35 -08002522 // Send the event to the focused child or to this view group if it has focus.
Dianne Hackborn4702a852012-08-17 15:18:29 -07002523 if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
2524 == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
Jeff Browna032cc02011-03-07 16:56:21 -08002525 return super.dispatchGenericFocusedEvent(event);
Dianne Hackborn4702a852012-08-17 15:18:29 -07002526 } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
2527 == PFLAG_HAS_BOUNDS) {
Jeff Browncb1404e2011-01-15 18:14:15 -08002528 return mFocused.dispatchGenericMotionEvent(event);
2529 }
2530 return false;
2531 }
2532
2533 /**
Jeff Browna032cc02011-03-07 16:56:21 -08002534 * Dispatches a generic pointer event to a child, taking into account
2535 * transformations that apply to the child.
2536 *
2537 * @param event The event to send.
2538 * @param child The view to send the event to.
2539 * @return {@code true} if the child handled the event.
2540 */
2541 private boolean dispatchTransformedGenericPointerEvent(MotionEvent event, View child) {
Jeff Browna032cc02011-03-07 16:56:21 -08002542 boolean handled;
2543 if (!child.hasIdentityMatrix()) {
Michael Wrighte051f6f2016-05-13 17:44:16 +01002544 MotionEvent transformedEvent = getTransformedMotionEvent(event, child);
Jeff Browna032cc02011-03-07 16:56:21 -08002545 handled = child.dispatchGenericMotionEvent(transformedEvent);
2546 transformedEvent.recycle();
2547 } else {
Michael Wrighte051f6f2016-05-13 17:44:16 +01002548 final float offsetX = mScrollX - child.mLeft;
2549 final float offsetY = mScrollY - child.mTop;
Jeff Browna032cc02011-03-07 16:56:21 -08002550 event.offsetLocation(offsetX, offsetY);
2551 handled = child.dispatchGenericMotionEvent(event);
2552 event.offsetLocation(-offsetX, -offsetY);
2553 }
2554 return handled;
2555 }
2556
Michael Wrighte051f6f2016-05-13 17:44:16 +01002557 /**
2558 * Returns a MotionEvent that's been transformed into the child's local coordinates.
2559 *
2560 * It's the responsibility of the caller to recycle it once they're finished with it.
2561 * @param event The event to transform.
2562 * @param child The view whose coordinate space is to be used.
2563 * @return A copy of the the given MotionEvent, transformed into the given View's coordinate
2564 * space.
2565 */
2566 private MotionEvent getTransformedMotionEvent(MotionEvent event, View child) {
2567 final float offsetX = mScrollX - child.mLeft;
2568 final float offsetY = mScrollY - child.mTop;
2569 final MotionEvent transformedEvent = MotionEvent.obtain(event);
2570 transformedEvent.offsetLocation(offsetX, offsetY);
2571 if (!child.hasIdentityMatrix()) {
2572 transformedEvent.transform(child.getInverseMatrix());
2573 }
2574 return transformedEvent;
2575 }
2576
Jeff Browncb1404e2011-01-15 18:14:15 -08002577 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002578 public boolean dispatchTouchEvent(MotionEvent ev) {
Jeff Brown21bc5c92011-02-28 18:27:14 -08002579 if (mInputEventConsistencyVerifier != null) {
2580 mInputEventConsistencyVerifier.onTouchEvent(ev, 1);
2581 }
2582
Svet Ganov0a2ccee2015-02-06 10:12:32 -08002583 // If the event targets the accessibility focused view and this is it, start
2584 // normal event dispatch. Maybe a descendant is what will handle the click.
Svet Ganovf33fe1f2015-02-06 19:23:31 -08002585 if (ev.isTargetAccessibilityFocus() && isAccessibilityFocusedViewOrHost()) {
Svet Ganov0a2ccee2015-02-06 10:12:32 -08002586 ev.setTargetAccessibilityFocus(false);
2587 }
2588
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002589 boolean handled = false;
2590 if (onFilterTouchEventForSecurity(ev)) {
2591 final int action = ev.getAction();
2592 final int actionMasked = action & MotionEvent.ACTION_MASK;
Jeff Brown85a31762010-09-01 17:01:00 -07002593
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002594 // Handle an initial down.
2595 if (actionMasked == MotionEvent.ACTION_DOWN) {
2596 // Throw away all previous state when starting a new touch gesture.
2597 // The framework may have dropped the up or cancel event for the previous gesture
2598 // due to an app switch, ANR, or some other state change.
2599 cancelAndClearTouchTargets(ev);
2600 resetTouchState();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002601 }
Adam Powellb08013c2010-09-16 16:28:11 -07002602
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002603 // Check for interception.
2604 final boolean intercepted;
Svet Ganovf33fe1f2015-02-06 19:23:31 -08002605 if (actionMasked == MotionEvent.ACTION_DOWN
2606 || mFirstTouchTarget != null) {
2607 final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
2608 if (!disallowIntercept) {
2609 intercepted = onInterceptTouchEvent(ev);
2610 ev.setAction(action); // restore action in case it was changed
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002611 } else {
Svet Ganovf33fe1f2015-02-06 19:23:31 -08002612 intercepted = false;
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002613 }
2614 } else {
Svet Ganovf33fe1f2015-02-06 19:23:31 -08002615 // There are no touch targets and this action is not an initial down
2616 // so this view group continues to intercept touches.
2617 intercepted = true;
2618 }
2619
2620 // If intercepted, start normal event dispatch. Also if there is already
2621 // a view that is handling the gesture, do normal event dispatch.
2622 if (intercepted || mFirstTouchTarget != null) {
2623 ev.setTargetAccessibilityFocus(false);
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002624 }
Jeff Brown20e987b2010-08-23 12:01:02 -07002625
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002626 // Check for cancelation.
2627 final boolean canceled = resetCancelNextUpFlag(this)
2628 || actionMasked == MotionEvent.ACTION_CANCEL;
Jeff Brown20e987b2010-08-23 12:01:02 -07002629
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002630 // Update list of touch targets for pointer down, if needed.
2631 final boolean split = (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) != 0;
2632 TouchTarget newTouchTarget = null;
2633 boolean alreadyDispatchedToNewTouchTarget = false;
2634 if (!canceled && !intercepted) {
Svetoslavc73cfa02015-02-09 17:14:28 -08002635
Phil Weaver1e6ecc62017-11-07 15:28:21 -08002636 // If the event is targeting accessibility focus we give it to the
Svetoslavc73cfa02015-02-09 17:14:28 -08002637 // view that has accessibility focus and if it does not handle it
2638 // we clear the flag and dispatch the event to all children as usual.
2639 // We are looking up the accessibility focused host to avoid keeping
2640 // state since these events are very rare.
2641 View childWithAccessibilityFocus = ev.isTargetAccessibilityFocus()
2642 ? findChildWithAccessibilityFocus() : null;
2643
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002644 if (actionMasked == MotionEvent.ACTION_DOWN
2645 || (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN)
Svet Ganovf33fe1f2015-02-06 19:23:31 -08002646 || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002647 final int actionIndex = ev.getActionIndex(); // always 0 for down
2648 final int idBitsToAssign = split ? 1 << ev.getPointerId(actionIndex)
2649 : TouchTarget.ALL_POINTER_IDS;
Jeff Brown20e987b2010-08-23 12:01:02 -07002650
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002651 // Clean up earlier touch targets for this pointer id in case they
2652 // have become out of sync.
2653 removePointersFromTouchTargets(idBitsToAssign);
2654
2655 final int childrenCount = mChildrenCount;
Chet Haase9c17fe62013-03-22 17:05:55 -07002656 if (newTouchTarget == null && childrenCount != 0) {
Chet Haaseedf6f4b2013-03-26 07:55:30 -07002657 final float x = ev.getX(actionIndex);
2658 final float y = ev.getY(actionIndex);
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002659 // Find a child that can receive the event.
2660 // Scan children from front to back.
Filip Gruszczynskia33bdf32015-11-19 18:22:16 -08002661 final ArrayList<View> preorderedList = buildTouchDispatchChildList();
Chris Craikab008f02014-05-23 17:55:03 -07002662 final boolean customOrder = preorderedList == null
2663 && isChildrenDrawingOrderEnabled();
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002664 final View[] children = mChildren;
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002665 for (int i = childrenCount - 1; i >= 0; i--) {
Alan Viverettea7b85e62016-01-22 10:14:02 -05002666 final int childIndex = getAndVerifyPreorderedIndex(
2667 childrenCount, i, customOrder);
2668 final View child = getAndVerifyPreorderedView(
2669 preorderedList, children, childIndex);
Svetoslavc73cfa02015-02-09 17:14:28 -08002670
2671 // If there is a view that has accessibility focus we want it
2672 // to get the event first and if not handled we will perform a
2673 // normal dispatch. We may do a double iteration but this is
2674 // safer given the timeframe.
2675 if (childWithAccessibilityFocus != null) {
2676 if (childWithAccessibilityFocus != child) {
2677 continue;
2678 }
2679 childWithAccessibilityFocus = null;
2680 i = childrenCount - 1;
2681 }
2682
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002683 if (!canViewReceivePointerEvents(child)
2684 || !isTransformedTouchPointInView(x, y, child, null)) {
Svetoslavc73cfa02015-02-09 17:14:28 -08002685 ev.setTargetAccessibilityFocus(false);
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002686 continue;
2687 }
2688
2689 newTouchTarget = getTouchTarget(child);
2690 if (newTouchTarget != null) {
2691 // Child is already receiving touch within its bounds.
2692 // Give it the new pointer in addition to the ones it is handling.
2693 newTouchTarget.pointerIdBits |= idBitsToAssign;
2694 break;
2695 }
2696
2697 resetCancelNextUpFlag(child);
2698 if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
2699 // Child wants to receive touch within its bounds.
2700 mLastTouchDownTime = ev.getDownTime();
Chris Craikab008f02014-05-23 17:55:03 -07002701 if (preorderedList != null) {
2702 // childIndex points into presorted list, find original index
2703 for (int j = 0; j < childrenCount; j++) {
2704 if (children[childIndex] == mChildren[j]) {
2705 mLastTouchDownIndex = j;
2706 break;
2707 }
2708 }
2709 } else {
2710 mLastTouchDownIndex = childIndex;
2711 }
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002712 mLastTouchDownX = ev.getX();
2713 mLastTouchDownY = ev.getY();
2714 newTouchTarget = addTouchTarget(child, idBitsToAssign);
2715 alreadyDispatchedToNewTouchTarget = true;
2716 break;
2717 }
Svetoslavc73cfa02015-02-09 17:14:28 -08002718
2719 // The accessibility focus didn't handle the event, so clear
2720 // the flag and do a normal dispatch to all children.
2721 ev.setTargetAccessibilityFocus(false);
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002722 }
Chris Craikab008f02014-05-23 17:55:03 -07002723 if (preorderedList != null) preorderedList.clear();
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002724 }
2725
2726 if (newTouchTarget == null && mFirstTouchTarget != null) {
2727 // Did not find a child to receive the event.
2728 // Assign the pointer to the least recently added target.
2729 newTouchTarget = mFirstTouchTarget;
2730 while (newTouchTarget.next != null) {
2731 newTouchTarget = newTouchTarget.next;
2732 }
2733 newTouchTarget.pointerIdBits |= idBitsToAssign;
2734 }
2735 }
2736 }
2737
2738 // Dispatch to touch targets.
2739 if (mFirstTouchTarget == null) {
2740 // No touch targets so treat this as an ordinary view.
2741 handled = dispatchTransformedTouchEvent(ev, canceled, null,
2742 TouchTarget.ALL_POINTER_IDS);
2743 } else {
2744 // Dispatch to touch targets, excluding the new touch target if we already
2745 // dispatched to it. Cancel touch targets if necessary.
2746 TouchTarget predecessor = null;
2747 TouchTarget target = mFirstTouchTarget;
2748 while (target != null) {
2749 final TouchTarget next = target.next;
2750 if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {
2751 handled = true;
2752 } else {
2753 final boolean cancelChild = resetCancelNextUpFlag(target.child)
Chet Haase9c17fe62013-03-22 17:05:55 -07002754 || intercepted;
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002755 if (dispatchTransformedTouchEvent(ev, cancelChild,
2756 target.child, target.pointerIdBits)) {
2757 handled = true;
2758 }
2759 if (cancelChild) {
2760 if (predecessor == null) {
2761 mFirstTouchTarget = next;
2762 } else {
2763 predecessor.next = next;
2764 }
2765 target.recycle();
2766 target = next;
Jeff Brown20e987b2010-08-23 12:01:02 -07002767 continue;
2768 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002769 }
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002770 predecessor = target;
2771 target = next;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002772 }
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002773 }
Jeff Brown20e987b2010-08-23 12:01:02 -07002774
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002775 // Update list of touch targets for pointer up or cancel, if needed.
2776 if (canceled
2777 || actionMasked == MotionEvent.ACTION_UP
2778 || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
2779 resetTouchState();
2780 } else if (split && actionMasked == MotionEvent.ACTION_POINTER_UP) {
2781 final int actionIndex = ev.getActionIndex();
2782 final int idBitsToRemove = 1 << ev.getPointerId(actionIndex);
2783 removePointersFromTouchTargets(idBitsToRemove);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002784 }
2785 }
Romain Guy8506ab42009-06-11 17:35:47 -07002786
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002787 if (!handled && mInputEventConsistencyVerifier != null) {
2788 mInputEventConsistencyVerifier.onUnhandledEvent(ev, 1);
Jeff Brown20e987b2010-08-23 12:01:02 -07002789 }
Jeff Brown20e987b2010-08-23 12:01:02 -07002790 return handled;
2791 }
2792
Romain Guy469b1db2010-10-05 11:49:57 -07002793 /**
Filip Gruszczynskia33bdf32015-11-19 18:22:16 -08002794 * Provide custom ordering of views in which the touch will be dispatched.
2795 *
2796 * This is called within a tight loop, so you are not allowed to allocate objects, including
2797 * the return array. Instead, you should return a pre-allocated list that will be cleared
2798 * after the dispatch is finished.
2799 * @hide
2800 */
2801 public ArrayList<View> buildTouchDispatchChildList() {
2802 return buildOrderedChildList();
2803 }
2804
2805 /**
Svetoslavc73cfa02015-02-09 17:14:28 -08002806 * Finds the child which has accessibility focus.
2807 *
2808 * @return The child that has focus.
2809 */
2810 private View findChildWithAccessibilityFocus() {
2811 ViewRootImpl viewRoot = getViewRootImpl();
2812 if (viewRoot == null) {
2813 return null;
2814 }
2815
2816 View current = viewRoot.getAccessibilityFocusedHost();
2817 if (current == null) {
2818 return null;
2819 }
2820
2821 ViewParent parent = current.getParent();
2822 while (parent instanceof View) {
2823 if (parent == this) {
2824 return current;
2825 }
2826 current = (View) parent;
2827 parent = current.getParent();
2828 }
2829
2830 return null;
2831 }
2832
2833 /**
Romain Guy469b1db2010-10-05 11:49:57 -07002834 * Resets all touch state in preparation for a new cycle.
2835 */
2836 private void resetTouchState() {
Jeff Brown20e987b2010-08-23 12:01:02 -07002837 clearTouchTargets();
2838 resetCancelNextUpFlag(this);
2839 mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
Adam Powell10ba2772014-04-15 09:46:51 -07002840 mNestedScrollAxes = SCROLL_AXIS_NONE;
Jeff Brown20e987b2010-08-23 12:01:02 -07002841 }
2842
Romain Guy469b1db2010-10-05 11:49:57 -07002843 /**
2844 * Resets the cancel next up flag.
2845 * Returns true if the flag was previously set.
2846 */
Alan Viverettea7b85e62016-01-22 10:14:02 -05002847 private static boolean resetCancelNextUpFlag(@NonNull View view) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07002848 if ((view.mPrivateFlags & PFLAG_CANCEL_NEXT_UP_EVENT) != 0) {
2849 view.mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT;
Jeff Brown20e987b2010-08-23 12:01:02 -07002850 return true;
Adam Cohen9b073942010-08-19 16:49:52 -07002851 }
2852 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002853 }
2854
Romain Guy469b1db2010-10-05 11:49:57 -07002855 /**
2856 * Clears all touch targets.
2857 */
2858 private void clearTouchTargets() {
Jeff Brown20e987b2010-08-23 12:01:02 -07002859 TouchTarget target = mFirstTouchTarget;
2860 if (target != null) {
2861 do {
2862 TouchTarget next = target.next;
2863 target.recycle();
2864 target = next;
2865 } while (target != null);
2866 mFirstTouchTarget = null;
2867 }
2868 }
2869
Romain Guy469b1db2010-10-05 11:49:57 -07002870 /**
2871 * Cancels and clears all touch targets.
2872 */
2873 private void cancelAndClearTouchTargets(MotionEvent event) {
Jeff Brown20e987b2010-08-23 12:01:02 -07002874 if (mFirstTouchTarget != null) {
2875 boolean syntheticEvent = false;
2876 if (event == null) {
2877 final long now = SystemClock.uptimeMillis();
2878 event = MotionEvent.obtain(now, now,
2879 MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
Jeff Brown2fdbc5a2011-06-30 12:25:54 -07002880 event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
Jeff Brown20e987b2010-08-23 12:01:02 -07002881 syntheticEvent = true;
2882 }
2883
2884 for (TouchTarget target = mFirstTouchTarget; target != null; target = target.next) {
2885 resetCancelNextUpFlag(target.child);
2886 dispatchTransformedTouchEvent(event, true, target.child, target.pointerIdBits);
2887 }
2888 clearTouchTargets();
2889
2890 if (syntheticEvent) {
2891 event.recycle();
2892 }
2893 }
2894 }
2895
Romain Guy469b1db2010-10-05 11:49:57 -07002896 /**
2897 * Gets the touch target for specified child view.
2898 * Returns null if not found.
2899 */
Alan Viverettea7b85e62016-01-22 10:14:02 -05002900 private TouchTarget getTouchTarget(@NonNull View child) {
Jeff Brown20e987b2010-08-23 12:01:02 -07002901 for (TouchTarget target = mFirstTouchTarget; target != null; target = target.next) {
2902 if (target.child == child) {
2903 return target;
2904 }
2905 }
2906 return null;
2907 }
2908
Romain Guy469b1db2010-10-05 11:49:57 -07002909 /**
2910 * Adds a touch target for specified child to the beginning of the list.
2911 * Assumes the target child is not already present.
2912 */
Alan Viverettea7b85e62016-01-22 10:14:02 -05002913 private TouchTarget addTouchTarget(@NonNull View child, int pointerIdBits) {
2914 final TouchTarget target = TouchTarget.obtain(child, pointerIdBits);
Jeff Brown20e987b2010-08-23 12:01:02 -07002915 target.next = mFirstTouchTarget;
2916 mFirstTouchTarget = target;
2917 return target;
2918 }
2919
Romain Guy469b1db2010-10-05 11:49:57 -07002920 /**
2921 * Removes the pointer ids from consideration.
2922 */
2923 private void removePointersFromTouchTargets(int pointerIdBits) {
Jeff Brown20e987b2010-08-23 12:01:02 -07002924 TouchTarget predecessor = null;
2925 TouchTarget target = mFirstTouchTarget;
2926 while (target != null) {
2927 final TouchTarget next = target.next;
2928 if ((target.pointerIdBits & pointerIdBits) != 0) {
2929 target.pointerIdBits &= ~pointerIdBits;
2930 if (target.pointerIdBits == 0) {
2931 if (predecessor == null) {
2932 mFirstTouchTarget = next;
2933 } else {
2934 predecessor.next = next;
2935 }
2936 target.recycle();
2937 target = next;
2938 continue;
2939 }
2940 }
2941 predecessor = target;
2942 target = next;
2943 }
2944 }
2945
Mathew Inwooda570dee2018-08-17 14:56:00 +01002946 @UnsupportedAppUsage
Jeff Brown59a422e2012-04-19 15:19:19 -07002947 private void cancelTouchTarget(View view) {
2948 TouchTarget predecessor = null;
2949 TouchTarget target = mFirstTouchTarget;
2950 while (target != null) {
2951 final TouchTarget next = target.next;
2952 if (target.child == view) {
2953 if (predecessor == null) {
2954 mFirstTouchTarget = next;
2955 } else {
2956 predecessor.next = next;
2957 }
2958 target.recycle();
2959
2960 final long now = SystemClock.uptimeMillis();
2961 MotionEvent event = MotionEvent.obtain(now, now,
2962 MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
2963 event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
2964 view.dispatchTouchEvent(event);
2965 event.recycle();
2966 return;
2967 }
2968 predecessor = target;
2969 target = next;
2970 }
2971 }
2972
Romain Guy469b1db2010-10-05 11:49:57 -07002973 /**
Jeff Browna032cc02011-03-07 16:56:21 -08002974 * Returns true if a child view can receive pointer events.
2975 * @hide
2976 */
Alan Viverettea7b85e62016-01-22 10:14:02 -05002977 private static boolean canViewReceivePointerEvents(@NonNull View child) {
Jeff Browna032cc02011-03-07 16:56:21 -08002978 return (child.mViewFlags & VISIBILITY_MASK) == VISIBLE
2979 || child.getAnimation() != null;
2980 }
2981
Alan Viveretteb942b6f2014-12-08 10:37:39 -08002982 private float[] getTempPoint() {
2983 if (mTempPoint == null) {
2984 mTempPoint = new float[2];
2985 }
2986 return mTempPoint;
2987 }
2988
Jeff Browna032cc02011-03-07 16:56:21 -08002989 /**
Romain Guy469b1db2010-10-05 11:49:57 -07002990 * Returns true if a child view contains the specified point when transformed
Jeff Brown20e987b2010-08-23 12:01:02 -07002991 * into its coordinate space.
Romain Guy469b1db2010-10-05 11:49:57 -07002992 * Child must not be null.
Adam Cohena32edd42010-10-26 10:35:01 -07002993 * @hide
Romain Guy469b1db2010-10-05 11:49:57 -07002994 */
Mathew Inwooda570dee2018-08-17 14:56:00 +01002995 @UnsupportedAppUsage
Adam Cohena32edd42010-10-26 10:35:01 -07002996 protected boolean isTransformedTouchPointInView(float x, float y, View child,
Christopher Tate2c095f32010-10-04 14:13:40 -07002997 PointF outLocalPoint) {
Alan Viveretteb942b6f2014-12-08 10:37:39 -08002998 final float[] point = getTempPoint();
2999 point[0] = x;
3000 point[1] = y;
3001 transformPointToViewLocal(point, child);
3002 final boolean isInView = child.pointInView(point[0], point[1]);
Christopher Tate2c095f32010-10-04 14:13:40 -07003003 if (isInView && outLocalPoint != null) {
Alan Viveretteb942b6f2014-12-08 10:37:39 -08003004 outLocalPoint.set(point[0], point[1]);
Christopher Tate2c095f32010-10-04 14:13:40 -07003005 }
3006 return isInView;
Adam Powell2b342f02010-08-18 18:14:13 -07003007 }
3008
Romain Guy469b1db2010-10-05 11:49:57 -07003009 /**
Alan Viveretteb942b6f2014-12-08 10:37:39 -08003010 * @hide
3011 */
Mathew Inwooda570dee2018-08-17 14:56:00 +01003012 @UnsupportedAppUsage
Alan Viveretteb942b6f2014-12-08 10:37:39 -08003013 public void transformPointToViewLocal(float[] point, View child) {
3014 point[0] += mScrollX - child.mLeft;
3015 point[1] += mScrollY - child.mTop;
3016
3017 if (!child.hasIdentityMatrix()) {
3018 child.getInverseMatrix().mapPoints(point);
3019 }
3020 }
3021
3022 /**
Romain Guy469b1db2010-10-05 11:49:57 -07003023 * Transforms a motion event into the coordinate space of a particular child view,
Jeff Brown20e987b2010-08-23 12:01:02 -07003024 * filters out irrelevant pointer ids, and overrides its action if necessary.
Romain Guy469b1db2010-10-05 11:49:57 -07003025 * If child is null, assumes the MotionEvent will be sent to this ViewGroup instead.
3026 */
3027 private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,
Jeff Brown20e987b2010-08-23 12:01:02 -07003028 View child, int desiredPointerIdBits) {
3029 final boolean handled;
Adam Powell2b342f02010-08-18 18:14:13 -07003030
Jeff Brown20e987b2010-08-23 12:01:02 -07003031 // Canceling motions is a special case. We don't need to perform any transformations
3032 // or filtering. The important part is the action, not the contents.
3033 final int oldAction = event.getAction();
3034 if (cancel || oldAction == MotionEvent.ACTION_CANCEL) {
3035 event.setAction(MotionEvent.ACTION_CANCEL);
3036 if (child == null) {
3037 handled = super.dispatchTouchEvent(event);
3038 } else {
3039 handled = child.dispatchTouchEvent(event);
3040 }
3041 event.setAction(oldAction);
3042 return handled;
3043 }
Adam Powell2b342f02010-08-18 18:14:13 -07003044
Jeff Brown20e987b2010-08-23 12:01:02 -07003045 // Calculate the number of pointers to deliver.
Jeff Brownfe9f8ab2011-05-06 18:20:01 -07003046 final int oldPointerIdBits = event.getPointerIdBits();
3047 final int newPointerIdBits = oldPointerIdBits & desiredPointerIdBits;
Adam Powell2b342f02010-08-18 18:14:13 -07003048
Jeff Brown20e987b2010-08-23 12:01:02 -07003049 // If for some reason we ended up in an inconsistent state where it looks like we
3050 // might produce a motion event with no pointers in it, then drop the event.
Jeff Brownfe9f8ab2011-05-06 18:20:01 -07003051 if (newPointerIdBits == 0) {
Jeff Brown20e987b2010-08-23 12:01:02 -07003052 return false;
3053 }
Adam Powell2b342f02010-08-18 18:14:13 -07003054
Jeff Brown20e987b2010-08-23 12:01:02 -07003055 // If the number of pointers is the same and we don't need to perform any fancy
3056 // irreversible transformations, then we can reuse the motion event for this
3057 // dispatch as long as we are careful to revert any changes we make.
Jeff Brownfe9f8ab2011-05-06 18:20:01 -07003058 // Otherwise we need to make a copy.
3059 final MotionEvent transformedEvent;
3060 if (newPointerIdBits == oldPointerIdBits) {
3061 if (child == null || child.hasIdentityMatrix()) {
3062 if (child == null) {
3063 handled = super.dispatchTouchEvent(event);
3064 } else {
3065 final float offsetX = mScrollX - child.mLeft;
3066 final float offsetY = mScrollY - child.mTop;
3067 event.offsetLocation(offsetX, offsetY);
Adam Powell2b342f02010-08-18 18:14:13 -07003068
Jeff Brownfe9f8ab2011-05-06 18:20:01 -07003069 handled = child.dispatchTouchEvent(event);
Jeff Brown20e987b2010-08-23 12:01:02 -07003070
Jeff Brownfe9f8ab2011-05-06 18:20:01 -07003071 event.offsetLocation(-offsetX, -offsetY);
3072 }
3073 return handled;
Jeff Brown20e987b2010-08-23 12:01:02 -07003074 }
Jeff Brown20e987b2010-08-23 12:01:02 -07003075 transformedEvent = MotionEvent.obtain(event);
3076 } else {
Jeff Brownfe9f8ab2011-05-06 18:20:01 -07003077 transformedEvent = event.split(newPointerIdBits);
Adam Powell2b342f02010-08-18 18:14:13 -07003078 }
3079
Jeff Brown20e987b2010-08-23 12:01:02 -07003080 // Perform any necessary transformations and dispatch.
3081 if (child == null) {
3082 handled = super.dispatchTouchEvent(transformedEvent);
3083 } else {
3084 final float offsetX = mScrollX - child.mLeft;
3085 final float offsetY = mScrollY - child.mTop;
3086 transformedEvent.offsetLocation(offsetX, offsetY);
3087 if (! child.hasIdentityMatrix()) {
3088 transformedEvent.transform(child.getInverseMatrix());
Adam Powell2b342f02010-08-18 18:14:13 -07003089 }
3090
Jeff Brown20e987b2010-08-23 12:01:02 -07003091 handled = child.dispatchTouchEvent(transformedEvent);
Adam Powell2b342f02010-08-18 18:14:13 -07003092 }
3093
Jeff Brown20e987b2010-08-23 12:01:02 -07003094 // Done.
3095 transformedEvent.recycle();
Adam Powell2b342f02010-08-18 18:14:13 -07003096 return handled;
3097 }
3098
Romain Guy469b1db2010-10-05 11:49:57 -07003099 /**
Adam Powell2b342f02010-08-18 18:14:13 -07003100 * Enable or disable the splitting of MotionEvents to multiple children during touch event
Jeff Brown995e7742010-12-22 16:59:36 -08003101 * dispatch. This behavior is enabled by default for applications that target an
3102 * SDK version of {@link Build.VERSION_CODES#HONEYCOMB} or newer.
Adam Powell2b342f02010-08-18 18:14:13 -07003103 *
3104 * <p>When this option is enabled MotionEvents may be split and dispatched to different child
3105 * views depending on where each pointer initially went down. This allows for user interactions
3106 * such as scrolling two panes of content independently, chording of buttons, and performing
3107 * independent gestures on different pieces of content.
3108 *
3109 * @param split <code>true</code> to allow MotionEvents to be split and dispatched to multiple
3110 * child views. <code>false</code> to only allow one child view to be the target of
3111 * any MotionEvent received by this ViewGroup.
Scott Main27a85082013-06-10 10:39:48 -07003112 * @attr ref android.R.styleable#ViewGroup_splitMotionEvents
Adam Powell2b342f02010-08-18 18:14:13 -07003113 */
3114 public void setMotionEventSplittingEnabled(boolean split) {
3115 // TODO Applications really shouldn't change this setting mid-touch event,
3116 // but perhaps this should handle that case and send ACTION_CANCELs to any child views
3117 // with gestures in progress when this is changed.
3118 if (split) {
Adam Powell2b342f02010-08-18 18:14:13 -07003119 mGroupFlags |= FLAG_SPLIT_MOTION_EVENTS;
3120 } else {
3121 mGroupFlags &= ~FLAG_SPLIT_MOTION_EVENTS;
Adam Powell2b342f02010-08-18 18:14:13 -07003122 }
3123 }
3124
3125 /**
Jeff Brown995e7742010-12-22 16:59:36 -08003126 * Returns true if MotionEvents dispatched to this ViewGroup can be split to multiple children.
Adam Powell2b342f02010-08-18 18:14:13 -07003127 * @return true if MotionEvents dispatched to this ViewGroup can be split to multiple children.
3128 */
Ashley Rose55f9f922019-01-28 19:29:36 -05003129 @InspectableProperty(name = "splitMotionEvents")
Adam Powell2b342f02010-08-18 18:14:13 -07003130 public boolean isMotionEventSplittingEnabled() {
3131 return (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) == FLAG_SPLIT_MOTION_EVENTS;
3132 }
3133
3134 /**
George Mount0a778ed2013-12-13 13:35:36 -08003135 * Returns true if this ViewGroup should be considered as a single entity for removal
3136 * when executing an Activity transition. If this is false, child elements will move
3137 * individually during the transition.
George Mount427c6412014-11-05 16:45:36 -08003138 *
George Mount0a778ed2013-12-13 13:35:36 -08003139 * @return True if the ViewGroup should be acted on together during an Activity transition.
George Mount427c6412014-11-05 16:45:36 -08003140 * The default value is true when there is a non-null background or if
3141 * {@link #getTransitionName()} is not null or if a
3142 * non-null {@link android.view.ViewOutlineProvider} other than
3143 * {@link android.view.ViewOutlineProvider#BACKGROUND} was given to
3144 * {@link #setOutlineProvider(ViewOutlineProvider)} and false otherwise.
George Mount0a778ed2013-12-13 13:35:36 -08003145 */
Ashley Rose55f9f922019-01-28 19:29:36 -05003146 @InspectableProperty
George Mount0a778ed2013-12-13 13:35:36 -08003147 public boolean isTransitionGroup() {
3148 if ((mGroupFlags & FLAG_IS_TRANSITION_GROUP_SET) != 0) {
3149 return ((mGroupFlags & FLAG_IS_TRANSITION_GROUP) != 0);
3150 } else {
George Mount427c6412014-11-05 16:45:36 -08003151 final ViewOutlineProvider outlineProvider = getOutlineProvider();
3152 return getBackground() != null || getTransitionName() != null ||
3153 (outlineProvider != null && outlineProvider != ViewOutlineProvider.BACKGROUND);
George Mount0a778ed2013-12-13 13:35:36 -08003154 }
3155 }
3156
3157 /**
3158 * Changes whether or not this ViewGroup should be treated as a single entity during
George Mount31a21722014-03-24 17:44:36 -07003159 * Activity Transitions.
George Mount0a778ed2013-12-13 13:35:36 -08003160 * @param isTransitionGroup Whether or not the ViewGroup should be treated as a unit
3161 * in Activity transitions. If false, the ViewGroup won't transition,
3162 * only its children. If true, the entire ViewGroup will transition
3163 * together.
George Mount62ab9b72014-05-02 13:51:17 -07003164 * @see android.app.ActivityOptions#makeSceneTransitionAnimation(android.app.Activity,
3165 * android.util.Pair[])
George Mount0a778ed2013-12-13 13:35:36 -08003166 */
3167 public void setTransitionGroup(boolean isTransitionGroup) {
3168 mGroupFlags |= FLAG_IS_TRANSITION_GROUP_SET;
3169 if (isTransitionGroup) {
3170 mGroupFlags |= FLAG_IS_TRANSITION_GROUP;
3171 } else {
3172 mGroupFlags &= ~FLAG_IS_TRANSITION_GROUP;
3173 }
3174 }
3175
Alan Viverettebe463f22016-01-21 10:50:10 -05003176 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003177 public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
Romain Guy8506ab42009-06-11 17:35:47 -07003178
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003179 if (disallowIntercept == ((mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0)) {
3180 // We're already in this state, assume our ancestors are too
3181 return;
3182 }
Romain Guy8506ab42009-06-11 17:35:47 -07003183
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003184 if (disallowIntercept) {
3185 mGroupFlags |= FLAG_DISALLOW_INTERCEPT;
3186 } else {
3187 mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
3188 }
Romain Guy8506ab42009-06-11 17:35:47 -07003189
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003190 // Pass it up to our parent
3191 if (mParent != null) {
3192 mParent.requestDisallowInterceptTouchEvent(disallowIntercept);
3193 }
3194 }
3195
3196 /**
3197 * Implement this method to intercept all touch screen motion events. This
3198 * allows you to watch events as they are dispatched to your children, and
3199 * take ownership of the current gesture at any point.
3200 *
3201 * <p>Using this function takes some care, as it has a fairly complicated
3202 * interaction with {@link View#onTouchEvent(MotionEvent)
3203 * View.onTouchEvent(MotionEvent)}, and using it requires implementing
3204 * that method as well as this one in the correct way. Events will be
3205 * received in the following order:
3206 *
3207 * <ol>
3208 * <li> You will receive the down event here.
3209 * <li> The down event will be handled either by a child of this view
3210 * group, or given to your own onTouchEvent() method to handle; this means
3211 * you should implement onTouchEvent() to return true, so you will
3212 * continue to see the rest of the gesture (instead of looking for
3213 * a parent view to handle it). Also, by returning true from
3214 * onTouchEvent(), you will not receive any following
3215 * events in onInterceptTouchEvent() and all touch processing must
3216 * happen in onTouchEvent() like normal.
3217 * <li> For as long as you return false from this function, each following
3218 * event (up to and including the final up) will be delivered first here
3219 * and then to the target's onTouchEvent().
3220 * <li> If you return true from here, you will not receive any
3221 * following events: the target view will receive the same event but
3222 * with the action {@link MotionEvent#ACTION_CANCEL}, and all further
3223 * events will be delivered to your onTouchEvent() method and no longer
3224 * appear here.
3225 * </ol>
3226 *
3227 * @param ev The motion event being dispatched down the hierarchy.
3228 * @return Return true to steal motion events from the children and have
3229 * them dispatched to this ViewGroup through onTouchEvent().
3230 * The current target will receive an ACTION_CANCEL event, and no further
3231 * messages will be delivered here.
3232 */
3233 public boolean onInterceptTouchEvent(MotionEvent ev) {
Keisuke Kuroyanagid85bc502016-01-21 14:50:38 +09003234 if (ev.isFromSource(InputDevice.SOURCE_MOUSE)
3235 && ev.getAction() == MotionEvent.ACTION_DOWN
3236 && ev.isButtonPressed(MotionEvent.BUTTON_PRIMARY)
3237 && isOnScrollbarThumb(ev.getX(), ev.getY())) {
3238 return true;
3239 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003240 return false;
3241 }
3242
3243 /**
3244 * {@inheritDoc}
3245 *
3246 * Looks for a view to give focus to respecting the setting specified by
3247 * {@link #getDescendantFocusability()}.
3248 *
3249 * Uses {@link #onRequestFocusInDescendants(int, android.graphics.Rect)} to
3250 * find focus within the children of this group when appropriate.
3251 *
3252 * @see #FOCUS_BEFORE_DESCENDANTS
3253 * @see #FOCUS_AFTER_DESCENDANTS
3254 * @see #FOCUS_BLOCK_DESCENDANTS
Filip Gruszczynskia33bdf32015-11-19 18:22:16 -08003255 * @see #onRequestFocusInDescendants(int, android.graphics.Rect)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003256 */
3257 @Override
3258 public boolean requestFocus(int direction, Rect previouslyFocusedRect) {
3259 if (DBG) {
3260 System.out.println(this + " ViewGroup.requestFocus direction="
3261 + direction);
3262 }
3263 int descendantFocusability = getDescendantFocusability();
3264
Evan Rosky5db64eb2017-11-20 23:04:46 +00003265 boolean result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003266 switch (descendantFocusability) {
3267 case FOCUS_BLOCK_DESCENDANTS:
Evan Rosky5db64eb2017-11-20 23:04:46 +00003268 result = super.requestFocus(direction, previouslyFocusedRect);
3269 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003270 case FOCUS_BEFORE_DESCENDANTS: {
3271 final boolean took = super.requestFocus(direction, previouslyFocusedRect);
Evan Rosky5db64eb2017-11-20 23:04:46 +00003272 result = took ? took : onRequestFocusInDescendants(direction,
3273 previouslyFocusedRect);
3274 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003275 }
3276 case FOCUS_AFTER_DESCENDANTS: {
3277 final boolean took = onRequestFocusInDescendants(direction, previouslyFocusedRect);
Evan Rosky5db64eb2017-11-20 23:04:46 +00003278 result = took ? took : super.requestFocus(direction, previouslyFocusedRect);
3279 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003280 }
3281 default:
3282 throw new IllegalStateException("descendant focusability must be "
3283 + "one of FOCUS_BEFORE_DESCENDANTS, FOCUS_AFTER_DESCENDANTS, FOCUS_BLOCK_DESCENDANTS "
3284 + "but is " + descendantFocusability);
3285 }
Evan Rosky5db64eb2017-11-20 23:04:46 +00003286 if (result && !isLayoutValid() && ((mPrivateFlags & PFLAG_WANTS_FOCUS) == 0)) {
3287 mPrivateFlags |= PFLAG_WANTS_FOCUS;
3288 }
3289 return result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003290 }
3291
3292 /**
3293 * Look for a descendant to call {@link View#requestFocus} on.
3294 * Called by {@link ViewGroup#requestFocus(int, android.graphics.Rect)}
3295 * when it wants to request focus within its children. Override this to
3296 * customize how your {@link ViewGroup} requests focus within its children.
3297 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT
3298 * @param previouslyFocusedRect The rectangle (in this View's coordinate system)
3299 * to give a finer grained hint about where focus is coming from. May be null
3300 * if there is no hint.
3301 * @return Whether focus was taken.
3302 */
3303 @SuppressWarnings({"ConstantConditions"})
3304 protected boolean onRequestFocusInDescendants(int direction,
3305 Rect previouslyFocusedRect) {
3306 int index;
3307 int increment;
3308 int end;
3309 int count = mChildrenCount;
3310 if ((direction & FOCUS_FORWARD) != 0) {
3311 index = 0;
3312 increment = 1;
3313 end = count;
3314 } else {
3315 index = count - 1;
3316 increment = -1;
3317 end = -1;
3318 }
3319 final View[] children = mChildren;
3320 for (int i = index; i != end; i += increment) {
3321 View child = children[i];
Vadim Tryshevb5ced222017-01-17 19:31:35 -08003322 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003323 if (child.requestFocus(direction, previouslyFocusedRect)) {
3324 return true;
3325 }
3326 }
3327 }
3328 return false;
3329 }
Chet Haase5c13d892010-10-08 08:37:55 -07003330
Vadim Tryshev01d8c492016-12-15 11:33:15 -08003331 @Override
Evan Rosky53fcf112017-01-26 14:37:55 -08003332 public boolean restoreDefaultFocus() {
3333 if (mDefaultFocus != null
Vadim Tryshev01d8c492016-12-15 11:33:15 -08003334 && getDescendantFocusability() != FOCUS_BLOCK_DESCENDANTS
Vadim Tryshev5ca73982017-01-04 17:24:43 -08003335 && (mDefaultFocus.mViewFlags & VISIBILITY_MASK) == VISIBLE
Evan Rosky53fcf112017-01-26 14:37:55 -08003336 && mDefaultFocus.restoreDefaultFocus()) {
Vadim Tryshev01d8c492016-12-15 11:33:15 -08003337 return true;
3338 }
Evan Rosky53fcf112017-01-26 14:37:55 -08003339 return super.restoreDefaultFocus();
3340 }
3341
3342 /**
3343 * @hide
3344 */
Evan Rosky3ac64632017-02-13 18:04:43 -08003345 @TestApi
Evan Rosky53fcf112017-01-26 14:37:55 -08003346 @Override
3347 public boolean restoreFocusInCluster(@FocusRealDirection int direction) {
Evan Rosky18b886e2017-02-15 13:26:51 -08003348 // Allow cluster-navigation to enter touchscreenBlocksFocus ViewGroups.
3349 if (isKeyboardNavigationCluster()) {
3350 final boolean blockedFocus = getTouchscreenBlocksFocus();
3351 try {
3352 setTouchscreenBlocksFocusNoRefocus(false);
3353 return restoreFocusInClusterInternal(direction);
3354 } finally {
3355 setTouchscreenBlocksFocusNoRefocus(blockedFocus);
3356 }
3357 } else {
3358 return restoreFocusInClusterInternal(direction);
3359 }
3360 }
3361
3362 private boolean restoreFocusInClusterInternal(@FocusRealDirection int direction) {
Evan Rosky0e8a6832017-04-10 12:35:15 -07003363 if (mFocusedInCluster != null && getDescendantFocusability() != FOCUS_BLOCK_DESCENDANTS
Evan Rosky53fcf112017-01-26 14:37:55 -08003364 && (mFocusedInCluster.mViewFlags & VISIBILITY_MASK) == VISIBLE
3365 && mFocusedInCluster.restoreFocusInCluster(direction)) {
3366 return true;
3367 }
3368 return super.restoreFocusInCluster(direction);
Vadim Tryshev01d8c492016-12-15 11:33:15 -08003369 }
3370
Romain Guya440b002010-02-24 15:57:54 -08003371 /**
Evan Rosky3ac64632017-02-13 18:04:43 -08003372 * @hide
3373 */
3374 @Override
3375 public boolean restoreFocusNotInCluster() {
3376 if (mFocusedInCluster != null) {
3377 // since clusters don't nest; we can assume that a non-null mFocusedInCluster
3378 // will refer to a view not-in a cluster.
3379 return restoreFocusInCluster(View.FOCUS_DOWN);
3380 }
Evan Rosky2ae1bf52017-05-11 11:18:45 -07003381 if (isKeyboardNavigationCluster() || (mViewFlags & VISIBILITY_MASK) != VISIBLE) {
Evan Rosky3ac64632017-02-13 18:04:43 -08003382 return false;
3383 }
3384 int descendentFocusability = getDescendantFocusability();
3385 if (descendentFocusability == FOCUS_BLOCK_DESCENDANTS) {
3386 return super.requestFocus(FOCUS_DOWN, null);
3387 }
3388 if (descendentFocusability == FOCUS_BEFORE_DESCENDANTS
3389 && super.requestFocus(FOCUS_DOWN, null)) {
3390 return true;
3391 }
3392 for (int i = 0; i < mChildrenCount; ++i) {
3393 View child = mChildren[i];
3394 if (!child.isKeyboardNavigationCluster()
3395 && child.restoreFocusNotInCluster()) {
3396 return true;
3397 }
3398 }
Evan Rosky2ae1bf52017-05-11 11:18:45 -07003399 if (descendentFocusability == FOCUS_AFTER_DESCENDANTS && !hasFocusableChild(false)) {
Evan Rosky3ac64632017-02-13 18:04:43 -08003400 return super.requestFocus(FOCUS_DOWN, null);
3401 }
3402 return false;
3403 }
3404
3405 /**
Romain Guya440b002010-02-24 15:57:54 -08003406 * {@inheritDoc}
Chet Haase5c13d892010-10-08 08:37:55 -07003407 *
Romain Guydcc490f2010-02-24 17:59:35 -08003408 * @hide
Romain Guya440b002010-02-24 15:57:54 -08003409 */
3410 @Override
3411 public void dispatchStartTemporaryDetach() {
3412 super.dispatchStartTemporaryDetach();
3413 final int count = mChildrenCount;
3414 final View[] children = mChildren;
3415 for (int i = 0; i < count; i++) {
3416 children[i].dispatchStartTemporaryDetach();
3417 }
3418 }
Chet Haase5c13d892010-10-08 08:37:55 -07003419
Romain Guya440b002010-02-24 15:57:54 -08003420 /**
3421 * {@inheritDoc}
Chet Haase5c13d892010-10-08 08:37:55 -07003422 *
Romain Guydcc490f2010-02-24 17:59:35 -08003423 * @hide
Romain Guya440b002010-02-24 15:57:54 -08003424 */
3425 @Override
3426 public void dispatchFinishTemporaryDetach() {
3427 super.dispatchFinishTemporaryDetach();
3428 final int count = mChildrenCount;
3429 final View[] children = mChildren;
3430 for (int i = 0; i < count; i++) {
3431 children[i].dispatchFinishTemporaryDetach();
3432 }
3433 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003434
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003435 @Override
Mathew Inwooda570dee2018-08-17 14:56:00 +01003436 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003437 void dispatchAttachedToWindow(AttachInfo info, int visibility) {
Adam Powell4b867882011-09-16 12:59:46 -07003438 mGroupFlags |= FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003439 super.dispatchAttachedToWindow(info, visibility);
Adam Powell4b867882011-09-16 12:59:46 -07003440 mGroupFlags &= ~FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW;
3441
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003442 final int count = mChildrenCount;
3443 final View[] children = mChildren;
3444 for (int i = 0; i < count; i++) {
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07003445 final View child = children[i];
3446 child.dispatchAttachedToWindow(info,
Adam Powelleb2b0af2015-05-20 18:26:35 -07003447 combineVisibility(visibility, child.getVisibility()));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003448 }
Chet Haasec633d2f2015-04-07 10:29:39 -07003449 final int transientCount = mTransientIndices == null ? 0 : mTransientIndices.size();
3450 for (int i = 0; i < transientCount; ++i) {
3451 View view = mTransientViews.get(i);
Adam Powelleb2b0af2015-05-20 18:26:35 -07003452 view.dispatchAttachedToWindow(info,
3453 combineVisibility(visibility, view.getVisibility()));
Chet Haasec633d2f2015-04-07 10:29:39 -07003454 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003455 }
3456
svetoslavganov75986cf2009-05-14 22:28:01 -07003457 @Override
Romain Guybb9908b2012-03-08 11:14:07 -08003458 void dispatchScreenStateChanged(int screenState) {
3459 super.dispatchScreenStateChanged(screenState);
3460
3461 final int count = mChildrenCount;
3462 final View[] children = mChildren;
3463 for (int i = 0; i < count; i++) {
3464 children[i].dispatchScreenStateChanged(screenState);
3465 }
3466 }
3467
Andrii Kulianb047b8b2017-02-08 18:38:26 -08003468 @Override
Andrii Kuliane5c58ee2017-03-27 19:25:24 -07003469 void dispatchMovedToDisplay(Display display, Configuration config) {
3470 super.dispatchMovedToDisplay(display, config);
Andrii Kulianb047b8b2017-02-08 18:38:26 -08003471
3472 final int count = mChildrenCount;
3473 final View[] children = mChildren;
3474 for (int i = 0; i < count; i++) {
Andrii Kuliane5c58ee2017-03-27 19:25:24 -07003475 children[i].dispatchMovedToDisplay(display, config);
Andrii Kulianb047b8b2017-02-08 18:38:26 -08003476 }
3477 }
3478
Alan Viverettea54956a2015-01-07 16:05:02 -08003479 /** @hide */
Romain Guybb9908b2012-03-08 11:14:07 -08003480 @Override
Alan Viverettea54956a2015-01-07 16:05:02 -08003481 public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07003482 boolean handled = false;
3483 if (includeForAccessibility()) {
3484 handled = super.dispatchPopulateAccessibilityEventInternal(event);
3485 if (handled) {
3486 return handled;
3487 }
Svetoslav Ganovb84b94e2011-09-22 19:26:56 -07003488 }
Svetoslav Ganov736c2752011-04-22 18:30:36 -07003489 // Let our children have a shot in populating the event.
Svetoslav Ganov42138042012-03-20 11:51:39 -07003490 ChildListForAccessibility children = ChildListForAccessibility.obtain(this, true);
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07003491 try {
3492 final int childCount = children.getChildCount();
3493 for (int i = 0; i < childCount; i++) {
3494 View child = children.getChildAt(i);
3495 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
3496 handled = child.dispatchPopulateAccessibilityEvent(event);
3497 if (handled) {
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07003498 return handled;
3499 }
Svetoslav Ganov6179ea32011-06-28 01:12:41 -07003500 }
Svetoslav Ganov736c2752011-04-22 18:30:36 -07003501 }
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07003502 } finally {
3503 children.recycle();
svetoslavganov75986cf2009-05-14 22:28:01 -07003504 }
Svetoslav Ganov736c2752011-04-22 18:30:36 -07003505 return false;
svetoslavganov75986cf2009-05-14 22:28:01 -07003506 }
3507
Dianne Hackborn6251f0d2015-04-01 16:45:03 -07003508 /**
Felipe Leme6d553872016-12-08 17:13:25 -08003509 * Dispatch creation of {@link ViewStructure} down the hierarchy. This implementation
3510 * adds in all child views of the view group, in addition to calling the default View
3511 * implementation.
3512 */
3513 @Override
3514 public void dispatchProvideStructure(ViewStructure structure) {
3515 super.dispatchProvideStructure(structure);
Svet Ganov2f8fb1f2017-03-13 00:21:04 -07003516 if (isAssistBlocked() || structure.getChildCount() != 0) {
3517 return;
3518 }
3519 final int childrenCount = mChildrenCount;
3520 if (childrenCount <= 0) {
3521 return;
3522 }
Philip P. Moltmann083d8aa2017-08-15 15:22:37 -07003523
3524 if (!isLaidOut()) {
Felipe Lemefe05a522018-01-23 15:57:49 -08003525 if (Helper.sVerbose) {
3526 Log.v(VIEW_LOG_TAG, "dispatchProvideStructure(): not laid out, ignoring "
3527 + childrenCount + " children of " + getAccessibilityViewId());
3528 }
Philip P. Moltmann083d8aa2017-08-15 15:22:37 -07003529 return;
3530 }
3531
Svet Ganov2f8fb1f2017-03-13 00:21:04 -07003532 structure.setChildCount(childrenCount);
3533 ArrayList<View> preorderedList = buildOrderedChildList();
3534 boolean customOrder = preorderedList == null
3535 && isChildrenDrawingOrderEnabled();
3536 for (int i = 0; i < childrenCount; i++) {
3537 int childIndex;
3538 try {
3539 childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
3540 } catch (IndexOutOfBoundsException e) {
3541 childIndex = i;
3542 if (mContext.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.M) {
3543 Log.w(TAG, "Bad getChildDrawingOrder while collecting assist @ "
3544 + i + " of " + childrenCount, e);
3545 // At least one app is failing when we call getChildDrawingOrder
3546 // at this point, so deal semi-gracefully with it by falling back
3547 // on the basic order.
3548 customOrder = false;
3549 if (i > 0) {
3550 // If we failed at the first index, there really isn't
3551 // anything to do -- we will just proceed with the simple
3552 // sequence order.
3553 // Otherwise, we failed in the middle, so need to come up
3554 // with an order for the remaining indices and use that.
3555 // Failed at the first one, easy peasy.
3556 int[] permutation = new int[childrenCount];
3557 SparseBooleanArray usedIndices = new SparseBooleanArray();
3558 // Go back and collected the indices we have done so far.
3559 for (int j = 0; j < i; j++) {
3560 permutation[j] = getChildDrawingOrder(childrenCount, j);
3561 usedIndices.put(permutation[j], true);
3562 }
3563 // Fill in the remaining indices with indices that have not
3564 // yet been used.
3565 int nextIndex = 0;
3566 for (int j = i; j < childrenCount; j++) {
3567 while (usedIndices.get(nextIndex, false)) {
3568 nextIndex++;
3569 }
3570 permutation[j] = nextIndex;
3571 nextIndex++;
3572 }
3573 // Build the final view list.
3574 preorderedList = new ArrayList<>(childrenCount);
3575 for (int j = 0; j < childrenCount; j++) {
3576 final int index = permutation[j];
3577 final View child = mChildren[index];
3578 preorderedList.add(child);
3579 }
3580 }
3581 } else {
3582 throw e;
3583 }
3584 }
3585 final View child = getAndVerifyPreorderedView(preorderedList, mChildren,
3586 childIndex);
3587 final ViewStructure cstructure = structure.newChild(i);
3588 child.dispatchProvideStructure(cstructure);
3589 }
3590 if (preorderedList != null) {
3591 preorderedList.clear();
3592 }
Felipe Leme6d553872016-12-08 17:13:25 -08003593 }
3594
3595 /**
Felipe Leme1ca634a2016-11-28 17:21:21 -08003596 * {@inheritDoc}
3597 *
3598 * <p>This implementation adds in all child views of the view group, in addition to calling the
3599 * default {@link View} implementation.
Dianne Hackborn6251f0d2015-04-01 16:45:03 -07003600 */
Alan Viverettebe463f22016-01-21 10:50:10 -05003601 @Override
Svet Ganovfd31f852017-04-26 15:54:27 -07003602 public void dispatchProvideAutofillStructure(ViewStructure structure,
3603 @AutofillFlags int flags) {
Felipe Leme640f30a2017-03-06 15:44:06 -08003604 super.dispatchProvideAutofillStructure(structure, flags);
Svetoslav Ganov24c90452017-12-27 15:17:14 -08003605
Svet Ganovfd31f852017-04-26 15:54:27 -07003606 if (structure.getChildCount() != 0) {
Svet Ganov2f8fb1f2017-03-13 00:21:04 -07003607 return;
3608 }
Philip P. Moltmann083d8aa2017-08-15 15:22:37 -07003609
3610 if (!isLaidOut()) {
Svetoslav Ganov24c90452017-12-27 15:17:14 -08003611 if (Helper.sVerbose) {
3612 Log.v(VIEW_LOG_TAG, "dispatchProvideAutofillStructure(): not laid out, ignoring "
3613 + mChildrenCount + " children of " + getAutofillId());
3614 }
Philip P. Moltmann083d8aa2017-08-15 15:22:37 -07003615 return;
3616 }
3617
Felipe Leme01297692019-01-29 18:16:23 -08003618 final ChildListForAutoFillOrContentCapture children = getChildrenForAutofill(flags);
Svet Ganov2f8fb1f2017-03-13 00:21:04 -07003619 final int childrenCount = children.size();
3620 structure.setChildCount(childrenCount);
3621 for (int i = 0; i < childrenCount; i++) {
3622 final View child = children.get(i);
3623 final ViewStructure cstructure = structure.newChild(i);
3624 child.dispatchProvideAutofillStructure(cstructure, flags);
3625 }
3626 children.recycle();
Felipe Leme6d553872016-12-08 17:13:25 -08003627 }
Felipe Leme1ca634a2016-11-28 17:21:21 -08003628
Felipe Leme01297692019-01-29 18:16:23 -08003629 /** @hide */
3630 @Override
3631 public void dispatchProvideContentCaptureStructure() {
3632 super.dispatchProvideContentCaptureStructure();
3633
3634 if (!isLaidOut()) return;
3635
3636 final ChildListForAutoFillOrContentCapture children = getChildrenForContentCapture();
3637 final int childrenCount = children.size();
3638 for (int i = 0; i < childrenCount; i++) {
3639 final View child = children.get(i);
3640 child.dispatchProvideContentCaptureStructure();
3641 }
3642 children.recycle();
3643 }
3644
Svet Ganov2f8fb1f2017-03-13 00:21:04 -07003645 /**
3646 * Gets the children for autofill. Children for autofill are the first
3647 * level descendants that are important for autofill. The returned
3648 * child list object is pooled and the caller must recycle it once done.
3649 * @hide */
Felipe Leme01297692019-01-29 18:16:23 -08003650 private @NonNull ChildListForAutoFillOrContentCapture getChildrenForAutofill(
3651 @AutofillFlags int flags) {
3652 final ChildListForAutoFillOrContentCapture children = ChildListForAutoFillOrContentCapture
3653 .obtain();
Svet Ganovfd31f852017-04-26 15:54:27 -07003654 populateChildrenForAutofill(children, flags);
Svet Ganov2f8fb1f2017-03-13 00:21:04 -07003655 return children;
Felipe Lemed04a6972017-03-02 12:56:18 -08003656 }
3657
3658 /** @hide */
Svet Ganovfd31f852017-04-26 15:54:27 -07003659 private void populateChildrenForAutofill(ArrayList<View> list, @AutofillFlags int flags) {
Svet Ganov2f8fb1f2017-03-13 00:21:04 -07003660 final int childrenCount = mChildrenCount;
3661 if (childrenCount <= 0) {
3662 return;
3663 }
3664 final ArrayList<View> preorderedList = buildOrderedChildList();
3665 final boolean customOrder = preorderedList == null
3666 && isChildrenDrawingOrderEnabled();
3667 for (int i = 0; i < childrenCount; i++) {
3668 final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
3669 final View child = (preorderedList == null)
3670 ? mChildren[childIndex] : preorderedList.get(childIndex);
Svet Ganovfd31f852017-04-26 15:54:27 -07003671 if ((flags & AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) != 0
3672 || child.isImportantForAutofill()) {
Felipe Lemed04a6972017-03-02 12:56:18 -08003673 list.add(child);
3674 } else if (child instanceof ViewGroup) {
Svet Ganovfd31f852017-04-26 15:54:27 -07003675 ((ViewGroup) child).populateChildrenForAutofill(list, flags);
Felipe Lemed04a6972017-03-02 12:56:18 -08003676 }
3677 }
3678 }
3679
Felipe Leme01297692019-01-29 18:16:23 -08003680 private @NonNull ChildListForAutoFillOrContentCapture getChildrenForContentCapture() {
3681 final ChildListForAutoFillOrContentCapture children = ChildListForAutoFillOrContentCapture
3682 .obtain();
3683 populateChildrenForContentCapture(children);
3684 return children;
3685 }
3686
3687 /** @hide */
3688 private void populateChildrenForContentCapture(ArrayList<View> list) {
3689 final int childrenCount = mChildrenCount;
3690 if (childrenCount <= 0) {
3691 return;
3692 }
3693 final ArrayList<View> preorderedList = buildOrderedChildList();
3694 final boolean customOrder = preorderedList == null
3695 && isChildrenDrawingOrderEnabled();
3696 for (int i = 0; i < childrenCount; i++) {
3697 final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
3698 final View child = (preorderedList == null)
3699 ? mChildren[childIndex] : preorderedList.get(childIndex);
3700 if (child.isImportantForContentCapture()) {
3701 list.add(child);
3702 } else if (child instanceof ViewGroup) {
3703 ((ViewGroup) child).populateChildrenForContentCapture(list);
3704 }
3705 }
3706 }
3707
Alan Viverettea7b85e62016-01-22 10:14:02 -05003708 private static View getAndVerifyPreorderedView(ArrayList<View> preorderedList, View[] children,
3709 int childIndex) {
3710 final View child;
3711 if (preorderedList != null) {
3712 child = preorderedList.get(childIndex);
3713 if (child == null) {
3714 throw new RuntimeException("Invalid preorderedList contained null child at index "
3715 + childIndex);
3716 }
3717 } else {
3718 child = children[childIndex];
3719 }
3720 return child;
3721 }
3722
Alan Viverettea54956a2015-01-07 16:05:02 -08003723 /** @hide */
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003724 @Override
Mathew Inwooda570dee2018-08-17 14:56:00 +01003725 @UnsupportedAppUsage
Alan Viverettea54956a2015-01-07 16:05:02 -08003726 public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
Svetoslav Ganov031d9c12011-09-09 16:41:13 -07003727 super.onInitializeAccessibilityNodeInfoInternal(info);
Svet Ganov55bdb102015-02-06 12:41:17 -08003728 if (getAccessibilityNodeProvider() != null) {
3729 return;
3730 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07003731 if (mAttachInfo != null) {
Alan Viverettef0aed092013-11-06 15:33:03 -08003732 final ArrayList<View> childrenForAccessibility = mAttachInfo.mTempArrayList;
Svetoslav Ganov42138042012-03-20 11:51:39 -07003733 childrenForAccessibility.clear();
3734 addChildrenForAccessibility(childrenForAccessibility);
3735 final int childrenForAccessibilityCount = childrenForAccessibility.size();
3736 for (int i = 0; i < childrenForAccessibilityCount; i++) {
Alan Viverettef0aed092013-11-06 15:33:03 -08003737 final View child = childrenForAccessibility.get(i);
3738 info.addChildUnchecked(child);
Svetoslav Ganovea1da3d2011-06-15 17:16:02 -07003739 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07003740 childrenForAccessibility.clear();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003741 }
3742 }
3743
Svetoslav Ganov8a78fd42012-01-17 14:36:46 -08003744 @Override
Maxim Bogatovf399af32015-06-16 15:15:49 -07003745 public CharSequence getAccessibilityClassName() {
3746 return ViewGroup.class.getName();
Svetoslav Ganov8a78fd42012-01-17 14:36:46 -08003747 }
3748
Eugene Susla72c510f2018-01-23 21:12:11 +00003749 @Override
3750 public void notifySubtreeAccessibilityStateChanged(View child, View source, int changeType) {
3751 // If this is a live region, we should send a subtree change event
3752 // from this view. Otherwise, we can let it propagate up.
3753 if (getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE) {
3754 notifyViewAccessibilityStateChangedIfNeeded(
3755 AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE);
3756 } else if (mParent != null) {
3757 try {
3758 mParent.notifySubtreeAccessibilityStateChanged(this, source, changeType);
3759 } catch (AbstractMethodError e) {
3760 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() +
3761 " does not fully implement ViewParent", e);
3762 }
3763 }
3764 }
3765
Phil Weaver4d3eec412016-09-01 16:28:34 -07003766 /** @hide */
3767 @Override
Eugene Susla72c510f2018-01-23 21:12:11 +00003768 public void notifySubtreeAccessibilityStateChangedIfNeeded() {
Phil Weaver4d3eec412016-09-01 16:28:34 -07003769 if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) {
3770 return;
3771 }
3772 // If something important for a11y is happening in this subtree, make sure it's dispatched
3773 // from a view that is important for a11y so it doesn't get lost.
Eugene Susla72c510f2018-01-23 21:12:11 +00003774 if ((getImportantForAccessibility() != IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS)
3775 && !isImportantForAccessibility() && (getChildCount() > 0)) {
Phil Weaver4d3eec412016-09-01 16:28:34 -07003776 ViewParent a11yParent = getParentForAccessibility();
3777 if (a11yParent instanceof View) {
Eugene Susla72c510f2018-01-23 21:12:11 +00003778 ((View) a11yParent).notifySubtreeAccessibilityStateChangedIfNeeded();
Phil Weaver4d3eec412016-09-01 16:28:34 -07003779 return;
3780 }
3781 }
Eugene Susla72c510f2018-01-23 21:12:11 +00003782 super.notifySubtreeAccessibilityStateChangedIfNeeded();
Phil Weaver4d3eec412016-09-01 16:28:34 -07003783 }
3784
Svetoslav6254f482013-06-04 17:22:14 -07003785 @Override
Eugene Susla72c510f2018-01-23 21:12:11 +00003786 void resetSubtreeAccessibilityStateChanged() {
Svetoslav6254f482013-06-04 17:22:14 -07003787 super.resetSubtreeAccessibilityStateChanged();
Svetoslav Ganov42138042012-03-20 11:51:39 -07003788 View[] children = mChildren;
3789 final int childCount = mChildrenCount;
3790 for (int i = 0; i < childCount; i++) {
Svetoslav6254f482013-06-04 17:22:14 -07003791 children[i].resetSubtreeAccessibilityStateChanged();
Svetoslav Ganov42138042012-03-20 11:51:39 -07003792 }
3793 }
3794
3795 /**
Phil Weaver1f222542016-01-08 11:49:32 -08003796 * Counts the number of children of this View that will be sent to an accessibility service.
3797 *
3798 * @return The number of children an {@code AccessibilityNodeInfo} rooted at this View
3799 * would have.
3800 */
3801 int getNumChildrenForAccessibility() {
3802 int numChildrenForAccessibility = 0;
3803 for (int i = 0; i < getChildCount(); i++) {
3804 View child = getChildAt(i);
3805 if (child.includeForAccessibility()) {
3806 numChildrenForAccessibility++;
3807 } else if (child instanceof ViewGroup) {
3808 numChildrenForAccessibility += ((ViewGroup) child)
3809 .getNumChildrenForAccessibility();
3810 }
3811 }
3812 return numChildrenForAccessibility;
3813 }
3814
3815 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003816 * {@inheritDoc}
Adam Powellb6ab0982015-01-07 17:00:12 -08003817 *
3818 * <p>Subclasses should always call <code>super.onNestedPrePerformAccessibilityAction</code></p>
3819 *
3820 * @param target The target view dispatching this action
3821 * @param action Action being performed; see
3822 * {@link android.view.accessibility.AccessibilityNodeInfo}
3823 * @param args Optional action arguments
3824 * @return false by default. Subclasses should return true if they handle the event.
3825 */
3826 @Override
3827 public boolean onNestedPrePerformAccessibilityAction(View target, int action, Bundle args) {
3828 return false;
3829 }
3830
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003831 @Override
Mathew Inwooda570dee2018-08-17 14:56:00 +01003832 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003833 void dispatchDetachedFromWindow() {
Jeff Brown20e987b2010-08-23 12:01:02 -07003834 // If we still have a touch target, we are still in the process of
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003835 // dispatching motion events to a child; we need to get rid of that
3836 // child to avoid dispatching events to it after the window is torn
3837 // down. To make sure we keep the child in a consistent state, we
3838 // first send it an ACTION_CANCEL motion event.
Jeff Brown20e987b2010-08-23 12:01:02 -07003839 cancelAndClearTouchTargets(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003840
Jeff Brown59a422e2012-04-19 15:19:19 -07003841 // Similarly, set ACTION_EXIT to all hover targets and clear them.
3842 exitHoverTargets();
Vladislav Kaznacheevf847ee32016-11-21 14:11:00 -08003843 exitTooltipHoverTargets();
Jeff Brown59a422e2012-04-19 15:19:19 -07003844
Chet Haase9c087442011-01-12 16:20:16 -08003845 // In case view is detached while transition is running
Chet Haaseb9895022013-04-02 15:10:58 -07003846 mLayoutCalledWhileSuppressed = false;
Chet Haase9c087442011-01-12 16:20:16 -08003847
Christopher Tate86cab1b2011-01-13 20:28:55 -08003848 // Tear down our drag tracking
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07003849 mChildrenInterestedInDrag = null;
3850 mIsInterestedInDrag = false;
3851 if (mCurrentDragStartEvent != null) {
3852 mCurrentDragStartEvent.recycle();
3853 mCurrentDragStartEvent = null;
Christopher Tate86cab1b2011-01-13 20:28:55 -08003854 }
3855
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003856 final int count = mChildrenCount;
3857 final View[] children = mChildren;
3858 for (int i = 0; i < count; i++) {
3859 children[i].dispatchDetachedFromWindow();
3860 }
John Reckca7a9da2014-03-05 16:29:07 -08003861 clearDisappearingChildren();
Chet Haasec633d2f2015-04-07 10:29:39 -07003862 final int transientCount = mTransientViews == null ? 0 : mTransientIndices.size();
3863 for (int i = 0; i < transientCount; ++i) {
3864 View view = mTransientViews.get(i);
3865 view.dispatchDetachedFromWindow();
3866 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003867 super.dispatchDetachedFromWindow();
3868 }
3869
Fabrice Di Meglio23c89fd2012-08-13 12:17:42 -07003870 /**
3871 * @hide
3872 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003873 @Override
Fabrice Di Meglio23c89fd2012-08-13 12:17:42 -07003874 protected void internalSetPadding(int left, int top, int right, int bottom) {
Romain Guy2440e672012-08-07 14:43:43 -07003875 super.internalSetPadding(left, top, right, bottom);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003876
Romain Guy13f35f32011-03-24 12:03:17 -07003877 if ((mPaddingLeft | mPaddingTop | mPaddingRight | mPaddingBottom) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003878 mGroupFlags |= FLAG_PADDING_NOT_NULL;
3879 } else {
3880 mGroupFlags &= ~FLAG_PADDING_NOT_NULL;
3881 }
3882 }
3883
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003884 @Override
3885 protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
3886 super.dispatchSaveInstanceState(container);
3887 final int count = mChildrenCount;
3888 final View[] children = mChildren;
3889 for (int i = 0; i < count; i++) {
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07003890 View c = children[i];
3891 if ((c.mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED) {
3892 c.dispatchSaveInstanceState(container);
3893 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003894 }
3895 }
3896
3897 /**
Romain Guy9fc27812011-04-27 14:21:41 -07003898 * Perform dispatching of a {@link #saveHierarchyState(android.util.SparseArray)} freeze()}
3899 * to only this view, not to its children. For use when overriding
3900 * {@link #dispatchSaveInstanceState(android.util.SparseArray)} dispatchFreeze()} to allow
3901 * subclasses to freeze their own state but not the state of their children.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003902 *
3903 * @param container the container
3904 */
3905 protected void dispatchFreezeSelfOnly(SparseArray<Parcelable> container) {
3906 super.dispatchSaveInstanceState(container);
3907 }
3908
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003909 @Override
3910 protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
3911 super.dispatchRestoreInstanceState(container);
3912 final int count = mChildrenCount;
3913 final View[] children = mChildren;
3914 for (int i = 0; i < count; i++) {
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07003915 View c = children[i];
3916 if ((c.mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED) {
3917 c.dispatchRestoreInstanceState(container);
3918 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003919 }
3920 }
3921
3922 /**
Romain Guy02739a82011-05-16 11:43:18 -07003923 * Perform dispatching of a {@link #restoreHierarchyState(android.util.SparseArray)}
3924 * to only this view, not to its children. For use when overriding
3925 * {@link #dispatchRestoreInstanceState(android.util.SparseArray)} to allow
3926 * subclasses to thaw their own state but not the state of their children.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003927 *
3928 * @param container the container
3929 */
3930 protected void dispatchThawSelfOnly(SparseArray<Parcelable> container) {
3931 super.dispatchRestoreInstanceState(container);
3932 }
3933
3934 /**
3935 * Enables or disables the drawing cache for each child of this view group.
3936 *
3937 * @param enabled true to enable the cache, false to dispose of it
John Reck949cfe12017-10-09 13:27:03 -07003938 *
3939 * @deprecated The view drawing cache was largely made obsolete with the introduction of
3940 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache
3941 * layers are largely unnecessary and can easily result in a net loss in performance due to the
3942 * cost of creating and updating the layer. In the rare cases where caching layers are useful,
3943 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware
3944 * rendering. For software-rendered snapshots of a small part of the View hierarchy or
3945 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or
3946 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these
3947 * software-rendered usages are discouraged and have compatibility issues with hardware-only
3948 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE}
3949 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback
3950 * reports or unit testing the {@link PixelCopy} API is recommended.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003951 */
John Reck949cfe12017-10-09 13:27:03 -07003952 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003953 protected void setChildrenDrawingCacheEnabled(boolean enabled) {
3954 if (enabled || (mPersistentDrawingCache & PERSISTENT_ALL_CACHES) != PERSISTENT_ALL_CACHES) {
3955 final View[] children = mChildren;
3956 final int count = mChildrenCount;
3957 for (int i = 0; i < count; i++) {
3958 children[i].setDrawingCacheEnabled(enabled);
3959 }
3960 }
3961 }
3962
sergeyvb37d44e2016-03-29 20:27:44 -07003963 /**
3964 * @hide
3965 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003966 @Override
Sunny Goyald1b287e2018-01-04 09:37:22 -08003967 public Bitmap createSnapshot(ViewDebug.CanvasProvider canvasProvider, boolean skipChildren) {
Romain Guy65554f22010-03-22 18:58:21 -07003968 int count = mChildrenCount;
3969 int[] visibilities = null;
3970
Romain Guy223ff5c2010-03-02 17:07:47 -08003971 if (skipChildren) {
Romain Guy65554f22010-03-22 18:58:21 -07003972 visibilities = new int[count];
3973 for (int i = 0; i < count; i++) {
3974 View child = getChildAt(i);
3975 visibilities[i] = child.getVisibility();
3976 if (visibilities[i] == View.VISIBLE) {
sergeyvb37d44e2016-03-29 20:27:44 -07003977 child.mViewFlags = (child.mViewFlags & ~View.VISIBILITY_MASK)
3978 | (View.INVISIBLE & View.VISIBILITY_MASK);
Romain Guy65554f22010-03-22 18:58:21 -07003979 }
3980 }
Romain Guy223ff5c2010-03-02 17:07:47 -08003981 }
3982
Sunny Goyald1b287e2018-01-04 09:37:22 -08003983 try {
3984 return super.createSnapshot(canvasProvider, skipChildren);
3985 } finally {
3986 if (skipChildren) {
3987 for (int i = 0; i < count; i++) {
3988 View child = getChildAt(i);
3989 child.mViewFlags = (child.mViewFlags & ~View.VISIBILITY_MASK)
3990 | (visibilities[i] & View.VISIBILITY_MASK);
3991 }
Chet Haase5c13d892010-10-08 08:37:55 -07003992 }
Romain Guy65554f22010-03-22 18:58:21 -07003993 }
Romain Guy223ff5c2010-03-02 17:07:47 -08003994 }
3995
Philip Milne7b757812012-09-19 18:13:44 -07003996 /** Return true if this ViewGroup is laying out using optical bounds. */
3997 boolean isLayoutModeOptical() {
3998 return mLayoutMode == LAYOUT_MODE_OPTICAL_BOUNDS;
3999 }
Romain Guycbc67742012-04-27 16:12:57 -07004000
Alan Viverettebe463f22016-01-21 10:50:10 -05004001 @Override
Philip Milne7b757812012-09-19 18:13:44 -07004002 Insets computeOpticalInsets() {
4003 if (isLayoutModeOptical()) {
4004 int left = 0;
4005 int top = 0;
4006 int right = 0;
4007 int bottom = 0;
4008 for (int i = 0; i < mChildrenCount; i++) {
4009 View child = getChildAt(i);
4010 if (child.getVisibility() == VISIBLE) {
4011 Insets insets = child.getOpticalInsets();
4012 left = Math.max(left, insets.left);
4013 top = Math.max(top, insets.top);
4014 right = Math.max(right, insets.right);
4015 bottom = Math.max(bottom, insets.bottom);
4016 }
4017 }
4018 return Insets.of(left, top, right, bottom);
4019 } else {
4020 return Insets.NONE;
4021 }
4022 }
4023
4024 private static void fillRect(Canvas canvas, Paint paint, int x1, int y1, int x2, int y2) {
4025 if (x1 != x2 && y1 != y2) {
4026 if (x1 > x2) {
4027 int tmp = x1; x1 = x2; x2 = tmp;
4028 }
4029 if (y1 > y2) {
4030 int tmp = y1; y1 = y2; y2 = tmp;
4031 }
4032 canvas.drawRect(x1, y1, x2, y2, paint);
4033 }
4034 }
4035
4036 private static int sign(int x) {
4037 return (x >= 0) ? 1 : -1;
4038 }
4039
4040 private static void drawCorner(Canvas c, Paint paint, int x1, int y1, int dx, int dy, int lw) {
4041 fillRect(c, paint, x1, y1, x1 + dx, y1 + lw * sign(dy));
4042 fillRect(c, paint, x1, y1, x1 + lw * sign(dx), y1 + dy);
4043 }
4044
Romain Guy6410c0a2013-06-17 11:21:58 -07004045 private static void drawRectCorners(Canvas canvas, int x1, int y1, int x2, int y2, Paint paint,
4046 int lineLength, int lineWidth) {
Philip Milne7b757812012-09-19 18:13:44 -07004047 drawCorner(canvas, paint, x1, y1, lineLength, lineLength, lineWidth);
4048 drawCorner(canvas, paint, x1, y2, lineLength, -lineLength, lineWidth);
4049 drawCorner(canvas, paint, x2, y1, -lineLength, lineLength, lineWidth);
4050 drawCorner(canvas, paint, x2, y2, -lineLength, -lineLength, lineWidth);
4051 }
4052
4053 private static void fillDifference(Canvas canvas,
4054 int x2, int y2, int x3, int y3,
4055 int dx1, int dy1, int dx2, int dy2, Paint paint) {
4056 int x1 = x2 - dx1;
4057 int y1 = y2 - dy1;
4058
4059 int x4 = x3 + dx2;
4060 int y4 = y3 + dy2;
4061
4062 fillRect(canvas, paint, x1, y1, x4, y2);
4063 fillRect(canvas, paint, x1, y2, x2, y3);
4064 fillRect(canvas, paint, x3, y2, x4, y3);
4065 fillRect(canvas, paint, x1, y3, x4, y4);
Philip Milne10ca24a2012-04-23 15:38:27 -07004066 }
4067
4068 /**
Alan Viverette2d7771c2018-01-31 17:04:31 -05004069 * @hide
Philip Milne10ca24a2012-04-23 15:38:27 -07004070 */
Philip Milne7b757812012-09-19 18:13:44 -07004071 protected void onDebugDrawMargins(Canvas canvas, Paint paint) {
Philip Milne10ca24a2012-04-23 15:38:27 -07004072 for (int i = 0; i < getChildCount(); i++) {
4073 View c = getChildAt(i);
Philip Milne7b757812012-09-19 18:13:44 -07004074 c.getLayoutParams().onDebugDraw(c, canvas, paint);
Philip Milne10ca24a2012-04-23 15:38:27 -07004075 }
4076 }
4077
4078 /**
Alan Viverette2d7771c2018-01-31 17:04:31 -05004079 * @hide
Philip Milne10ca24a2012-04-23 15:38:27 -07004080 */
4081 protected void onDebugDraw(Canvas canvas) {
Philip Milne7b757812012-09-19 18:13:44 -07004082 Paint paint = getDebugPaint();
4083
Philip Milne10ca24a2012-04-23 15:38:27 -07004084 // Draw optical bounds
Philip Milne7b757812012-09-19 18:13:44 -07004085 {
4086 paint.setColor(Color.RED);
4087 paint.setStyle(Paint.Style.STROKE);
Philip Milne7b757812012-09-19 18:13:44 -07004088
Philip Milne10ca24a2012-04-23 15:38:27 -07004089 for (int i = 0; i < getChildCount(); i++) {
4090 View c = getChildAt(i);
Chris Craika1dab8b2015-06-30 13:51:25 -07004091 if (c.getVisibility() != View.GONE) {
4092 Insets insets = c.getOpticalInsets();
Philip Milne7b757812012-09-19 18:13:44 -07004093
Chris Craika1dab8b2015-06-30 13:51:25 -07004094 drawRect(canvas, paint,
4095 c.getLeft() + insets.left,
4096 c.getTop() + insets.top,
4097 c.getRight() - insets.right - 1,
4098 c.getBottom() - insets.bottom - 1);
4099 }
Philip Milne10ca24a2012-04-23 15:38:27 -07004100 }
4101 }
4102
Philip Milne10ca24a2012-04-23 15:38:27 -07004103 // Draw margins
Philip Milne7b757812012-09-19 18:13:44 -07004104 {
4105 paint.setColor(Color.argb(63, 255, 0, 255));
4106 paint.setStyle(Paint.Style.FILL);
Philip Milne604f4402012-04-24 19:27:11 -07004107
Philip Milne7b757812012-09-19 18:13:44 -07004108 onDebugDrawMargins(canvas, paint);
4109 }
4110
4111 // Draw clip bounds
4112 {
Vadim Tryshevcdf38ba2016-10-11 18:33:10 -07004113 paint.setColor(DEBUG_CORNERS_COLOR);
Philip Milne7b757812012-09-19 18:13:44 -07004114 paint.setStyle(Paint.Style.FILL);
4115
Vadim Tryshevcdf38ba2016-10-11 18:33:10 -07004116 int lineLength = dipsToPixels(DEBUG_CORNERS_SIZE_DIP);
Philip Milne7b757812012-09-19 18:13:44 -07004117 int lineWidth = dipsToPixels(1);
4118 for (int i = 0; i < getChildCount(); i++) {
4119 View c = getChildAt(i);
Chris Craika1dab8b2015-06-30 13:51:25 -07004120 if (c.getVisibility() != View.GONE) {
4121 drawRectCorners(canvas, c.getLeft(), c.getTop(), c.getRight(), c.getBottom(),
4122 paint, lineLength, lineWidth);
4123 }
Philip Milne7b757812012-09-19 18:13:44 -07004124 }
Philip Milne604f4402012-04-24 19:27:11 -07004125 }
Philip Milne10ca24a2012-04-23 15:38:27 -07004126 }
4127
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004128 @Override
4129 protected void dispatchDraw(Canvas canvas) {
Chris Craika753f4c2014-07-24 12:39:17 -07004130 boolean usingRenderNodeProperties = canvas.isRecordingFor(mRenderNode);
Chris Craikab008f02014-05-23 17:55:03 -07004131 final int childrenCount = mChildrenCount;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004132 final View[] children = mChildren;
4133 int flags = mGroupFlags;
4134
4135 if ((flags & FLAG_RUN_ANIMATION) != 0 && canAnimate()) {
Romain Guy0d9275e2010-10-26 14:22:30 -07004136 final boolean buildCache = !isHardwareAccelerated();
Chris Craikab008f02014-05-23 17:55:03 -07004137 for (int i = 0; i < childrenCount; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004138 final View child = children[i];
4139 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
4140 final LayoutParams params = child.getLayoutParams();
Chris Craikab008f02014-05-23 17:55:03 -07004141 attachLayoutAnimationParameters(child, params, i, childrenCount);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004142 bindLayoutAnimation(child);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004143 }
4144 }
4145
4146 final LayoutAnimationController controller = mLayoutAnimationController;
4147 if (controller.willOverlap()) {
4148 mGroupFlags |= FLAG_OPTIMIZE_INVALIDATE;
4149 }
4150
4151 controller.start();
4152
4153 mGroupFlags &= ~FLAG_RUN_ANIMATION;
4154 mGroupFlags &= ~FLAG_ANIMATION_DONE;
4155
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004156 if (mAnimationListener != null) {
4157 mAnimationListener.onAnimationStart(controller.getAnimation());
4158 }
4159 }
4160
Selim Cinek19cadc22014-04-16 17:27:19 +02004161 int clipSaveCount = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004162 final boolean clipToPadding = (flags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK;
4163 if (clipToPadding) {
John Reck41f864e2016-05-12 15:07:49 -07004164 clipSaveCount = canvas.save(Canvas.CLIP_SAVE_FLAG);
Romain Guy8f2d94f2009-03-25 18:04:42 -07004165 canvas.clipRect(mScrollX + mPaddingLeft, mScrollY + mPaddingTop,
4166 mScrollX + mRight - mLeft - mPaddingRight,
4167 mScrollY + mBottom - mTop - mPaddingBottom);
Selim Cinek19cadc22014-04-16 17:27:19 +02004168 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004169
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004170 // We will draw our child's animation, let's reset the flag
Dianne Hackborn4702a852012-08-17 15:18:29 -07004171 mPrivateFlags &= ~PFLAG_DRAW_ANIMATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004172 mGroupFlags &= ~FLAG_INVALIDATE_REQUIRED;
4173
4174 boolean more = false;
4175 final long drawingTime = getDrawingTime();
4176
Chris Craik8afd0f22014-08-21 17:41:57 -07004177 if (usingRenderNodeProperties) canvas.insertReorderBarrier();
Chet Haasec633d2f2015-04-07 10:29:39 -07004178 final int transientCount = mTransientIndices == null ? 0 : mTransientIndices.size();
4179 int transientIndex = transientCount != 0 ? 0 : -1;
Chris Craikab008f02014-05-23 17:55:03 -07004180 // Only use the preordered list if not HW accelerated, since the HW pipeline will do the
4181 // draw reordering internally
Chris Craika753f4c2014-07-24 12:39:17 -07004182 final ArrayList<View> preorderedList = usingRenderNodeProperties
Chris Craikab008f02014-05-23 17:55:03 -07004183 ? null : buildOrderedChildList();
4184 final boolean customOrder = preorderedList == null
4185 && isChildrenDrawingOrderEnabled();
4186 for (int i = 0; i < childrenCount; i++) {
Chet Haasec633d2f2015-04-07 10:29:39 -07004187 while (transientIndex >= 0 && mTransientIndices.get(transientIndex) == i) {
4188 final View transientChild = mTransientViews.get(transientIndex);
4189 if ((transientChild.mViewFlags & VISIBILITY_MASK) == VISIBLE ||
4190 transientChild.getAnimation() != null) {
4191 more |= drawChild(canvas, transientChild, drawingTime);
4192 }
4193 transientIndex++;
4194 if (transientIndex >= transientCount) {
4195 transientIndex = -1;
4196 }
4197 }
Alan Viverettea7b85e62016-01-22 10:14:02 -05004198
4199 final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
4200 final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);
Chris Craikab008f02014-05-23 17:55:03 -07004201 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
4202 more |= drawChild(canvas, child, drawingTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004203 }
4204 }
Chet Haasec633d2f2015-04-07 10:29:39 -07004205 while (transientIndex >= 0) {
4206 // there may be additional transient views after the normal views
4207 final View transientChild = mTransientViews.get(transientIndex);
4208 if ((transientChild.mViewFlags & VISIBILITY_MASK) == VISIBLE ||
4209 transientChild.getAnimation() != null) {
4210 more |= drawChild(canvas, transientChild, drawingTime);
4211 }
4212 transientIndex++;
4213 if (transientIndex >= transientCount) {
4214 break;
4215 }
4216 }
Chris Craikab008f02014-05-23 17:55:03 -07004217 if (preorderedList != null) preorderedList.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004218
4219 // Draw any disappearing views that have animations
4220 if (mDisappearingChildren != null) {
4221 final ArrayList<View> disappearingChildren = mDisappearingChildren;
4222 final int disappearingCount = disappearingChildren.size() - 1;
4223 // Go backwards -- we may delete as animations finish
4224 for (int i = disappearingCount; i >= 0; i--) {
4225 final View child = disappearingChildren.get(i);
4226 more |= drawChild(canvas, child, drawingTime);
4227 }
4228 }
Chris Craik8afd0f22014-08-21 17:41:57 -07004229 if (usingRenderNodeProperties) canvas.insertInorderBarrier();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004230
Philip Milne10ca24a2012-04-23 15:38:27 -07004231 if (debugDraw()) {
4232 onDebugDraw(canvas);
4233 }
4234
Chris Craike4cf1522014-08-04 17:55:22 -07004235 if (clipToPadding) {
Selim Cinek19cadc22014-04-16 17:27:19 +02004236 canvas.restoreToCount(clipSaveCount);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004237 }
4238
4239 // mGroupFlags might have been updated by drawChild()
4240 flags = mGroupFlags;
4241
4242 if ((flags & FLAG_INVALIDATE_REQUIRED) == FLAG_INVALIDATE_REQUIRED) {
Romain Guy849d0a32011-02-01 17:20:48 -08004243 invalidate(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004244 }
4245
4246 if ((flags & FLAG_ANIMATION_DONE) == 0 && (flags & FLAG_NOTIFY_ANIMATION_LISTENER) == 0 &&
4247 mLayoutAnimationController.isDone() && !more) {
4248 // We want to erase the drawing cache and notify the listener after the
4249 // next frame is drawn because one extra invalidate() is caused by
4250 // drawChild() after the animation is over
4251 mGroupFlags |= FLAG_NOTIFY_ANIMATION_LISTENER;
4252 final Runnable end = new Runnable() {
Alan Viverettebe463f22016-01-21 10:50:10 -05004253 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004254 public void run() {
4255 notifyAnimationListener();
4256 }
4257 };
4258 post(end);
4259 }
4260 }
Romain Guy8506ab42009-06-11 17:35:47 -07004261
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004262 /**
Chet Haaseedf6f4b2013-03-26 07:55:30 -07004263 * Returns the ViewGroupOverlay for this view group, creating it if it does
4264 * not yet exist. In addition to {@link ViewOverlay}'s support for drawables,
4265 * {@link ViewGroupOverlay} allows views to be added to the overlay. These
4266 * views, like overlay drawables, are visual-only; they do not receive input
4267 * events and should not be used as anything other than a temporary
4268 * representation of a view in a parent container, such as might be used
4269 * by an animation effect.
4270 *
Chet Haase95399492013-04-08 14:30:31 -07004271 * <p>Note: Overlays do not currently work correctly with {@link
4272 * SurfaceView} or {@link TextureView}; contents in overlays for these
4273 * types of views may not display correctly.</p>
4274 *
Chet Haaseedf6f4b2013-03-26 07:55:30 -07004275 * @return The ViewGroupOverlay object for this view.
4276 * @see ViewGroupOverlay
4277 */
4278 @Override
4279 public ViewGroupOverlay getOverlay() {
4280 if (mOverlay == null) {
4281 mOverlay = new ViewGroupOverlay(mContext, this);
4282 }
4283 return (ViewGroupOverlay) mOverlay;
4284 }
4285
4286 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004287 * Returns the index of the child to draw for this iteration. Override this
4288 * if you want to change the drawing order of children. By default, it
4289 * returns i.
4290 * <p>
Romain Guy293451e2009-11-04 13:59:48 -08004291 * NOTE: In order for this method to be called, you must enable child ordering
4292 * first by calling {@link #setChildrenDrawingOrderEnabled(boolean)}.
Romain Guy8506ab42009-06-11 17:35:47 -07004293 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004294 * @param i The current iteration.
4295 * @return The index of the child to draw this iteration.
Chet Haase5c13d892010-10-08 08:37:55 -07004296 *
Romain Guy293451e2009-11-04 13:59:48 -08004297 * @see #setChildrenDrawingOrderEnabled(boolean)
4298 * @see #isChildrenDrawingOrderEnabled()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004299 */
4300 protected int getChildDrawingOrder(int childCount, int i) {
4301 return i;
4302 }
Romain Guy8506ab42009-06-11 17:35:47 -07004303
Andrey Kulikov7c4e6932019-02-05 19:13:19 +00004304 /**
4305 * The public version of getChildDrawingOrder().
4306 *
4307 * Returns the index of the child to draw for this iteration.
4308 *
4309 * @param i The current iteration.
4310 * @return The index of the child to draw this iteration.
4311 *
4312 * @see #getChildDrawingOrder(int, int)}
4313 */
4314 public final int getChildDrawingOrder(int i) {
4315 return getChildDrawingOrder(getChildCount(), i);
4316 }
4317
Chris Craikab008f02014-05-23 17:55:03 -07004318 private boolean hasChildWithZ() {
4319 for (int i = 0; i < mChildrenCount; i++) {
4320 if (mChildren[i].getZ() != 0) return true;
4321 }
4322 return false;
4323 }
4324
4325 /**
4326 * Populates (and returns) mPreSortedChildren with a pre-ordered list of the View's children,
Chris Craik57c79c82014-09-30 12:54:31 -07004327 * sorted first by Z, then by child drawing order (if applicable). This list must be cleared
4328 * after use to avoid leaking child Views.
Chris Craikab008f02014-05-23 17:55:03 -07004329 *
4330 * Uses a stable, insertion sort which is commonly O(n) for ViewGroups with very few elevated
4331 * children.
4332 */
George Mount81206522014-09-26 21:53:39 -07004333 ArrayList<View> buildOrderedChildList() {
Alan Viverettea7b85e62016-01-22 10:14:02 -05004334 final int childrenCount = mChildrenCount;
4335 if (childrenCount <= 1 || !hasChildWithZ()) return null;
Chris Craikab008f02014-05-23 17:55:03 -07004336
4337 if (mPreSortedChildren == null) {
Alan Viverettea7b85e62016-01-22 10:14:02 -05004338 mPreSortedChildren = new ArrayList<>(childrenCount);
Chris Craikab008f02014-05-23 17:55:03 -07004339 } else {
Chris Craikfc563772016-05-04 13:34:30 -07004340 // callers should clear, so clear shouldn't be necessary, but for safety...
4341 mPreSortedChildren.clear();
Alan Viverettea7b85e62016-01-22 10:14:02 -05004342 mPreSortedChildren.ensureCapacity(childrenCount);
Chris Craikab008f02014-05-23 17:55:03 -07004343 }
4344
Alan Viverettea7b85e62016-01-22 10:14:02 -05004345 final boolean customOrder = isChildrenDrawingOrderEnabled();
4346 for (int i = 0; i < childrenCount; i++) {
Chris Craikab008f02014-05-23 17:55:03 -07004347 // add next child (in child order) to end of list
Alan Viverettea7b85e62016-01-22 10:14:02 -05004348 final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
4349 final View nextChild = mChildren[childIndex];
4350 final float currentZ = nextChild.getZ();
Chris Craikab008f02014-05-23 17:55:03 -07004351
4352 // insert ahead of any Views with greater Z
4353 int insertIndex = i;
4354 while (insertIndex > 0 && mPreSortedChildren.get(insertIndex - 1).getZ() > currentZ) {
4355 insertIndex--;
4356 }
4357 mPreSortedChildren.add(insertIndex, nextChild);
4358 }
4359 return mPreSortedChildren;
4360 }
4361
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004362 private void notifyAnimationListener() {
4363 mGroupFlags &= ~FLAG_NOTIFY_ANIMATION_LISTENER;
4364 mGroupFlags |= FLAG_ANIMATION_DONE;
4365
4366 if (mAnimationListener != null) {
4367 final Runnable end = new Runnable() {
Alan Viverettebe463f22016-01-21 10:50:10 -05004368 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004369 public void run() {
4370 mAnimationListener.onAnimationEnd(mLayoutAnimationController.getAnimation());
4371 }
4372 };
4373 post(end);
4374 }
4375
Romain Guy849d0a32011-02-01 17:20:48 -08004376 invalidate(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004377 }
4378
4379 /**
Chet Haasedaf98e92011-01-10 14:10:36 -08004380 * This method is used to cause children of this ViewGroup to restore or recreate their
4381 * display lists. It is called by getDisplayList() when the parent ViewGroup does not need
4382 * to recreate its own display list, which would happen if it went through the normal
4383 * draw/dispatchDraw mechanisms.
4384 *
4385 * @hide
4386 */
4387 @Override
Mathew Inwooda570dee2018-08-17 14:56:00 +01004388 @UnsupportedAppUsage
Chet Haasedaf98e92011-01-10 14:10:36 -08004389 protected void dispatchGetDisplayList() {
4390 final int count = mChildrenCount;
4391 final View[] children = mChildren;
4392 for (int i = 0; i < count; i++) {
4393 final View child = children[i];
John Reckc2330f52015-04-28 13:18:52 -07004394 if (((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null)) {
Chet Haase6c0665f2014-08-01 13:32:27 -07004395 recreateChildDisplayList(child);
Romain Guy2f57ba52011-02-03 18:03:29 -08004396 }
Chet Haasedaf98e92011-01-10 14:10:36 -08004397 }
Selim Cinekd6a51b12018-03-15 17:10:20 -07004398 final int transientCount = mTransientViews == null ? 0 : mTransientIndices.size();
4399 for (int i = 0; i < transientCount; ++i) {
4400 View child = mTransientViews.get(i);
4401 if (((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null)) {
4402 recreateChildDisplayList(child);
4403 }
4404 }
Chet Haase91cedf12013-03-11 07:56:30 -07004405 if (mOverlay != null) {
Chet Haaseedf6f4b2013-03-26 07:55:30 -07004406 View overlayView = mOverlay.getOverlayView();
Chet Haase6c0665f2014-08-01 13:32:27 -07004407 recreateChildDisplayList(overlayView);
Chet Haase91cedf12013-03-11 07:56:30 -07004408 }
Chet Haase6c0665f2014-08-01 13:32:27 -07004409 if (mDisappearingChildren != null) {
4410 final ArrayList<View> disappearingChildren = mDisappearingChildren;
4411 final int disappearingCount = disappearingChildren.size();
4412 for (int i = 0; i < disappearingCount; ++i) {
4413 final View child = disappearingChildren.get(i);
4414 recreateChildDisplayList(child);
4415 }
4416 }
4417 }
4418
4419 private void recreateChildDisplayList(View child) {
Chris Craik31a2d062015-05-01 14:22:47 -07004420 child.mRecreateDisplayList = (child.mPrivateFlags & PFLAG_INVALIDATED) != 0;
Chet Haase6c0665f2014-08-01 13:32:27 -07004421 child.mPrivateFlags &= ~PFLAG_INVALIDATED;
Chris Craik31a2d062015-05-01 14:22:47 -07004422 child.updateDisplayListIfDirty();
Chet Haase6c0665f2014-08-01 13:32:27 -07004423 child.mRecreateDisplayList = false;
Chet Haasedaf98e92011-01-10 14:10:36 -08004424 }
4425
4426 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004427 * Draw one child of this View Group. This method is responsible for getting
4428 * the canvas in the right state. This includes clipping, translating so
4429 * that the child's scrolled origin is at 0, 0, and applying any animation
4430 * transformations.
4431 *
4432 * @param canvas The canvas on which to draw the child
4433 * @param child Who to draw
Chet Haasebcca79a2012-02-14 08:45:14 -08004434 * @param drawingTime The time at which draw is occurring
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004435 * @return True if an invalidate() was issued
4436 */
4437 protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
Chet Haase64a48c12012-02-13 16:33:29 -08004438 return child.draw(canvas, this, drawingTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004439 }
4440
Alan Viverette922e1c62015-05-05 17:18:27 -07004441 @Override
4442 void getScrollIndicatorBounds(@NonNull Rect out) {
4443 super.getScrollIndicatorBounds(out);
4444
4445 // If we have padding and we're supposed to clip children to that
4446 // padding, offset the scroll indicators to match our clip bounds.
4447 final boolean clipToPadding = (mGroupFlags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK;
4448 if (clipToPadding) {
4449 out.left += mPaddingLeft;
4450 out.right -= mPaddingRight;
4451 out.top += mPaddingTop;
4452 out.bottom -= mPaddingBottom;
4453 }
4454 }
4455
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004456 /**
Chris Craikd863a102013-12-19 13:31:15 -08004457 * Returns whether this group's children are clipped to their bounds before drawing.
Chet Haase430742f2013-04-12 11:18:36 -07004458 * The default value is true.
4459 * @see #setClipChildren(boolean)
4460 *
4461 * @return True if the group's children will be clipped to their bounds,
4462 * false otherwise.
4463 */
Chris Craik5c75c522014-09-05 14:08:08 -07004464 @ViewDebug.ExportedProperty(category = "drawing")
Ashley Rose55f9f922019-01-28 19:29:36 -05004465 @InspectableProperty
Chet Haase430742f2013-04-12 11:18:36 -07004466 public boolean getClipChildren() {
4467 return ((mGroupFlags & FLAG_CLIP_CHILDREN) != 0);
4468 }
4469
4470 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004471 * By default, children are clipped to their bounds before drawing. This
4472 * allows view groups to override this behavior for animations, etc.
4473 *
4474 * @param clipChildren true to clip children to their bounds,
4475 * false otherwise
4476 * @attr ref android.R.styleable#ViewGroup_clipChildren
4477 */
4478 public void setClipChildren(boolean clipChildren) {
Chet Haasea1cff502012-02-21 13:43:44 -08004479 boolean previousValue = (mGroupFlags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN;
4480 if (clipChildren != previousValue) {
4481 setBooleanFlag(FLAG_CLIP_CHILDREN, clipChildren);
Chet Haase1271e2c2012-04-20 09:54:27 -07004482 for (int i = 0; i < mChildrenCount; ++i) {
4483 View child = getChildAt(i);
Chris Craik64a12e12014-03-28 18:12:12 -07004484 if (child.mRenderNode != null) {
4485 child.mRenderNode.setClipToBounds(clipChildren);
Chet Haasea1cff502012-02-21 13:43:44 -08004486 }
4487 }
John Reckaae9f3b2014-07-28 09:30:36 -07004488 invalidate(true);
Chet Haasea1cff502012-02-21 13:43:44 -08004489 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004490 }
4491
4492 /**
Doris Liub134b5e2015-05-28 17:26:46 -07004493 * Sets whether this ViewGroup will clip its children to its padding and resize (but not
4494 * clip) any EdgeEffect to the padded region, if padding is present.
Chris Craikb1652962014-11-14 17:05:06 -08004495 * <p>
4496 * By default, children are clipped to the padding of their parent
Doris Liub134b5e2015-05-28 17:26:46 -07004497 * ViewGroup. This clipping behavior is only enabled if padding is non-zero.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004498 *
Doris Liub134b5e2015-05-28 17:26:46 -07004499 * @param clipToPadding true to clip children to the padding of the group, and resize (but
4500 * not clip) any EdgeEffect to the padded region. False otherwise.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004501 * @attr ref android.R.styleable#ViewGroup_clipToPadding
4502 */
4503 public void setClipToPadding(boolean clipToPadding) {
John Reck9fa3a242014-06-27 15:57:19 -07004504 if (hasBooleanFlag(FLAG_CLIP_TO_PADDING) != clipToPadding) {
4505 setBooleanFlag(FLAG_CLIP_TO_PADDING, clipToPadding);
John Reckaae9f3b2014-07-28 09:30:36 -07004506 invalidate(true);
John Reck9fa3a242014-06-27 15:57:19 -07004507 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004508 }
4509
4510 /**
Doris Liub134b5e2015-05-28 17:26:46 -07004511 * Returns whether this ViewGroup will clip its children to its padding, and resize (but
4512 * not clip) any EdgeEffect to the padded region, if padding is present.
Chris Craikb1652962014-11-14 17:05:06 -08004513 * <p>
4514 * By default, children are clipped to the padding of their parent
4515 * Viewgroup. This clipping behavior is only enabled if padding is non-zero.
Adam Powell1c35b082014-07-11 15:37:15 -07004516 *
Doris Liub134b5e2015-05-28 17:26:46 -07004517 * @return true if this ViewGroup clips children to its padding and resizes (but doesn't
4518 * clip) any EdgeEffect to the padded region, false otherwise.
Adam Powell1c35b082014-07-11 15:37:15 -07004519 *
4520 * @attr ref android.R.styleable#ViewGroup_clipToPadding
4521 */
Chris Craik5c75c522014-09-05 14:08:08 -07004522 @ViewDebug.ExportedProperty(category = "drawing")
Ashley Rose55f9f922019-01-28 19:29:36 -05004523 @InspectableProperty
Adam Powell1c35b082014-07-11 15:37:15 -07004524 public boolean getClipToPadding() {
4525 return hasBooleanFlag(FLAG_CLIP_TO_PADDING);
4526 }
4527
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004528 @Override
4529 public void dispatchSetSelected(boolean selected) {
4530 final View[] children = mChildren;
4531 final int count = mChildrenCount;
4532 for (int i = 0; i < count; i++) {
4533 children[i].setSelected(selected);
4534 }
4535 }
Romain Guy8506ab42009-06-11 17:35:47 -07004536
Dianne Hackbornd0fa3712010-09-14 18:57:14 -07004537 @Override
4538 public void dispatchSetActivated(boolean activated) {
4539 final View[] children = mChildren;
4540 final int count = mChildrenCount;
4541 for (int i = 0; i < count; i++) {
Dianne Hackbornd0fa3712010-09-14 18:57:14 -07004542 children[i].setActivated(activated);
4543 }
4544 }
4545
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004546 @Override
4547 protected void dispatchSetPressed(boolean pressed) {
4548 final View[] children = mChildren;
4549 final int count = mChildrenCount;
4550 for (int i = 0; i < count; i++) {
Adam Powell035a1fc2012-02-27 15:23:50 -08004551 final View child = children[i];
4552 // Children that are clickable on their own should not
4553 // show a pressed state when their parent view does.
4554 // Clearing a pressed state always propagates.
4555 if (!pressed || (!child.isClickable() && !child.isLongClickable())) {
4556 child.setPressed(pressed);
4557 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004558 }
4559 }
4560
Alan Viveretteb942b6f2014-12-08 10:37:39 -08004561 /**
4562 * Dispatches drawable hotspot changes to child views that meet at least
4563 * one of the following criteria:
4564 * <ul>
4565 * <li>Returns {@code false} from both {@link View#isClickable()} and
4566 * {@link View#isLongClickable()}</li>
4567 * <li>Requests duplication of parent state via
4568 * {@link View#setDuplicateParentStateEnabled(boolean)}</li>
4569 * </ul>
4570 *
4571 * @param x hotspot x coordinate
4572 * @param y hotspot y coordinate
4573 * @see #drawableHotspotChanged(float, float)
4574 */
4575 @Override
4576 public void dispatchDrawableHotspotChanged(float x, float y) {
4577 final int count = mChildrenCount;
4578 if (count == 0) {
4579 return;
4580 }
4581
4582 final View[] children = mChildren;
4583 for (int i = 0; i < count; i++) {
4584 final View child = children[i];
4585 // Children that are clickable on their own should not
4586 // receive hotspots when their parent view does.
4587 final boolean nonActionable = !child.isClickable() && !child.isLongClickable();
4588 final boolean duplicatesState = (child.mViewFlags & DUPLICATE_PARENT_STATE) != 0;
4589 if (nonActionable || duplicatesState) {
4590 final float[] point = getTempPoint();
4591 point[0] = x;
4592 point[1] = y;
4593 transformPointToViewLocal(point, child);
4594 child.drawableHotspotChanged(point[0], point[1]);
4595 }
4596 }
4597 }
4598
Adam Powell14874662013-07-18 19:42:41 -07004599 @Override
4600 void dispatchCancelPendingInputEvents() {
4601 super.dispatchCancelPendingInputEvents();
4602
4603 final View[] children = mChildren;
4604 final int count = mChildrenCount;
4605 for (int i = 0; i < count; i++) {
4606 children[i].dispatchCancelPendingInputEvents();
4607 }
4608 }
4609
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004610 /**
4611 * When this property is set to true, this ViewGroup supports static transformations on
4612 * children; this causes
4613 * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} to be
4614 * invoked when a child is drawn.
4615 *
4616 * Any subclass overriding
4617 * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} should
4618 * set this property to true.
4619 *
4620 * @param enabled True to enable static transformations on children, false otherwise.
4621 *
Chet Haase599913d2012-07-23 16:22:05 -07004622 * @see #getChildStaticTransformation(View, android.view.animation.Transformation)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004623 */
4624 protected void setStaticTransformationsEnabled(boolean enabled) {
4625 setBooleanFlag(FLAG_SUPPORT_STATIC_TRANSFORMATIONS, enabled);
4626 }
4627
4628 /**
Chet Haase2d46fcc2011-12-19 18:01:05 -08004629 * Sets <code>t</code> to be the static transformation of the child, if set, returning a
4630 * boolean to indicate whether a static transform was set. The default implementation
4631 * simply returns <code>false</code>; subclasses may override this method for different
Chet Haase599913d2012-07-23 16:22:05 -07004632 * behavior. {@link #setStaticTransformationsEnabled(boolean)} must be set to true
4633 * for this method to be called.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004634 *
Chet Haase2d46fcc2011-12-19 18:01:05 -08004635 * @param child The child view whose static transform is being requested
4636 * @param t The Transformation which will hold the result
4637 * @return true if the transformation was set, false otherwise
Romain Guy8506ab42009-06-11 17:35:47 -07004638 * @see #setStaticTransformationsEnabled(boolean)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004639 */
4640 protected boolean getChildStaticTransformation(View child, Transformation t) {
4641 return false;
4642 }
4643
Romain Guyf6991302013-06-05 17:19:01 -07004644 Transformation getChildTransformation() {
4645 if (mChildTransformation == null) {
4646 mChildTransformation = new Transformation();
4647 }
4648 return mChildTransformation;
4649 }
4650
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004651 /**
4652 * {@hide}
4653 */
4654 @Override
Alan Viverette8e1a7292017-02-27 10:57:58 -05004655 protected <T extends View> T findViewTraversal(@IdRes int id) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004656 if (id == mID) {
Alan Viverette8e1a7292017-02-27 10:57:58 -05004657 return (T) this;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004658 }
4659
4660 final View[] where = mChildren;
4661 final int len = mChildrenCount;
4662
4663 for (int i = 0; i < len; i++) {
4664 View v = where[i];
4665
Dianne Hackborn4702a852012-08-17 15:18:29 -07004666 if ((v.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004667 v = v.findViewById(id);
4668
4669 if (v != null) {
Alan Viverette8e1a7292017-02-27 10:57:58 -05004670 return (T) v;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004671 }
4672 }
4673 }
4674
4675 return null;
4676 }
4677
4678 /**
4679 * {@hide}
4680 */
4681 @Override
Alan Viverette8e1a7292017-02-27 10:57:58 -05004682 protected <T extends View> T findViewWithTagTraversal(Object tag) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004683 if (tag != null && tag.equals(mTag)) {
Alan Viverette8e1a7292017-02-27 10:57:58 -05004684 return (T) this;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004685 }
4686
4687 final View[] where = mChildren;
4688 final int len = mChildrenCount;
4689
4690 for (int i = 0; i < len; i++) {
4691 View v = where[i];
4692
Dianne Hackborn4702a852012-08-17 15:18:29 -07004693 if ((v.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004694 v = v.findViewWithTag(tag);
4695
4696 if (v != null) {
Alan Viverette8e1a7292017-02-27 10:57:58 -05004697 return (T) v;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004698 }
4699 }
4700 }
4701
4702 return null;
4703 }
4704
4705 /**
Jeff Brown4e6319b2010-12-13 10:36:51 -08004706 * {@hide}
4707 */
4708 @Override
Alan Viverette8e1a7292017-02-27 10:57:58 -05004709 protected <T extends View> T findViewByPredicateTraversal(Predicate<View> predicate,
4710 View childToSkip) {
Paul Duffinca4964c2017-02-07 15:04:10 +00004711 if (predicate.test(this)) {
Alan Viverette8e1a7292017-02-27 10:57:58 -05004712 return (T) this;
Jeff Brown4e6319b2010-12-13 10:36:51 -08004713 }
4714
4715 final View[] where = mChildren;
4716 final int len = mChildrenCount;
4717
4718 for (int i = 0; i < len; i++) {
4719 View v = where[i];
4720
Dianne Hackborn4702a852012-08-17 15:18:29 -07004721 if (v != childToSkip && (v.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
Jeff Brown4e6319b2010-12-13 10:36:51 -08004722 v = v.findViewByPredicate(predicate);
4723
4724 if (v != null) {
Alan Viverette8e1a7292017-02-27 10:57:58 -05004725 return (T) v;
Jeff Brown4e6319b2010-12-13 10:36:51 -08004726 }
4727 }
4728 }
4729
4730 return null;
4731 }
4732
4733 /**
Chet Haasec633d2f2015-04-07 10:29:39 -07004734 * This method adds a view to this container at the specified index purely for the
4735 * purposes of allowing that view to draw even though it is not a normal child of
4736 * the container. That is, the view does not participate in layout, focus, accessibility,
4737 * input, or other normal view operations; it is purely an item to be drawn during the normal
4738 * rendering operation of this container. The index that it is added at is the order
4739 * in which it will be drawn, with respect to the other views in the container.
4740 * For example, a transient view added at index 0 will be drawn before all other views
4741 * in the container because it will be drawn first (including before any real view
4742 * at index 0). There can be more than one transient view at any particular index;
4743 * these views will be drawn in the order in which they were added to the list of
4744 * transient views. The index of transient views can also be greater than the number
4745 * of normal views in the container; that just means that they will be drawn after all
4746 * other views are drawn.
4747 *
4748 * <p>Note that since transient views do not participate in layout, they must be sized
4749 * manually or, more typically, they should just use the size that they had before they
4750 * were removed from their container.</p>
4751 *
4752 * <p>Transient views are useful for handling animations of views that have been removed
4753 * from the container, but which should be animated out after the removal. Adding these
4754 * views as transient views allows them to participate in drawing without side-effecting
4755 * the layout of the container.</p>
4756 *
4757 * <p>Transient views must always be explicitly {@link #removeTransientView(View) removed}
4758 * from the container when they are no longer needed. For example, a transient view
4759 * which is added in order to fade it out in its old location should be removed
4760 * once the animation is complete.</p>
4761 *
Riddle Hsu95459d32018-06-08 15:54:08 +08004762 * @param view The view to be added. The view must not have a parent.
Chet Haasec633d2f2015-04-07 10:29:39 -07004763 * @param index The index at which this view should be drawn, must be >= 0.
4764 * This value is relative to the {@link #getChildAt(int) index} values in the normal
4765 * child list of this container, where any transient view at a particular index will
4766 * be drawn before any normal child at that same index.
Chris Craik66b41392015-04-17 10:08:10 -07004767 *
4768 * @hide
Chet Haasec633d2f2015-04-07 10:29:39 -07004769 */
Mathew Inwooda570dee2018-08-17 14:56:00 +01004770 @UnsupportedAppUsage
Chet Haasec633d2f2015-04-07 10:29:39 -07004771 public void addTransientView(View view, int index) {
Riddle Hsu95459d32018-06-08 15:54:08 +08004772 if (index < 0 || view == null) {
Chet Haasec633d2f2015-04-07 10:29:39 -07004773 return;
4774 }
Riddle Hsu95459d32018-06-08 15:54:08 +08004775 if (view.mParent != null) {
4776 throw new IllegalStateException("The specified view already has a parent "
4777 + view.mParent);
4778 }
4779
Chet Haasec633d2f2015-04-07 10:29:39 -07004780 if (mTransientIndices == null) {
4781 mTransientIndices = new ArrayList<Integer>();
4782 mTransientViews = new ArrayList<View>();
4783 }
4784 final int oldSize = mTransientIndices.size();
4785 if (oldSize > 0) {
4786 int insertionIndex;
4787 for (insertionIndex = 0; insertionIndex < oldSize; ++insertionIndex) {
4788 if (index < mTransientIndices.get(insertionIndex)) {
4789 break;
4790 }
4791 }
4792 mTransientIndices.add(insertionIndex, index);
4793 mTransientViews.add(insertionIndex, view);
4794 } else {
4795 mTransientIndices.add(index);
4796 mTransientViews.add(view);
4797 }
4798 view.mParent = this;
Riddle Hsu95459d32018-06-08 15:54:08 +08004799 if (mAttachInfo != null) {
4800 view.dispatchAttachedToWindow(mAttachInfo, (mViewFlags & VISIBILITY_MASK));
4801 }
Chet Haasec633d2f2015-04-07 10:29:39 -07004802 invalidate(true);
4803 }
4804
4805 /**
4806 * Removes a view from the list of transient views in this container. If there is no
4807 * such transient view, this method does nothing.
4808 *
4809 * @param view The transient view to be removed
Chris Craik66b41392015-04-17 10:08:10 -07004810 *
4811 * @hide
Chet Haasec633d2f2015-04-07 10:29:39 -07004812 */
Mathew Inwooda570dee2018-08-17 14:56:00 +01004813 @UnsupportedAppUsage
Chet Haasec633d2f2015-04-07 10:29:39 -07004814 public void removeTransientView(View view) {
4815 if (mTransientViews == null) {
4816 return;
4817 }
4818 final int size = mTransientViews.size();
4819 for (int i = 0; i < size; ++i) {
4820 if (view == mTransientViews.get(i)) {
4821 mTransientViews.remove(i);
4822 mTransientIndices.remove(i);
4823 view.mParent = null;
Riddle Hsu95459d32018-06-08 15:54:08 +08004824 if (view.mAttachInfo != null) {
4825 view.dispatchDetachedFromWindow();
4826 }
Chet Haasec633d2f2015-04-07 10:29:39 -07004827 invalidate(true);
4828 return;
4829 }
4830 }
4831 }
4832
4833 /**
4834 * Returns the number of transient views in this container. Specific transient
4835 * views and the index at which they were added can be retrieved via
4836 * {@link #getTransientView(int)} and {@link #getTransientViewIndex(int)}.
4837 *
4838 * @see #addTransientView(View, int)
4839 * @return The number of transient views in this container
Chris Craik66b41392015-04-17 10:08:10 -07004840 *
4841 * @hide
Chet Haasec633d2f2015-04-07 10:29:39 -07004842 */
Mathew Inwooda570dee2018-08-17 14:56:00 +01004843 @UnsupportedAppUsage
Chet Haasec633d2f2015-04-07 10:29:39 -07004844 public int getTransientViewCount() {
4845 return mTransientIndices == null ? 0 : mTransientIndices.size();
4846 }
4847
4848 /**
4849 * Given a valid position within the list of transient views, returns the index of
4850 * the transient view at that position.
4851 *
4852 * @param position The position of the index being queried. Must be at least 0
4853 * and less than the value returned by {@link #getTransientViewCount()}.
4854 * @return The index of the transient view stored in the given position if the
4855 * position is valid, otherwise -1
Chris Craik66b41392015-04-17 10:08:10 -07004856 *
4857 * @hide
Chet Haasec633d2f2015-04-07 10:29:39 -07004858 */
4859 public int getTransientViewIndex(int position) {
4860 if (position < 0 || mTransientIndices == null || position >= mTransientIndices.size()) {
4861 return -1;
4862 }
4863 return mTransientIndices.get(position);
4864 }
4865
4866 /**
4867 * Given a valid position within the list of transient views, returns the
4868 * transient view at that position.
4869 *
4870 * @param position The position of the view being queried. Must be at least 0
4871 * and less than the value returned by {@link #getTransientViewCount()}.
4872 * @return The transient view stored in the given position if the
4873 * position is valid, otherwise null
Chris Craik66b41392015-04-17 10:08:10 -07004874 *
4875 * @hide
Chet Haasec633d2f2015-04-07 10:29:39 -07004876 */
Mathew Inwooda570dee2018-08-17 14:56:00 +01004877 @UnsupportedAppUsage
Chet Haasec633d2f2015-04-07 10:29:39 -07004878 public View getTransientView(int position) {
4879 if (mTransientViews == null || position >= mTransientViews.size()) {
4880 return null;
4881 }
4882 return mTransientViews.get(position);
4883 }
4884
4885 /**
Romain Guy393a52c2012-05-22 20:21:08 -07004886 * <p>Adds a child view. If no layout parameters are already set on the child, the
4887 * default parameters for this ViewGroup are set on the child.</p>
Filip Gruszczynskia33bdf32015-11-19 18:22:16 -08004888 *
Romain Guy393a52c2012-05-22 20:21:08 -07004889 * <p><strong>Note:</strong> do not invoke this method from
4890 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
4891 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004892 *
4893 * @param child the child view to add
4894 *
4895 * @see #generateDefaultLayoutParams()
4896 */
4897 public void addView(View child) {
4898 addView(child, -1);
4899 }
4900
4901 /**
4902 * Adds a child view. If no layout parameters are already set on the child, the
4903 * default parameters for this ViewGroup are set on the child.
Filip Gruszczynskia33bdf32015-11-19 18:22:16 -08004904 *
Romain Guy393a52c2012-05-22 20:21:08 -07004905 * <p><strong>Note:</strong> do not invoke this method from
4906 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
4907 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004908 *
4909 * @param child the child view to add
4910 * @param index the position at which to add the child
4911 *
4912 * @see #generateDefaultLayoutParams()
4913 */
4914 public void addView(View child, int index) {
Adam Powell45a9da52014-10-09 09:44:18 -07004915 if (child == null) {
4916 throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup");
4917 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004918 LayoutParams params = child.getLayoutParams();
4919 if (params == null) {
4920 params = generateDefaultLayoutParams();
4921 if (params == null) {
4922 throw new IllegalArgumentException("generateDefaultLayoutParams() cannot return null");
4923 }
4924 }
4925 addView(child, index, params);
4926 }
4927
4928 /**
4929 * Adds a child view with this ViewGroup's default layout parameters and the
4930 * specified width and height.
4931 *
Romain Guy393a52c2012-05-22 20:21:08 -07004932 * <p><strong>Note:</strong> do not invoke this method from
4933 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
4934 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
4935 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004936 * @param child the child view to add
4937 */
4938 public void addView(View child, int width, int height) {
4939 final LayoutParams params = generateDefaultLayoutParams();
4940 params.width = width;
4941 params.height = height;
4942 addView(child, -1, params);
4943 }
4944
4945 /**
4946 * Adds a child view with the specified layout parameters.
4947 *
Romain Guy393a52c2012-05-22 20:21:08 -07004948 * <p><strong>Note:</strong> do not invoke this method from
4949 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
4950 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
4951 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004952 * @param child the child view to add
4953 * @param params the layout parameters to set on the child
4954 */
Alan Viverettebe463f22016-01-21 10:50:10 -05004955 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004956 public void addView(View child, LayoutParams params) {
4957 addView(child, -1, params);
4958 }
4959
4960 /**
4961 * Adds a child view with the specified layout parameters.
4962 *
Romain Guy393a52c2012-05-22 20:21:08 -07004963 * <p><strong>Note:</strong> do not invoke this method from
4964 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
4965 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
4966 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004967 * @param child the child view to add
Alan Viverette77bb6f12015-02-11 17:24:33 -08004968 * @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 -08004969 * @param params the layout parameters to set on the child
4970 */
4971 public void addView(View child, int index, LayoutParams params) {
4972 if (DBG) {
4973 System.out.println(this + " addView");
4974 }
4975
Adam Powell45a9da52014-10-09 09:44:18 -07004976 if (child == null) {
4977 throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup");
4978 }
4979
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004980 // addViewInner() will call child.requestLayout() when setting the new LayoutParams
4981 // therefore, we call requestLayout() on ourselves before, so that the child's request
4982 // will be blocked at our level
4983 requestLayout();
Romain Guy849d0a32011-02-01 17:20:48 -08004984 invalidate(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004985 addViewInner(child, index, params, false);
4986 }
4987
Alan Viverettebe463f22016-01-21 10:50:10 -05004988 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004989 public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
4990 if (!checkLayoutParams(params)) {
4991 throw new IllegalArgumentException("Invalid LayoutParams supplied to " + this);
4992 }
4993 if (view.mParent != this) {
4994 throw new IllegalArgumentException("Given view not a child of " + this);
4995 }
4996 view.setLayoutParams(params);
4997 }
4998
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004999 protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
5000 return p != null;
5001 }
5002
5003 /**
5004 * Interface definition for a callback to be invoked when the hierarchy
5005 * within this view changed. The hierarchy changes whenever a child is added
5006 * to or removed from this view.
5007 */
5008 public interface OnHierarchyChangeListener {
5009 /**
5010 * Called when a new child is added to a parent view.
5011 *
5012 * @param parent the view in which a child was added
5013 * @param child the new child view added in the hierarchy
5014 */
5015 void onChildViewAdded(View parent, View child);
5016
5017 /**
5018 * Called when a child is removed from a parent view.
5019 *
5020 * @param parent the view from which the child was removed
5021 * @param child the child removed from the hierarchy
5022 */
5023 void onChildViewRemoved(View parent, View child);
5024 }
5025
5026 /**
5027 * Register a callback to be invoked when a child is added to or removed
5028 * from this view.
5029 *
5030 * @param listener the callback to invoke on hierarchy change
5031 */
5032 public void setOnHierarchyChangeListener(OnHierarchyChangeListener listener) {
5033 mOnHierarchyChangeListener = listener;
5034 }
5035
Mathew Inwooda570dee2018-08-17 14:56:00 +01005036 @UnsupportedAppUsage
Adam Powell6690d012015-06-17 16:41:56 -07005037 void dispatchViewAdded(View child) {
5038 onViewAdded(child);
Philip Milnef51d91c2011-07-18 16:12:19 -07005039 if (mOnHierarchyChangeListener != null) {
5040 mOnHierarchyChangeListener.onChildViewAdded(this, child);
5041 }
5042 }
5043
5044 /**
Adam Powell6690d012015-06-17 16:41:56 -07005045 * Called when a new child is added to this ViewGroup. Overrides should always
5046 * call super.onViewAdded.
5047 *
5048 * @param child the added child view
Philip Milnef51d91c2011-07-18 16:12:19 -07005049 */
Adam Powell6690d012015-06-17 16:41:56 -07005050 public void onViewAdded(View child) {
5051 }
5052
Mathew Inwooda570dee2018-08-17 14:56:00 +01005053 @UnsupportedAppUsage
Adam Powell6690d012015-06-17 16:41:56 -07005054 void dispatchViewRemoved(View child) {
5055 onViewRemoved(child);
Philip Milnef51d91c2011-07-18 16:12:19 -07005056 if (mOnHierarchyChangeListener != null) {
5057 mOnHierarchyChangeListener.onChildViewRemoved(this, child);
5058 }
5059 }
5060
Adam Powell6690d012015-06-17 16:41:56 -07005061 /**
5062 * Called when a child view is removed from this ViewGroup. Overrides should always
5063 * call super.onViewRemoved.
5064 *
5065 * @param child the removed child view
5066 */
5067 public void onViewRemoved(View child) {
5068 }
5069
Philip Milnecfb631b2012-10-26 10:51:46 -07005070 private void clearCachedLayoutMode() {
Svetoslav6254f482013-06-04 17:22:14 -07005071 if (!hasBooleanFlag(FLAG_LAYOUT_MODE_WAS_EXPLICITLY_SET)) {
Philip Milnecfb631b2012-10-26 10:51:46 -07005072 mLayoutMode = LAYOUT_MODE_UNDEFINED;
5073 }
5074 }
5075
5076 @Override
5077 protected void onAttachedToWindow() {
5078 super.onAttachedToWindow();
5079 clearCachedLayoutMode();
5080 }
5081
5082 @Override
5083 protected void onDetachedFromWindow() {
5084 super.onDetachedFromWindow();
5085 clearCachedLayoutMode();
5086 }
5087
John Reck2de950d2017-01-25 10:58:30 -08005088 /** @hide */
5089 @Override
5090 protected void destroyHardwareResources() {
5091 super.destroyHardwareResources();
5092 int count = getChildCount();
5093 for (int i = 0; i < count; i++) {
5094 getChildAt(i).destroyHardwareResources();
5095 }
5096 }
5097
Philip Milnef51d91c2011-07-18 16:12:19 -07005098 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005099 * Adds a view during layout. This is useful if in your onLayout() method,
5100 * you need to add more views (as does the list view for example).
5101 *
5102 * If index is negative, it means put it at the end of the list.
5103 *
5104 * @param child the view to add to the group
Alan Viverette77bb6f12015-02-11 17:24:33 -08005105 * @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 -08005106 * @param params the layout parameters to associate with the child
5107 * @return true if the child was added, false otherwise
5108 */
5109 protected boolean addViewInLayout(View child, int index, LayoutParams params) {
5110 return addViewInLayout(child, index, params, false);
5111 }
5112
5113 /**
5114 * Adds a view during layout. This is useful if in your onLayout() method,
5115 * you need to add more views (as does the list view for example).
5116 *
5117 * If index is negative, it means put it at the end of the list.
5118 *
5119 * @param child the view to add to the group
Alan Viverette77bb6f12015-02-11 17:24:33 -08005120 * @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 -08005121 * @param params the layout parameters to associate with the child
5122 * @param preventRequestLayout if true, calling this method will not trigger a
5123 * layout request on child
5124 * @return true if the child was added, false otherwise
5125 */
5126 protected boolean addViewInLayout(View child, int index, LayoutParams params,
5127 boolean preventRequestLayout) {
Adam Powell45a9da52014-10-09 09:44:18 -07005128 if (child == null) {
5129 throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup");
5130 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005131 child.mParent = null;
5132 addViewInner(child, index, params, preventRequestLayout);
Dianne Hackborn4702a852012-08-17 15:18:29 -07005133 child.mPrivateFlags = (child.mPrivateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005134 return true;
5135 }
5136
5137 /**
5138 * Prevents the specified child to be laid out during the next layout pass.
5139 *
5140 * @param child the child on which to perform the cleanup
5141 */
5142 protected void cleanupLayoutState(View child) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07005143 child.mPrivateFlags &= ~View.PFLAG_FORCE_LAYOUT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005144 }
5145
5146 private void addViewInner(View child, int index, LayoutParams params,
5147 boolean preventRequestLayout) {
5148
Chet Haasee8e45d32011-03-02 17:07:35 -08005149 if (mTransition != null) {
5150 // Don't prevent other add transitions from completing, but cancel remove
5151 // transitions to let them complete the process before we add to the container
5152 mTransition.cancel(LayoutTransition.DISAPPEARING);
Chet Haaseadd65772011-02-09 16:47:29 -08005153 }
5154
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005155 if (child.getParent() != null) {
5156 throw new IllegalStateException("The specified child already has a parent. " +
5157 "You must call removeView() on the child's parent first.");
5158 }
5159
Chet Haase21cd1382010-09-01 17:42:29 -07005160 if (mTransition != null) {
Chet Haase5e25c2c2010-09-16 11:15:56 -07005161 mTransition.addChild(this, child);
Chet Haase21cd1382010-09-01 17:42:29 -07005162 }
5163
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005164 if (!checkLayoutParams(params)) {
5165 params = generateLayoutParams(params);
5166 }
5167
5168 if (preventRequestLayout) {
5169 child.mLayoutParams = params;
5170 } else {
5171 child.setLayoutParams(params);
5172 }
5173
5174 if (index < 0) {
5175 index = mChildrenCount;
5176 }
5177
5178 addInArray(child, index);
5179
5180 // tell our children
5181 if (preventRequestLayout) {
5182 child.assignParent(this);
5183 } else {
5184 child.mParent = this;
Evan Roskycd80e612018-05-17 17:46:09 -07005185 }
5186 if (child.hasUnhandledKeyListener()) {
5187 incrementChildUnhandledKeyListeners();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005188 }
5189
Evan Rosky2ae1bf52017-05-11 11:18:45 -07005190 final boolean childHasFocus = child.hasFocus();
5191 if (childHasFocus) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005192 requestChildFocus(child, child.findFocus());
5193 }
Romain Guy8506ab42009-06-11 17:35:47 -07005194
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005195 AttachInfo ai = mAttachInfo;
Adam Powell4b867882011-09-16 12:59:46 -07005196 if (ai != null && (mGroupFlags & FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW) == 0) {
Romain Guy8506ab42009-06-11 17:35:47 -07005197 boolean lastKeepOn = ai.mKeepScreenOn;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005198 ai.mKeepScreenOn = false;
5199 child.dispatchAttachedToWindow(mAttachInfo, (mViewFlags&VISIBILITY_MASK));
5200 if (ai.mKeepScreenOn) {
5201 needGlobalAttributesUpdate(true);
5202 }
5203 ai.mKeepScreenOn = lastKeepOn;
5204 }
5205
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07005206 if (child.isLayoutDirectionInherited()) {
Fabrice Di Meglioa7e0bcd2012-10-16 19:55:01 -07005207 child.resetRtlProperties();
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07005208 }
5209
Adam Powell6690d012015-06-17 16:41:56 -07005210 dispatchViewAdded(child);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005211
5212 if ((child.mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE) {
5213 mGroupFlags |= FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE;
5214 }
Adam Powell539ee872012-02-03 19:00:49 -08005215
5216 if (child.hasTransientState()) {
5217 childHasTransientStateChanged(child, true);
5218 }
Svetoslav6254f482013-06-04 17:22:14 -07005219
Svetoslav8e3feb12014-02-24 13:46:47 -08005220 if (child.getVisibility() != View.GONE) {
Eugene Susla72c510f2018-01-23 21:12:11 +00005221 notifySubtreeAccessibilityStateChangedIfNeeded();
Svetoslav6254f482013-06-04 17:22:14 -07005222 }
Chet Haasec633d2f2015-04-07 10:29:39 -07005223
5224 if (mTransientIndices != null) {
5225 final int transientCount = mTransientIndices.size();
5226 for (int i = 0; i < transientCount; ++i) {
5227 final int oldIndex = mTransientIndices.get(i);
5228 if (index <= oldIndex) {
5229 mTransientIndices.set(i, oldIndex + 1);
5230 }
5231 }
5232 }
Vadim Tryshev02ed4a02015-10-23 17:39:33 -07005233
5234 if (mCurrentDragStartEvent != null && child.getVisibility() == VISIBLE) {
5235 notifyChildOfDragStart(child);
5236 }
Vadim Tryshev5ca73982017-01-04 17:24:43 -08005237
5238 if (child.hasDefaultFocus()) {
5239 // When adding a child that contains default focus, either during inflation or while
5240 // manually assembling the hierarchy, update the ancestor default-focus chain.
5241 setDefaultFocus(child);
5242 }
Svetoslav Ganov24c90452017-12-27 15:17:14 -08005243
5244 touchAccessibilityNodeProviderIfNeeded(child);
5245 }
5246
5247 /**
5248 * We may need to touch the provider to bring up the a11y layer. In a11y mode
5249 * clients inspect the screen or the user touches it which triggers bringing up
5250 * of the a11y infrastructure while in autofill mode we want the infra up and
5251 * running from the beginning since we watch for a11y events to drive autofill.
5252 */
5253 private void touchAccessibilityNodeProviderIfNeeded(View child) {
5254 if (mContext.isAutofillCompatibilityEnabled()) {
5255 child.getAccessibilityNodeProvider();
5256 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005257 }
5258
5259 private void addInArray(View child, int index) {
5260 View[] children = mChildren;
5261 final int count = mChildrenCount;
5262 final int size = children.length;
5263 if (index == count) {
5264 if (size == count) {
5265 mChildren = new View[size + ARRAY_CAPACITY_INCREMENT];
5266 System.arraycopy(children, 0, mChildren, 0, size);
5267 children = mChildren;
5268 }
5269 children[mChildrenCount++] = child;
5270 } else if (index < count) {
5271 if (size == count) {
5272 mChildren = new View[size + ARRAY_CAPACITY_INCREMENT];
5273 System.arraycopy(children, 0, mChildren, 0, index);
5274 System.arraycopy(children, index, mChildren, index + 1, count - index);
5275 children = mChildren;
5276 } else {
5277 System.arraycopy(children, index, children, index + 1, count - index);
5278 }
5279 children[index] = child;
5280 mChildrenCount++;
Joe Onorato03ab0c72011-01-06 15:46:27 -08005281 if (mLastTouchDownIndex >= index) {
5282 mLastTouchDownIndex++;
5283 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005284 } else {
5285 throw new IndexOutOfBoundsException("index=" + index + " count=" + count);
5286 }
5287 }
5288
5289 // This method also sets the child's mParent to null
5290 private void removeFromArray(int index) {
5291 final View[] children = mChildren;
Chet Haase21cd1382010-09-01 17:42:29 -07005292 if (!(mTransitioningViews != null && mTransitioningViews.contains(children[index]))) {
5293 children[index].mParent = null;
5294 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005295 final int count = mChildrenCount;
5296 if (index == count - 1) {
5297 children[--mChildrenCount] = null;
5298 } else if (index >= 0 && index < count) {
5299 System.arraycopy(children, index + 1, children, index, count - index - 1);
5300 children[--mChildrenCount] = null;
5301 } else {
5302 throw new IndexOutOfBoundsException();
5303 }
Joe Onorato03ab0c72011-01-06 15:46:27 -08005304 if (mLastTouchDownIndex == index) {
5305 mLastTouchDownTime = 0;
5306 mLastTouchDownIndex = -1;
5307 } else if (mLastTouchDownIndex > index) {
5308 mLastTouchDownIndex--;
5309 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005310 }
5311
5312 // This method also sets the children's mParent to null
5313 private void removeFromArray(int start, int count) {
5314 final View[] children = mChildren;
5315 final int childrenCount = mChildrenCount;
5316
5317 start = Math.max(0, start);
5318 final int end = Math.min(childrenCount, start + count);
5319
5320 if (start == end) {
5321 return;
5322 }
5323
5324 if (end == childrenCount) {
5325 for (int i = start; i < end; i++) {
5326 children[i].mParent = null;
5327 children[i] = null;
5328 }
5329 } else {
5330 for (int i = start; i < end; i++) {
5331 children[i].mParent = null;
5332 }
5333
5334 // Since we're looping above, we might as well do the copy, but is arraycopy()
5335 // faster than the extra 2 bounds checks we would do in the loop?
5336 System.arraycopy(children, end, children, start, childrenCount - end);
5337
5338 for (int i = childrenCount - (end - start); i < childrenCount; i++) {
5339 children[i] = null;
5340 }
5341 }
5342
5343 mChildrenCount -= (end - start);
5344 }
5345
5346 private void bindLayoutAnimation(View child) {
5347 Animation a = mLayoutAnimationController.getAnimationForView(child);
5348 child.setAnimation(a);
5349 }
5350
5351 /**
5352 * Subclasses should override this method to set layout animation
5353 * parameters on the supplied child.
5354 *
5355 * @param child the child to associate with animation parameters
5356 * @param params the child's layout parameters which hold the animation
5357 * parameters
5358 * @param index the index of the child in the view group
5359 * @param count the number of children in the view group
5360 */
5361 protected void attachLayoutAnimationParameters(View child,
5362 LayoutParams params, int index, int count) {
5363 LayoutAnimationController.AnimationParameters animationParams =
5364 params.layoutAnimationParameters;
5365 if (animationParams == null) {
5366 animationParams = new LayoutAnimationController.AnimationParameters();
5367 params.layoutAnimationParameters = animationParams;
5368 }
5369
5370 animationParams.count = count;
5371 animationParams.index = index;
5372 }
5373
5374 /**
5375 * {@inheritDoc}
Filip Gruszczynskia33bdf32015-11-19 18:22:16 -08005376 *
Romain Guy393a52c2012-05-22 20:21:08 -07005377 * <p><strong>Note:</strong> do not invoke this method from
5378 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
5379 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005380 */
Alan Viverettebe463f22016-01-21 10:50:10 -05005381 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005382 public void removeView(View view) {
Alan Viverette177ec4602014-10-17 13:34:50 -07005383 if (removeViewInternal(view)) {
5384 requestLayout();
5385 invalidate(true);
5386 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005387 }
5388
5389 /**
5390 * Removes a view during layout. This is useful if in your onLayout() method,
5391 * you need to remove more views.
5392 *
Romain Guy393a52c2012-05-22 20:21:08 -07005393 * <p><strong>Note:</strong> do not invoke this method from
5394 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
5395 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
Filip Gruszczynskia33bdf32015-11-19 18:22:16 -08005396 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005397 * @param view the view to remove from the group
5398 */
5399 public void removeViewInLayout(View view) {
5400 removeViewInternal(view);
5401 }
5402
5403 /**
5404 * Removes a range of views during layout. This is useful if in your onLayout() method,
5405 * you need to remove more views.
5406 *
Romain Guy393a52c2012-05-22 20:21:08 -07005407 * <p><strong>Note:</strong> do not invoke this method from
5408 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
5409 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
5410 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005411 * @param start the index of the first view to remove from the group
5412 * @param count the number of views to remove from the group
5413 */
5414 public void removeViewsInLayout(int start, int count) {
5415 removeViewsInternal(start, count);
5416 }
5417
5418 /**
5419 * Removes the view at the specified position in the group.
5420 *
Romain Guy393a52c2012-05-22 20:21:08 -07005421 * <p><strong>Note:</strong> do not invoke this method from
5422 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
5423 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
Filip Gruszczynskia33bdf32015-11-19 18:22:16 -08005424 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005425 * @param index the position in the group of the view to remove
5426 */
5427 public void removeViewAt(int index) {
5428 removeViewInternal(index, getChildAt(index));
5429 requestLayout();
Romain Guy849d0a32011-02-01 17:20:48 -08005430 invalidate(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005431 }
5432
5433 /**
5434 * Removes the specified range of views from the group.
5435 *
Romain Guy393a52c2012-05-22 20:21:08 -07005436 * <p><strong>Note:</strong> do not invoke this method from
5437 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
5438 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
5439 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005440 * @param start the first position in the group of the range of views to remove
5441 * @param count the number of views to remove
5442 */
5443 public void removeViews(int start, int count) {
5444 removeViewsInternal(start, count);
5445 requestLayout();
Romain Guy849d0a32011-02-01 17:20:48 -08005446 invalidate(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005447 }
5448
Alan Viverette177ec4602014-10-17 13:34:50 -07005449 private boolean removeViewInternal(View view) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005450 final int index = indexOfChild(view);
5451 if (index >= 0) {
5452 removeViewInternal(index, view);
Alan Viverette177ec4602014-10-17 13:34:50 -07005453 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005454 }
Alan Viverette177ec4602014-10-17 13:34:50 -07005455 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005456 }
5457
5458 private void removeViewInternal(int index, View view) {
Chet Haase21cd1382010-09-01 17:42:29 -07005459 if (mTransition != null) {
Chet Haase5e25c2c2010-09-16 11:15:56 -07005460 mTransition.removeChild(this, view);
Chet Haase21cd1382010-09-01 17:42:29 -07005461 }
5462
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005463 boolean clearChildFocus = false;
5464 if (view == mFocused) {
Alan Viverette223622a2013-12-17 13:29:02 -08005465 view.unFocus(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005466 clearChildFocus = true;
5467 }
Evan Rosky53fcf112017-01-26 14:37:55 -08005468 if (view == mFocusedInCluster) {
Evan Rosky0e8a6832017-04-10 12:35:15 -07005469 clearFocusedInCluster(view);
Vadim Tryshev01d8c492016-12-15 11:33:15 -08005470 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005471
Alan Viverette632af842014-10-28 13:45:11 -07005472 view.clearAccessibilityFocus();
Svetoslav Ganov961bf0e2012-05-08 09:40:03 -07005473
Jeff Brown59a422e2012-04-19 15:19:19 -07005474 cancelTouchTarget(view);
5475 cancelHoverTarget(view);
5476
Chet Haase21cd1382010-09-01 17:42:29 -07005477 if (view.getAnimation() != null ||
5478 (mTransitioningViews != null && mTransitioningViews.contains(view))) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005479 addDisappearingView(view);
5480 } else if (view.mAttachInfo != null) {
5481 view.dispatchDetachedFromWindow();
5482 }
5483
Adam Powell539ee872012-02-03 19:00:49 -08005484 if (view.hasTransientState()) {
5485 childHasTransientStateChanged(view, false);
5486 }
5487
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005488 needGlobalAttributesUpdate(false);
Romain Guy8506ab42009-06-11 17:35:47 -07005489
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005490 removeFromArray(index);
5491
Evan Rosky4807ae22018-03-22 16:04:15 -07005492 if (view.hasUnhandledKeyListener()) {
5493 decrementChildUnhandledKeyListeners();
5494 }
5495
Evan Rosky53fcf112017-01-26 14:37:55 -08005496 if (view == mDefaultFocus) {
5497 clearDefaultFocus(view);
5498 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005499 if (clearChildFocus) {
5500 clearChildFocus(view);
Svetoslav Ganov149567f2013-01-08 15:23:34 -08005501 if (!rootViewRequestFocus()) {
5502 notifyGlobalFocusCleared(this);
5503 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07005504 }
Romain Guy6fb05632012-11-29 10:50:33 -08005505
Adam Powell6690d012015-06-17 16:41:56 -07005506 dispatchViewRemoved(view);
Svetoslav6254f482013-06-04 17:22:14 -07005507
Svetoslav8e3feb12014-02-24 13:46:47 -08005508 if (view.getVisibility() != View.GONE) {
Eugene Susla72c510f2018-01-23 21:12:11 +00005509 notifySubtreeAccessibilityStateChangedIfNeeded();
Svetoslav6254f482013-06-04 17:22:14 -07005510 }
Chet Haasec633d2f2015-04-07 10:29:39 -07005511
5512 int transientCount = mTransientIndices == null ? 0 : mTransientIndices.size();
5513 for (int i = 0; i < transientCount; ++i) {
5514 final int oldIndex = mTransientIndices.get(i);
5515 if (index < oldIndex) {
5516 mTransientIndices.set(i, oldIndex - 1);
5517 }
5518 }
Vadim Tryshev02ed4a02015-10-23 17:39:33 -07005519
5520 if (mCurrentDragStartEvent != null) {
5521 mChildrenInterestedInDrag.remove(view);
5522 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005523 }
5524
Chet Haase21cd1382010-09-01 17:42:29 -07005525 /**
5526 * Sets the LayoutTransition object for this ViewGroup. If the LayoutTransition object is
5527 * not null, changes in layout which occur because of children being added to or removed from
5528 * the ViewGroup will be animated according to the animations defined in that LayoutTransition
5529 * object. By default, the transition object is null (so layout changes are not animated).
5530 *
Chet Haaseef3cbfd2013-08-21 14:01:02 -07005531 * <p>Replacing a non-null transition will cause that previous transition to be
5532 * canceled, if it is currently running, to restore this container to
5533 * its correct post-transition state.</p>
5534 *
Chet Haase21cd1382010-09-01 17:42:29 -07005535 * @param transition The LayoutTransition object that will animated changes in layout. A value
5536 * of <code>null</code> means no transition will run on layout changes.
Chet Haase13cc1202010-09-03 15:39:20 -07005537 * @attr ref android.R.styleable#ViewGroup_animateLayoutChanges
Chet Haase21cd1382010-09-01 17:42:29 -07005538 */
5539 public void setLayoutTransition(LayoutTransition transition) {
Chet Haaseb20db3e2010-09-10 13:07:30 -07005540 if (mTransition != null) {
Chet Haasefee6f2b2013-08-27 12:22:29 -07005541 LayoutTransition previousTransition = mTransition;
5542 previousTransition.cancel();
5543 previousTransition.removeTransitionListener(mLayoutTransitionListener);
Chet Haaseb20db3e2010-09-10 13:07:30 -07005544 }
Chet Haase21cd1382010-09-01 17:42:29 -07005545 mTransition = transition;
Chet Haase13cc1202010-09-03 15:39:20 -07005546 if (mTransition != null) {
5547 mTransition.addTransitionListener(mLayoutTransitionListener);
5548 }
5549 }
5550
5551 /**
5552 * Gets the LayoutTransition object for this ViewGroup. If the LayoutTransition object is
5553 * not null, changes in layout which occur because of children being added to or removed from
5554 * the ViewGroup will be animated according to the animations defined in that LayoutTransition
5555 * object. By default, the transition object is null (so layout changes are not animated).
5556 *
5557 * @return LayoutTranstion The LayoutTransition object that will animated changes in layout.
5558 * A value of <code>null</code> means no transition will run on layout changes.
5559 */
5560 public LayoutTransition getLayoutTransition() {
5561 return mTransition;
Chet Haase21cd1382010-09-01 17:42:29 -07005562 }
5563
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005564 private void removeViewsInternal(int start, int count) {
Chris Craik18a759d2015-10-14 14:16:33 -07005565 final int end = start + count;
5566
5567 if (start < 0 || count < 0 || end > mChildrenCount) {
5568 throw new IndexOutOfBoundsException();
5569 }
5570
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005571 final View focused = mFocused;
5572 final boolean detach = mAttachInfo != null;
Svetoslav Ganov149567f2013-01-08 15:23:34 -08005573 boolean clearChildFocus = false;
Evan Rosky53fcf112017-01-26 14:37:55 -08005574 View clearDefaultFocus = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005575
5576 final View[] children = mChildren;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005577
5578 for (int i = start; i < end; 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 }
Vadim Tryshev5ca73982017-01-04 17:24:43 -08005589 if (view == mDefaultFocus) {
Evan Rosky53fcf112017-01-26 14:37:55 -08005590 clearDefaultFocus = view;
5591 }
5592 if (view == mFocusedInCluster) {
Evan Rosky0e8a6832017-04-10 12:35:15 -07005593 clearFocusedInCluster(view);
Vadim Tryshev01d8c492016-12-15 11:33:15 -08005594 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005595
Alan Viverette632af842014-10-28 13:45:11 -07005596 view.clearAccessibilityFocus();
Svetoslav Ganov961bf0e2012-05-08 09:40:03 -07005597
Jeff Brown59a422e2012-04-19 15:19:19 -07005598 cancelTouchTarget(view);
5599 cancelHoverTarget(view);
5600
Chet Haase21cd1382010-09-01 17:42:29 -07005601 if (view.getAnimation() != null ||
5602 (mTransitioningViews != null && mTransitioningViews.contains(view))) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005603 addDisappearingView(view);
5604 } else if (detach) {
5605 view.dispatchDetachedFromWindow();
5606 }
5607
Adam Powell539ee872012-02-03 19:00:49 -08005608 if (view.hasTransientState()) {
5609 childHasTransientStateChanged(view, false);
5610 }
5611
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005612 needGlobalAttributesUpdate(false);
Romain Guy8506ab42009-06-11 17:35:47 -07005613
Adam Powell6690d012015-06-17 16:41:56 -07005614 dispatchViewRemoved(view);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005615 }
5616
5617 removeFromArray(start, count);
5618
Evan Rosky53fcf112017-01-26 14:37:55 -08005619 if (clearDefaultFocus != null) {
5620 clearDefaultFocus(clearDefaultFocus);
5621 }
Svetoslav Ganov149567f2013-01-08 15:23:34 -08005622 if (clearChildFocus) {
5623 clearChildFocus(focused);
5624 if (!rootViewRequestFocus()) {
5625 notifyGlobalFocusCleared(focused);
5626 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005627 }
5628 }
5629
5630 /**
5631 * Call this method to remove all child views from the
5632 * ViewGroup.
Filip Gruszczynskia33bdf32015-11-19 18:22:16 -08005633 *
Romain Guy393a52c2012-05-22 20:21:08 -07005634 * <p><strong>Note:</strong> do not invoke this method from
5635 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
5636 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005637 */
5638 public void removeAllViews() {
5639 removeAllViewsInLayout();
5640 requestLayout();
Romain Guy849d0a32011-02-01 17:20:48 -08005641 invalidate(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005642 }
5643
5644 /**
5645 * Called by a ViewGroup subclass to remove child views from itself,
5646 * when it must first know its size on screen before it can calculate how many
5647 * child views it will render. An example is a Gallery or a ListView, which
5648 * may "have" 50 children, but actually only render the number of children
5649 * that can currently fit inside the object on screen. Do not call
5650 * this method unless you are extending ViewGroup and understand the
5651 * view measuring and layout pipeline.
Romain Guy393a52c2012-05-22 20:21:08 -07005652 *
5653 * <p><strong>Note:</strong> do not invoke this method from
5654 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
5655 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005656 */
5657 public void removeAllViewsInLayout() {
5658 final int count = mChildrenCount;
5659 if (count <= 0) {
5660 return;
5661 }
5662
5663 final View[] children = mChildren;
5664 mChildrenCount = 0;
5665
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005666 final View focused = mFocused;
5667 final boolean detach = mAttachInfo != null;
Svetoslav Ganov149567f2013-01-08 15:23:34 -08005668 boolean clearChildFocus = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005669
5670 needGlobalAttributesUpdate(false);
Romain Guy8506ab42009-06-11 17:35:47 -07005671
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005672 for (int i = count - 1; i >= 0; i--) {
5673 final View view = children[i];
5674
Chet Haase21cd1382010-09-01 17:42:29 -07005675 if (mTransition != null) {
Chet Haase5e25c2c2010-09-16 11:15:56 -07005676 mTransition.removeChild(this, view);
Chet Haase21cd1382010-09-01 17:42:29 -07005677 }
5678
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005679 if (view == focused) {
Alan Viverette223622a2013-12-17 13:29:02 -08005680 view.unFocus(null);
Svetoslav Ganov149567f2013-01-08 15:23:34 -08005681 clearChildFocus = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005682 }
5683
Alan Viverette632af842014-10-28 13:45:11 -07005684 view.clearAccessibilityFocus();
Svetoslav Ganov961bf0e2012-05-08 09:40:03 -07005685
Jeff Brown59a422e2012-04-19 15:19:19 -07005686 cancelTouchTarget(view);
5687 cancelHoverTarget(view);
5688
Chet Haase21cd1382010-09-01 17:42:29 -07005689 if (view.getAnimation() != null ||
5690 (mTransitioningViews != null && mTransitioningViews.contains(view))) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005691 addDisappearingView(view);
5692 } else if (detach) {
5693 view.dispatchDetachedFromWindow();
5694 }
5695
Adam Powell539ee872012-02-03 19:00:49 -08005696 if (view.hasTransientState()) {
5697 childHasTransientStateChanged(view, false);
5698 }
5699
Adam Powell6690d012015-06-17 16:41:56 -07005700 dispatchViewRemoved(view);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005701
5702 view.mParent = null;
5703 children[i] = null;
5704 }
5705
Evan Rosky53fcf112017-01-26 14:37:55 -08005706 if (mDefaultFocus != null) {
5707 clearDefaultFocus(mDefaultFocus);
5708 }
Evan Rosky776fa5f2017-04-26 16:47:54 -07005709 if (mFocusedInCluster != null) {
5710 clearFocusedInCluster(mFocusedInCluster);
5711 }
Svetoslav Ganov149567f2013-01-08 15:23:34 -08005712 if (clearChildFocus) {
5713 clearChildFocus(focused);
5714 if (!rootViewRequestFocus()) {
5715 notifyGlobalFocusCleared(focused);
5716 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005717 }
5718 }
5719
5720 /**
5721 * Finishes the removal of a detached view. This method will dispatch the detached from
5722 * window event and notify the hierarchy change listener.
Chet Haaseca479d42012-08-30 17:20:08 -07005723 * <p>
5724 * This method is intended to be lightweight and makes no assumptions about whether the
5725 * parent or child should be redrawn. Proper use of this method will include also making
5726 * any appropriate {@link #requestLayout()} or {@link #invalidate()} calls.
5727 * For example, callers can {@link #post(Runnable) post} a {@link Runnable}
5728 * which performs a {@link #requestLayout()} on the next frame, after all detach/remove
5729 * calls are finished, causing layout to be run prior to redrawing the view hierarchy.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005730 *
5731 * @param child the child to be definitely removed from the view hierarchy
5732 * @param animate if true and the view has an animation, the view is placed in the
5733 * disappearing views list, otherwise, it is detached from the window
5734 *
5735 * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
5736 * @see #detachAllViewsFromParent()
5737 * @see #detachViewFromParent(View)
5738 * @see #detachViewFromParent(int)
5739 */
5740 protected void removeDetachedView(View child, boolean animate) {
Chet Haase21cd1382010-09-01 17:42:29 -07005741 if (mTransition != null) {
Chet Haase5e25c2c2010-09-16 11:15:56 -07005742 mTransition.removeChild(this, child);
Chet Haase21cd1382010-09-01 17:42:29 -07005743 }
5744
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005745 if (child == mFocused) {
5746 child.clearFocus();
5747 }
Vadim Tryshev5ca73982017-01-04 17:24:43 -08005748 if (child == mDefaultFocus) {
Evan Rosky53fcf112017-01-26 14:37:55 -08005749 clearDefaultFocus(child);
5750 }
5751 if (child == mFocusedInCluster) {
Evan Rosky0e8a6832017-04-10 12:35:15 -07005752 clearFocusedInCluster(child);
Vadim Tryshev01d8c492016-12-15 11:33:15 -08005753 }
Romain Guy8506ab42009-06-11 17:35:47 -07005754
Svetoslav Ganov961bf0e2012-05-08 09:40:03 -07005755 child.clearAccessibilityFocus();
5756
Jeff Brown59a422e2012-04-19 15:19:19 -07005757 cancelTouchTarget(child);
5758 cancelHoverTarget(child);
5759
Chet Haase21cd1382010-09-01 17:42:29 -07005760 if ((animate && child.getAnimation() != null) ||
5761 (mTransitioningViews != null && mTransitioningViews.contains(child))) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005762 addDisappearingView(child);
5763 } else if (child.mAttachInfo != null) {
5764 child.dispatchDetachedFromWindow();
5765 }
5766
Adam Powell539ee872012-02-03 19:00:49 -08005767 if (child.hasTransientState()) {
5768 childHasTransientStateChanged(child, false);
5769 }
5770
Adam Powell6690d012015-06-17 16:41:56 -07005771 dispatchViewRemoved(child);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005772 }
5773
5774 /**
5775 * Attaches a view to this view group. Attaching a view assigns this group as the parent,
Chet Haaseca479d42012-08-30 17:20:08 -07005776 * sets the layout parameters and puts the view in the list of children so that
5777 * it can be retrieved by calling {@link #getChildAt(int)}.
5778 * <p>
5779 * This method is intended to be lightweight and makes no assumptions about whether the
5780 * parent or child should be redrawn. Proper use of this method will include also making
5781 * any appropriate {@link #requestLayout()} or {@link #invalidate()} calls.
5782 * For example, callers can {@link #post(Runnable) post} a {@link Runnable}
5783 * which performs a {@link #requestLayout()} on the next frame, after all detach/attach
5784 * calls are finished, causing layout to be run prior to redrawing the view hierarchy.
5785 * <p>
5786 * This method should be called only for views which were detached from their parent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005787 *
5788 * @param child the child to attach
5789 * @param index the index at which the child should be attached
5790 * @param params the layout parameters of the child
5791 *
5792 * @see #removeDetachedView(View, boolean)
5793 * @see #detachAllViewsFromParent()
5794 * @see #detachViewFromParent(View)
5795 * @see #detachViewFromParent(int)
5796 */
5797 protected void attachViewToParent(View child, int index, LayoutParams params) {
5798 child.mLayoutParams = params;
5799
5800 if (index < 0) {
5801 index = mChildrenCount;
5802 }
5803
5804 addInArray(child, index);
5805
5806 child.mParent = this;
Dianne Hackborn4702a852012-08-17 15:18:29 -07005807 child.mPrivateFlags = (child.mPrivateFlags & ~PFLAG_DIRTY_MASK
5808 & ~PFLAG_DRAWING_CACHE_VALID)
5809 | PFLAG_DRAWN | PFLAG_INVALIDATED;
5810 this.mPrivateFlags |= PFLAG_INVALIDATED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005811
5812 if (child.hasFocus()) {
5813 requestChildFocus(child, child.findFocus());
5814 }
Adam Powellc5874092016-03-17 16:27:24 -07005815 dispatchVisibilityAggregated(isAttachedToWindow() && getWindowVisibility() == VISIBLE
5816 && isShown());
Phil Weaver13171622018-04-03 11:39:20 -07005817 notifySubtreeAccessibilityStateChangedIfNeeded();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005818 }
5819
5820 /**
Chet Haaseca479d42012-08-30 17:20:08 -07005821 * Detaches a view from its parent. Detaching a view should be followed
5822 * either by a call to
5823 * {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
5824 * or a call to {@link #removeDetachedView(View, boolean)}. Detachment should only be
5825 * temporary; reattachment or removal should happen within the same drawing cycle as
5826 * detachment. When a view is detached, its parent is null and cannot be retrieved by a
5827 * call to {@link #getChildAt(int)}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005828 *
5829 * @param child the child to detach
5830 *
5831 * @see #detachViewFromParent(int)
5832 * @see #detachViewsFromParent(int, int)
5833 * @see #detachAllViewsFromParent()
5834 * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
5835 * @see #removeDetachedView(View, boolean)
5836 */
5837 protected void detachViewFromParent(View child) {
5838 removeFromArray(indexOfChild(child));
5839 }
5840
5841 /**
Chet Haaseca479d42012-08-30 17:20:08 -07005842 * Detaches a view from its parent. Detaching a view should be followed
5843 * either by a call to
5844 * {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
5845 * or a call to {@link #removeDetachedView(View, boolean)}. Detachment should only be
5846 * temporary; reattachment or removal should happen within the same drawing cycle as
5847 * detachment. When a view is detached, its parent is null and cannot be retrieved by a
5848 * call to {@link #getChildAt(int)}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005849 *
5850 * @param index the index of the child to detach
5851 *
5852 * @see #detachViewFromParent(View)
5853 * @see #detachAllViewsFromParent()
5854 * @see #detachViewsFromParent(int, int)
5855 * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
5856 * @see #removeDetachedView(View, boolean)
5857 */
5858 protected void detachViewFromParent(int index) {
5859 removeFromArray(index);
5860 }
5861
5862 /**
Chet Haaseca479d42012-08-30 17:20:08 -07005863 * Detaches a range of views from their parents. Detaching a view should be followed
5864 * either by a call to
5865 * {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
5866 * or a call to {@link #removeDetachedView(View, boolean)}. Detachment should only be
5867 * temporary; reattachment or removal should happen within the same drawing cycle as
5868 * detachment. When a view is detached, its parent is null and cannot be retrieved by a
5869 * call to {@link #getChildAt(int)}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005870 *
5871 * @param start the first index of the childrend range to detach
5872 * @param count the number of children to detach
5873 *
5874 * @see #detachViewFromParent(View)
5875 * @see #detachViewFromParent(int)
5876 * @see #detachAllViewsFromParent()
5877 * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
5878 * @see #removeDetachedView(View, boolean)
5879 */
5880 protected void detachViewsFromParent(int start, int count) {
5881 removeFromArray(start, count);
5882 }
5883
5884 /**
Chet Haaseca479d42012-08-30 17:20:08 -07005885 * Detaches all views from the parent. Detaching a view should be followed
5886 * either by a call to
5887 * {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
5888 * or a call to {@link #removeDetachedView(View, boolean)}. Detachment should only be
5889 * temporary; reattachment or removal should happen within the same drawing cycle as
5890 * detachment. When a view is detached, its parent is null and cannot be retrieved by a
5891 * call to {@link #getChildAt(int)}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005892 *
5893 * @see #detachViewFromParent(View)
5894 * @see #detachViewFromParent(int)
5895 * @see #detachViewsFromParent(int, int)
5896 * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
5897 * @see #removeDetachedView(View, boolean)
5898 */
5899 protected void detachAllViewsFromParent() {
5900 final int count = mChildrenCount;
5901 if (count <= 0) {
5902 return;
5903 }
5904
5905 final View[] children = mChildren;
5906 mChildrenCount = 0;
5907
5908 for (int i = count - 1; i >= 0; i--) {
5909 children[i].mParent = null;
5910 children[i] = null;
5911 }
5912 }
5913
Chris Craik9de95db2017-01-18 17:59:23 -08005914 @Override
5915 @CallSuper
5916 public void onDescendantInvalidated(@NonNull View child, @NonNull View target) {
5917 /*
5918 * HW-only, Rect-ignoring damage codepath
5919 *
5920 * We don't deal with rectangles here, since RenderThread native code computes damage for
5921 * everything drawn by HWUI (and SW layer / drawing cache doesn't keep track of damage area)
5922 */
5923
5924 // if set, combine the animation flag into the parent
5925 mPrivateFlags |= (target.mPrivateFlags & PFLAG_DRAW_ANIMATION);
5926
5927 if ((target.mPrivateFlags & ~PFLAG_DIRTY_MASK) != 0) {
5928 // We lazily use PFLAG_DIRTY, since computing opaque isn't worth the potential
5929 // optimization in provides in a DisplayList world.
5930 mPrivateFlags = (mPrivateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DIRTY;
5931
5932 // simplified invalidateChildInParent behavior: clear cache validity to be safe...
5933 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
Chris Craik3f06c6d2017-01-09 18:19:48 +00005934 }
5935
Chris Craik9de95db2017-01-18 17:59:23 -08005936 // ... and mark inval if in software layer that needs to repaint (hw handled in native)
5937 if (mLayerType == LAYER_TYPE_SOFTWARE) {
5938 // Layered parents should be invalidated. Escalate to a full invalidate (and note that
5939 // we do this after consuming any relevant flags from the originating descendant)
5940 mPrivateFlags |= PFLAG_INVALIDATED | PFLAG_DIRTY;
5941 target = this;
Chris Craik3f06c6d2017-01-09 18:19:48 +00005942 }
5943
Chris Craik9de95db2017-01-18 17:59:23 -08005944 if (mParent != null) {
5945 mParent.onDescendantInvalidated(this, target);
Chris Craik3f06c6d2017-01-09 18:19:48 +00005946 }
Chris Craik3f06c6d2017-01-09 18:19:48 +00005947 }
5948
5949
5950 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005951 * Don't call or override this method. It is used for the implementation of
5952 * the view hierarchy.
Chris Craik9de95db2017-01-18 17:59:23 -08005953 *
5954 * @deprecated Use {@link #onDescendantInvalidated(View, View)} instead to observe updates to
5955 * draw state in descendants.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005956 */
Chris Craik9de95db2017-01-18 17:59:23 -08005957 @Deprecated
Alan Viverettebe463f22016-01-21 10:50:10 -05005958 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005959 public final void invalidateChild(View child, final Rect dirty) {
Chris Craik9de95db2017-01-18 17:59:23 -08005960 final AttachInfo attachInfo = mAttachInfo;
5961 if (attachInfo != null && attachInfo.mHardwareAccelerated) {
5962 // HW accelerated fast path
5963 onDescendantInvalidated(child, child);
Chris Craik3f06c6d2017-01-09 18:19:48 +00005964 return;
5965 }
5966
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005967 ViewParent parent = this;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005968 if (attachInfo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005969 // If the child is drawing an animation, we want to copy this flag onto
5970 // ourselves and the parent to make sure the invalidate request goes
5971 // through
Chris Craik3f06c6d2017-01-09 18:19:48 +00005972 final boolean drawAnimation = (child.mPrivateFlags & PFLAG_DRAW_ANIMATION) != 0;
Romain Guy24443ea2009-05-11 11:56:30 -07005973
Romain Guyfe455af2012-02-15 16:40:20 -08005974 // Check whether the child that requests the invalidate is fully opaque
5975 // Views being animated or transformed are not considered opaque because we may
5976 // be invalidating their old position and need the parent to paint behind them.
5977 Matrix childMatrix = child.getMatrix();
Romain Guyfe455af2012-02-15 16:40:20 -08005978 // Mark the child as dirty, using the appropriate flag
5979 // Make sure we do not set both flags at the same time
Romain Guyfe455af2012-02-15 16:40:20 -08005980
John Reck96bb8ad2014-06-19 10:53:03 -07005981 if (child.mLayerType != LAYER_TYPE_NONE) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07005982 mPrivateFlags |= PFLAG_INVALIDATED;
5983 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
Romain Guyfe455af2012-02-15 16:40:20 -08005984 }
5985
5986 final int[] location = attachInfo.mInvalidateChildLocation;
5987 location[CHILD_LEFT_INDEX] = child.mLeft;
5988 location[CHILD_TOP_INDEX] = child.mTop;
Chet Haase599913d2012-07-23 16:22:05 -07005989 if (!childMatrix.isIdentity() ||
5990 (mGroupFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) {
Romain Guyfe455af2012-02-15 16:40:20 -08005991 RectF boundingRect = attachInfo.mTmpTransformRect;
5992 boundingRect.set(dirty);
Chet Haase599913d2012-07-23 16:22:05 -07005993 Matrix transformMatrix;
5994 if ((mGroupFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) {
5995 Transformation t = attachInfo.mTmpTransformation;
5996 boolean transformed = getChildStaticTransformation(child, t);
5997 if (transformed) {
5998 transformMatrix = attachInfo.mTmpMatrix;
5999 transformMatrix.set(t.getMatrix());
6000 if (!childMatrix.isIdentity()) {
6001 transformMatrix.preConcat(childMatrix);
6002 }
6003 } else {
6004 transformMatrix = childMatrix;
6005 }
6006 } else {
6007 transformMatrix = childMatrix;
6008 }
6009 transformMatrix.mapRect(boundingRect);
Alan Viverettec45b1d42015-11-16 15:38:59 -05006010 dirty.set((int) Math.floor(boundingRect.left),
6011 (int) Math.floor(boundingRect.top),
6012 (int) Math.ceil(boundingRect.right),
6013 (int) Math.ceil(boundingRect.bottom));
Romain Guyfe455af2012-02-15 16:40:20 -08006014 }
6015
6016 do {
6017 View view = null;
6018 if (parent instanceof View) {
6019 view = (View) parent;
Romain Guyfe455af2012-02-15 16:40:20 -08006020 }
6021
6022 if (drawAnimation) {
6023 if (view != null) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07006024 view.mPrivateFlags |= PFLAG_DRAW_ANIMATION;
Romain Guyfe455af2012-02-15 16:40:20 -08006025 } else if (parent instanceof ViewRootImpl) {
6026 ((ViewRootImpl) parent).mIsAnimating = true;
6027 }
6028 }
6029
6030 // If the parent is dirty opaque or not dirty, mark it dirty with the opaque
6031 // flag coming from the child that initiated the invalidate
6032 if (view != null) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07006033 if ((view.mPrivateFlags & PFLAG_DIRTY_MASK) != PFLAG_DIRTY) {
Nader Jawad70e72992018-05-08 10:54:33 -07006034 view.mPrivateFlags = (view.mPrivateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DIRTY;
Romain Guyfe455af2012-02-15 16:40:20 -08006035 }
6036 }
6037
6038 parent = parent.invalidateChildInParent(location, dirty);
6039 if (view != null) {
6040 // Account for transform on current parent
6041 Matrix m = view.getMatrix();
6042 if (!m.isIdentity()) {
6043 RectF boundingRect = attachInfo.mTmpTransformRect;
6044 boundingRect.set(dirty);
6045 m.mapRect(boundingRect);
Alan Viverettec45b1d42015-11-16 15:38:59 -05006046 dirty.set((int) Math.floor(boundingRect.left),
6047 (int) Math.floor(boundingRect.top),
6048 (int) Math.ceil(boundingRect.right),
6049 (int) Math.ceil(boundingRect.bottom));
Romain Guyfe455af2012-02-15 16:40:20 -08006050 }
6051 }
6052 } while (parent != null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006053 }
6054 }
6055
6056 /**
6057 * Don't call or override this method. It is used for the implementation of
6058 * the view hierarchy.
6059 *
6060 * This implementation returns null if this ViewGroup does not have a parent,
6061 * if this ViewGroup is already fully invalidated or if the dirty rectangle
6062 * does not intersect with this ViewGroup's bounds.
Chris Craik9de95db2017-01-18 17:59:23 -08006063 *
6064 * @deprecated Use {@link #onDescendantInvalidated(View, View)} instead to observe updates to
6065 * draw state in descendants.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006066 */
Chris Craik9de95db2017-01-18 17:59:23 -08006067 @Deprecated
Alan Viverettebe463f22016-01-21 10:50:10 -05006068 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006069 public ViewParent invalidateChildInParent(final int[] location, final Rect dirty) {
Chris Craik3f06c6d2017-01-09 18:19:48 +00006070 if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID)) != 0) {
6071 // either DRAWN, or DRAWING_CACHE_VALID
6072 if ((mGroupFlags & (FLAG_OPTIMIZE_INVALIDATE | FLAG_ANIMATION_DONE))
6073 != FLAG_OPTIMIZE_INVALIDATE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006074 dirty.offset(location[CHILD_LEFT_INDEX] - mScrollX,
6075 location[CHILD_TOP_INDEX] - mScrollY);
Chet Haasea4f14eb2013-04-22 11:11:39 -07006076 if ((mGroupFlags & FLAG_CLIP_CHILDREN) == 0) {
6077 dirty.union(0, 0, mRight - mLeft, mBottom - mTop);
6078 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006079
6080 final int left = mLeft;
6081 final int top = mTop;
6082
Chet Haase05e91ed2012-07-03 14:17:57 -07006083 if ((mGroupFlags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN) {
6084 if (!dirty.intersect(0, 0, mRight - left, mBottom - top)) {
6085 dirty.setEmpty();
Romain Guy3a3133d2011-02-01 22:59:58 -08006086 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006087 }
Chet Haase05e91ed2012-07-03 14:17:57 -07006088
6089 location[CHILD_LEFT_INDEX] = left;
6090 location[CHILD_TOP_INDEX] = top;
Selim Cinek1cb8b082016-12-21 15:34:30 +00006091 } else {
Selim Cinek1cb8b082016-12-21 15:34:30 +00006092
Chet Haasea3db8662011-07-19 10:36:05 -07006093 if ((mGroupFlags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN) {
6094 dirty.set(0, 0, mRight - mLeft, mBottom - mTop);
6095 } else {
6096 // in case the dirty rect extends outside the bounds of this container
6097 dirty.union(0, 0, mRight - mLeft, mBottom - mTop);
6098 }
Chris Craik3f06c6d2017-01-09 18:19:48 +00006099 location[CHILD_LEFT_INDEX] = mLeft;
6100 location[CHILD_TOP_INDEX] = mTop;
Romain Guy3a3133d2011-02-01 22:59:58 -08006101
Chris Craik3f06c6d2017-01-09 18:19:48 +00006102 mPrivateFlags &= ~PFLAG_DRAWN;
Selim Cinek1cb8b082016-12-21 15:34:30 +00006103 }
Chris Craik3f06c6d2017-01-09 18:19:48 +00006104 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
6105 if (mLayerType != LAYER_TYPE_NONE) {
6106 mPrivateFlags |= PFLAG_INVALIDATED;
6107 }
6108
6109 return mParent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006110 }
6111
6112 return null;
6113 }
6114
6115 /**
6116 * Offset a rectangle that is in a descendant's coordinate
6117 * space into our coordinate space.
6118 * @param descendant A descendant of this view
6119 * @param rect A rectangle defined in descendant's coordinate space.
6120 */
6121 public final void offsetDescendantRectToMyCoords(View descendant, Rect rect) {
6122 offsetRectBetweenParentAndChild(descendant, rect, true, false);
6123 }
6124
6125 /**
6126 * Offset a rectangle that is in our coordinate space into an ancestor's
6127 * coordinate space.
6128 * @param descendant A descendant of this view
6129 * @param rect A rectangle defined in descendant's coordinate space.
6130 */
6131 public final void offsetRectIntoDescendantCoords(View descendant, Rect rect) {
6132 offsetRectBetweenParentAndChild(descendant, rect, false, false);
6133 }
6134
6135 /**
6136 * Helper method that offsets a rect either from parent to descendant or
6137 * descendant to parent.
6138 */
6139 void offsetRectBetweenParentAndChild(View descendant, Rect rect,
6140 boolean offsetFromChildToParent, boolean clipToBounds) {
6141
6142 // already in the same coord system :)
6143 if (descendant == this) {
6144 return;
6145 }
6146
6147 ViewParent theParent = descendant.mParent;
6148
6149 // search and offset up to the parent
6150 while ((theParent != null)
6151 && (theParent instanceof View)
6152 && (theParent != this)) {
6153
6154 if (offsetFromChildToParent) {
Hyunyoung Song4eb1a4e2016-03-09 22:51:02 +00006155 rect.offset(descendant.mLeft - descendant.mScrollX,
6156 descendant.mTop - descendant.mScrollY);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006157 if (clipToBounds) {
6158 View p = (View) theParent;
Doris Liu9607fbe2015-05-28 17:17:28 -07006159 boolean intersected = rect.intersect(0, 0, p.mRight - p.mLeft,
6160 p.mBottom - p.mTop);
6161 if (!intersected) {
6162 rect.setEmpty();
6163 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006164 }
6165 } else {
6166 if (clipToBounds) {
6167 View p = (View) theParent;
Doris Liu9607fbe2015-05-28 17:17:28 -07006168 boolean intersected = rect.intersect(0, 0, p.mRight - p.mLeft,
6169 p.mBottom - p.mTop);
6170 if (!intersected) {
6171 rect.setEmpty();
6172 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006173 }
Hyunyoung Song4eb1a4e2016-03-09 22:51:02 +00006174 rect.offset(descendant.mScrollX - descendant.mLeft,
6175 descendant.mScrollY - descendant.mTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006176 }
6177
6178 descendant = (View) theParent;
6179 theParent = descendant.mParent;
6180 }
6181
6182 // now that we are up to this view, need to offset one more time
6183 // to get into our coordinate space
6184 if (theParent == this) {
6185 if (offsetFromChildToParent) {
Hyunyoung Song4eb1a4e2016-03-09 22:51:02 +00006186 rect.offset(descendant.mLeft - descendant.mScrollX,
6187 descendant.mTop - descendant.mScrollY);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006188 } else {
Hyunyoung Song4eb1a4e2016-03-09 22:51:02 +00006189 rect.offset(descendant.mScrollX - descendant.mLeft,
6190 descendant.mScrollY - descendant.mTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006191 }
6192 } else {
6193 throw new IllegalArgumentException("parameter must be a descendant of this view");
6194 }
6195 }
6196
6197 /**
6198 * Offset the vertical location of all children of this view by the specified number of pixels.
6199 *
6200 * @param offset the number of pixels to offset
6201 *
6202 * @hide
6203 */
Mathew Inwooda570dee2018-08-17 14:56:00 +01006204 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006205 public void offsetChildrenTopAndBottom(int offset) {
6206 final int count = mChildrenCount;
6207 final View[] children = mChildren;
Romain Guy5549cb52013-05-06 18:42:08 -07006208 boolean invalidate = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006209
6210 for (int i = 0; i < count; i++) {
6211 final View v = children[i];
6212 v.mTop += offset;
6213 v.mBottom += offset;
Chris Craik64a12e12014-03-28 18:12:12 -07006214 if (v.mRenderNode != null) {
Romain Guy5549cb52013-05-06 18:42:08 -07006215 invalidate = true;
Chris Craik64a12e12014-03-28 18:12:12 -07006216 v.mRenderNode.offsetTopAndBottom(offset);
Chet Haasea1cff502012-02-21 13:43:44 -08006217 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006218 }
Romain Guy5549cb52013-05-06 18:42:08 -07006219
6220 if (invalidate) {
6221 invalidateViewProperty(false, false);
6222 }
Eugene Susla72c510f2018-01-23 21:12:11 +00006223 notifySubtreeAccessibilityStateChangedIfNeeded();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006224 }
6225
Alan Viverettebe463f22016-01-21 10:50:10 -05006226 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006227 public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) {
Abodunrinwa Toki4e7a1202016-05-03 18:23:12 +01006228 return getChildVisibleRect(child, r, offset, false);
6229 }
6230
6231 /**
Abodunrinwa Tokicb664062016-05-13 19:26:03 +01006232 * @param forceParentCheck true to guarantee that this call will propagate to all ancestors,
6233 * false otherwise
6234 *
Abodunrinwa Toki4e7a1202016-05-03 18:23:12 +01006235 * @hide
6236 */
6237 public boolean getChildVisibleRect(
6238 View child, Rect r, android.graphics.Point offset, boolean forceParentCheck) {
Adam Powellf93bb6d2011-12-12 15:21:57 -08006239 // It doesn't make a whole lot of sense to call this on a view that isn't attached,
6240 // but for some simple tests it can be useful. If we don't have attach info this
6241 // will allocate memory.
6242 final RectF rect = mAttachInfo != null ? mAttachInfo.mTmpTransformRect : new RectF();
Gilles Debunnecea45132011-11-24 02:19:27 +01006243 rect.set(r);
6244
6245 if (!child.hasIdentityMatrix()) {
George Mount002d43d2014-11-11 12:54:43 -08006246 child.getMatrix().mapRect(rect);
Gilles Debunnecea45132011-11-24 02:19:27 +01006247 }
6248
Alan Viveretteab2cf6d2014-11-26 14:34:36 -08006249 final int dx = child.mLeft - mScrollX;
6250 final int dy = child.mTop - mScrollY;
Gilles Debunnecea45132011-11-24 02:19:27 +01006251
6252 rect.offset(dx, dy);
6253
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006254 if (offset != null) {
Gilles Debunnecea45132011-11-24 02:19:27 +01006255 if (!child.hasIdentityMatrix()) {
Adam Powellf93bb6d2011-12-12 15:21:57 -08006256 float[] position = mAttachInfo != null ? mAttachInfo.mTmpTransformLocation
6257 : new float[2];
Gilles Debunnecea45132011-11-24 02:19:27 +01006258 position[0] = offset.x;
6259 position[1] = offset.y;
6260 child.getMatrix().mapPoints(position);
Alan Viverettec45b1d42015-11-16 15:38:59 -05006261 offset.x = Math.round(position[0]);
6262 offset.y = Math.round(position[1]);
Gilles Debunnecea45132011-11-24 02:19:27 +01006263 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006264 offset.x += dx;
6265 offset.y += dy;
6266 }
Gilles Debunnecea45132011-11-24 02:19:27 +01006267
Alan Viveretteab2cf6d2014-11-26 14:34:36 -08006268 final int width = mRight - mLeft;
6269 final int height = mBottom - mTop;
6270
George Mount002d43d2014-11-11 12:54:43 -08006271 boolean rectIsVisible = true;
Adam Powell35da41e2014-12-10 18:59:34 -08006272 if (mParent == null ||
6273 (mParent instanceof ViewGroup && ((ViewGroup) mParent).getClipChildren())) {
Alan Viveretteab2cf6d2014-11-26 14:34:36 -08006274 // Clip to bounds.
6275 rectIsVisible = rect.intersect(0, 0, width, height);
Gilles Debunnecea45132011-11-24 02:19:27 +01006276 }
6277
Abodunrinwa Toki4e7a1202016-05-03 18:23:12 +01006278 if ((forceParentCheck || rectIsVisible)
6279 && (mGroupFlags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK) {
Alan Viveretteab2cf6d2014-11-26 14:34:36 -08006280 // Clip to padding.
George Mount002d43d2014-11-11 12:54:43 -08006281 rectIsVisible = rect.intersect(mPaddingLeft, mPaddingTop,
Alan Viveretteab2cf6d2014-11-26 14:34:36 -08006282 width - mPaddingRight, height - mPaddingBottom);
George Mount002d43d2014-11-11 12:54:43 -08006283 }
6284
Abodunrinwa Toki4e7a1202016-05-03 18:23:12 +01006285 if ((forceParentCheck || rectIsVisible) && mClipBounds != null) {
Alan Viveretteab2cf6d2014-11-26 14:34:36 -08006286 // Clip to clipBounds.
George Mount002d43d2014-11-11 12:54:43 -08006287 rectIsVisible = rect.intersect(mClipBounds.left, mClipBounds.top, mClipBounds.right,
6288 mClipBounds.bottom);
6289 }
Alan Viverettec45b1d42015-11-16 15:38:59 -05006290 r.set((int) Math.floor(rect.left), (int) Math.floor(rect.top),
6291 (int) Math.ceil(rect.right), (int) Math.ceil(rect.bottom));
Abodunrinwa Toki4e7a1202016-05-03 18:23:12 +01006292
6293 if ((forceParentCheck || rectIsVisible) && mParent != null) {
Abodunrinwa Tokicb664062016-05-13 19:26:03 +01006294 if (mParent instanceof ViewGroup) {
6295 rectIsVisible = ((ViewGroup) mParent)
6296 .getChildVisibleRect(this, r, offset, forceParentCheck);
6297 } else {
6298 rectIsVisible = mParent.getChildVisibleRect(this, r, offset);
6299 }
George Mount002d43d2014-11-11 12:54:43 -08006300 }
6301 return rectIsVisible;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006302 }
6303
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006304 @Override
Chet Haase9c087442011-01-12 16:20:16 -08006305 public final void layout(int l, int t, int r, int b) {
Chet Haase430742f2013-04-12 11:18:36 -07006306 if (!mSuppressLayout && (mTransition == null || !mTransition.isChangingLayout())) {
Chet Haase7dd4a532012-04-16 13:35:09 -07006307 if (mTransition != null) {
6308 mTransition.layoutChange(this);
6309 }
Chet Haase9c087442011-01-12 16:20:16 -08006310 super.layout(l, t, r, b);
6311 } else {
6312 // record the fact that we noop'd it; request layout when transition finishes
Chet Haaseb9895022013-04-02 15:10:58 -07006313 mLayoutCalledWhileSuppressed = true;
Chet Haase9c087442011-01-12 16:20:16 -08006314 }
6315 }
6316
Chet Haase9c087442011-01-12 16:20:16 -08006317 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006318 protected abstract void onLayout(boolean changed,
6319 int l, int t, int r, int b);
6320
6321 /**
6322 * Indicates whether the view group has the ability to animate its children
6323 * after the first layout.
6324 *
6325 * @return true if the children can be animated, false otherwise
6326 */
6327 protected boolean canAnimate() {
6328 return mLayoutAnimationController != null;
6329 }
6330
6331 /**
6332 * Runs the layout animation. Calling this method triggers a relayout of
6333 * this view group.
6334 */
6335 public void startLayoutAnimation() {
6336 if (mLayoutAnimationController != null) {
6337 mGroupFlags |= FLAG_RUN_ANIMATION;
6338 requestLayout();
6339 }
6340 }
6341
6342 /**
6343 * Schedules the layout animation to be played after the next layout pass
6344 * of this view group. This can be used to restart the layout animation
6345 * when the content of the view group changes or when the activity is
6346 * paused and resumed.
6347 */
6348 public void scheduleLayoutAnimation() {
6349 mGroupFlags |= FLAG_RUN_ANIMATION;
6350 }
6351
6352 /**
6353 * Sets the layout animation controller used to animate the group's
6354 * children after the first layout.
6355 *
6356 * @param controller the animation controller
6357 */
6358 public void setLayoutAnimation(LayoutAnimationController controller) {
6359 mLayoutAnimationController = controller;
6360 if (mLayoutAnimationController != null) {
6361 mGroupFlags |= FLAG_RUN_ANIMATION;
6362 }
6363 }
6364
6365 /**
6366 * Returns the layout animation controller used to animate the group's
6367 * children.
6368 *
6369 * @return the current animation controller
6370 */
Ashley Rose55f9f922019-01-28 19:29:36 -05006371 @InspectableProperty
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006372 public LayoutAnimationController getLayoutAnimation() {
6373 return mLayoutAnimationController;
6374 }
6375
6376 /**
6377 * Indicates whether the children's drawing cache is used during a layout
6378 * animation. By default, the drawing cache is enabled but this will prevent
6379 * nested layout animations from working. To nest animations, you must disable
6380 * the cache.
6381 *
6382 * @return true if the animation cache is enabled, false otherwise
6383 *
6384 * @see #setAnimationCacheEnabled(boolean)
6385 * @see View#setDrawingCacheEnabled(boolean)
Chris Craik5a6bbae2015-04-10 17:41:34 -07006386 *
Dianne Hackborn0e3de6c2015-07-29 15:20:21 -07006387 * @deprecated As of {@link android.os.Build.VERSION_CODES#M}, this property is ignored.
Chris Craik5a6bbae2015-04-10 17:41:34 -07006388 * Caching behavior of children may be controlled through {@link View#setLayerType(int, Paint)}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006389 */
Aurimas Liutikas514c5ef2016-05-24 15:22:55 -07006390 @Deprecated
Ashley Rose55f9f922019-01-28 19:29:36 -05006391 @InspectableProperty(name = "animationCache")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006392 public boolean isAnimationCacheEnabled() {
6393 return (mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE;
6394 }
6395
6396 /**
6397 * Enables or disables the children's drawing cache during a layout animation.
6398 * By default, the drawing cache is enabled but this will prevent nested
6399 * layout animations from working. To nest animations, you must disable the
6400 * cache.
6401 *
6402 * @param enabled true to enable the animation cache, false otherwise
6403 *
6404 * @see #isAnimationCacheEnabled()
6405 * @see View#setDrawingCacheEnabled(boolean)
Chris Craik5a6bbae2015-04-10 17:41:34 -07006406 *
Dianne Hackborn0e3de6c2015-07-29 15:20:21 -07006407 * @deprecated As of {@link android.os.Build.VERSION_CODES#M}, this property is ignored.
Chris Craik5a6bbae2015-04-10 17:41:34 -07006408 * Caching behavior of children may be controlled through {@link View#setLayerType(int, Paint)}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006409 */
Aurimas Liutikas514c5ef2016-05-24 15:22:55 -07006410 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006411 public void setAnimationCacheEnabled(boolean enabled) {
6412 setBooleanFlag(FLAG_ANIMATION_CACHE, enabled);
6413 }
6414
6415 /**
6416 * Indicates whether this ViewGroup will always try to draw its children using their
6417 * drawing cache. By default this property is enabled.
6418 *
6419 * @return true if the animation cache is enabled, false otherwise
6420 *
6421 * @see #setAlwaysDrawnWithCacheEnabled(boolean)
6422 * @see #setChildrenDrawnWithCacheEnabled(boolean)
6423 * @see View#setDrawingCacheEnabled(boolean)
Chris Craik5a6bbae2015-04-10 17:41:34 -07006424 *
Dianne Hackborn0e3de6c2015-07-29 15:20:21 -07006425 * @deprecated As of {@link android.os.Build.VERSION_CODES#M}, this property is ignored.
Chris Craik5a6bbae2015-04-10 17:41:34 -07006426 * Child views may no longer have their caching behavior disabled by parents.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006427 */
Aurimas Liutikas514c5ef2016-05-24 15:22:55 -07006428 @Deprecated
Ashley Rose55f9f922019-01-28 19:29:36 -05006429 @InspectableProperty(name = "alwaysDrawnWithCache")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006430 public boolean isAlwaysDrawnWithCacheEnabled() {
6431 return (mGroupFlags & FLAG_ALWAYS_DRAWN_WITH_CACHE) == FLAG_ALWAYS_DRAWN_WITH_CACHE;
6432 }
6433
6434 /**
6435 * Indicates whether this ViewGroup will always try to draw its children using their
6436 * drawing cache. This property can be set to true when the cache rendering is
6437 * slightly different from the children's normal rendering. Renderings can be different,
6438 * for instance, when the cache's quality is set to low.
6439 *
6440 * When this property is disabled, the ViewGroup will use the drawing cache of its
6441 * children only when asked to. It's usually the task of subclasses to tell ViewGroup
6442 * when to start using the drawing cache and when to stop using it.
6443 *
6444 * @param always true to always draw with the drawing cache, false otherwise
6445 *
6446 * @see #isAlwaysDrawnWithCacheEnabled()
6447 * @see #setChildrenDrawnWithCacheEnabled(boolean)
6448 * @see View#setDrawingCacheEnabled(boolean)
6449 * @see View#setDrawingCacheQuality(int)
Chris Craik5a6bbae2015-04-10 17:41:34 -07006450 *
Dianne Hackborn0e3de6c2015-07-29 15:20:21 -07006451 * @deprecated As of {@link android.os.Build.VERSION_CODES#M}, this property is ignored.
Chris Craik5a6bbae2015-04-10 17:41:34 -07006452 * Child views may no longer have their caching behavior disabled by parents.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006453 */
Aurimas Liutikas514c5ef2016-05-24 15:22:55 -07006454 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006455 public void setAlwaysDrawnWithCacheEnabled(boolean always) {
6456 setBooleanFlag(FLAG_ALWAYS_DRAWN_WITH_CACHE, always);
6457 }
6458
6459 /**
6460 * Indicates whether the ViewGroup is currently drawing its children using
6461 * their drawing cache.
6462 *
6463 * @return true if children should be drawn with their cache, false otherwise
6464 *
6465 * @see #setAlwaysDrawnWithCacheEnabled(boolean)
6466 * @see #setChildrenDrawnWithCacheEnabled(boolean)
Chris Craik5a6bbae2015-04-10 17:41:34 -07006467 *
Dianne Hackborn0e3de6c2015-07-29 15:20:21 -07006468 * @deprecated As of {@link android.os.Build.VERSION_CODES#M}, this property is ignored.
Chris Craik5a6bbae2015-04-10 17:41:34 -07006469 * Child views may no longer be forced to cache their rendering state by their parents.
6470 * Use {@link View#setLayerType(int, Paint)} on individual Views instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006471 */
Aurimas Liutikas514c5ef2016-05-24 15:22:55 -07006472 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006473 protected boolean isChildrenDrawnWithCacheEnabled() {
6474 return (mGroupFlags & FLAG_CHILDREN_DRAWN_WITH_CACHE) == FLAG_CHILDREN_DRAWN_WITH_CACHE;
6475 }
6476
6477 /**
6478 * Tells the ViewGroup to draw its children using their drawing cache. This property
6479 * is ignored when {@link #isAlwaysDrawnWithCacheEnabled()} is true. A child's drawing cache
6480 * will be used only if it has been enabled.
6481 *
6482 * Subclasses should call this method to start and stop using the drawing cache when
6483 * they perform performance sensitive operations, like scrolling or animating.
6484 *
6485 * @param enabled true if children should be drawn with their cache, false otherwise
6486 *
6487 * @see #setAlwaysDrawnWithCacheEnabled(boolean)
6488 * @see #isChildrenDrawnWithCacheEnabled()
Chris Craik5a6bbae2015-04-10 17:41:34 -07006489 *
Dianne Hackborn0e3de6c2015-07-29 15:20:21 -07006490 * @deprecated As of {@link android.os.Build.VERSION_CODES#M}, this property is ignored.
Chris Craik5a6bbae2015-04-10 17:41:34 -07006491 * Child views may no longer be forced to cache their rendering state by their parents.
6492 * Use {@link View#setLayerType(int, Paint)} on individual Views instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006493 */
Aurimas Liutikas514c5ef2016-05-24 15:22:55 -07006494 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006495 protected void setChildrenDrawnWithCacheEnabled(boolean enabled) {
6496 setBooleanFlag(FLAG_CHILDREN_DRAWN_WITH_CACHE, enabled);
6497 }
6498
Romain Guy293451e2009-11-04 13:59:48 -08006499 /**
6500 * Indicates whether the ViewGroup is drawing its children in the order defined by
6501 * {@link #getChildDrawingOrder(int, int)}.
6502 *
6503 * @return true if children drawing order is defined by {@link #getChildDrawingOrder(int, int)},
6504 * false otherwise
6505 *
6506 * @see #setChildrenDrawingOrderEnabled(boolean)
6507 * @see #getChildDrawingOrder(int, int)
6508 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07006509 @ViewDebug.ExportedProperty(category = "drawing")
Romain Guy293451e2009-11-04 13:59:48 -08006510 protected boolean isChildrenDrawingOrderEnabled() {
6511 return (mGroupFlags & FLAG_USE_CHILD_DRAWING_ORDER) == FLAG_USE_CHILD_DRAWING_ORDER;
6512 }
6513
6514 /**
6515 * Tells the ViewGroup whether to draw its children in the order defined by the method
6516 * {@link #getChildDrawingOrder(int, int)}.
Chris Craike83cbd42014-09-03 17:52:24 -07006517 * <p>
6518 * Note that {@link View#getZ() Z} reordering, done by {@link #dispatchDraw(Canvas)},
6519 * will override custom child ordering done via this method.
Romain Guy293451e2009-11-04 13:59:48 -08006520 *
6521 * @param enabled true if the order of the children when drawing is determined by
6522 * {@link #getChildDrawingOrder(int, int)}, false otherwise
6523 *
6524 * @see #isChildrenDrawingOrderEnabled()
6525 * @see #getChildDrawingOrder(int, int)
6526 */
6527 protected void setChildrenDrawingOrderEnabled(boolean enabled) {
6528 setBooleanFlag(FLAG_USE_CHILD_DRAWING_ORDER, enabled);
6529 }
6530
Svetoslav6254f482013-06-04 17:22:14 -07006531 private boolean hasBooleanFlag(int flag) {
Philip Milnef091b662013-02-27 11:15:21 -08006532 return (mGroupFlags & flag) == flag;
6533 }
6534
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006535 private void setBooleanFlag(int flag, boolean value) {
6536 if (value) {
6537 mGroupFlags |= flag;
6538 } else {
6539 mGroupFlags &= ~flag;
6540 }
6541 }
6542
6543 /**
6544 * Returns an integer indicating what types of drawing caches are kept in memory.
6545 *
6546 * @see #setPersistentDrawingCache(int)
6547 * @see #setAnimationCacheEnabled(boolean)
6548 *
6549 * @return one or a combination of {@link #PERSISTENT_NO_CACHE},
6550 * {@link #PERSISTENT_ANIMATION_CACHE}, {@link #PERSISTENT_SCROLLING_CACHE}
6551 * and {@link #PERSISTENT_ALL_CACHES}
John Reck949cfe12017-10-09 13:27:03 -07006552 *
6553 * @deprecated The view drawing cache was largely made obsolete with the introduction of
6554 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache
6555 * layers are largely unnecessary and can easily result in a net loss in performance due to the
6556 * cost of creating and updating the layer. In the rare cases where caching layers are useful,
6557 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware
6558 * rendering. For software-rendered snapshots of a small part of the View hierarchy or
6559 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or
6560 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these
6561 * software-rendered usages are discouraged and have compatibility issues with hardware-only
6562 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE}
6563 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback
6564 * reports or unit testing the {@link PixelCopy} API is recommended.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006565 */
John Reck949cfe12017-10-09 13:27:03 -07006566 @Deprecated
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07006567 @ViewDebug.ExportedProperty(category = "drawing", mapping = {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006568 @ViewDebug.IntToString(from = PERSISTENT_NO_CACHE, to = "NONE"),
Romain Guy203688c2010-05-12 15:41:32 -07006569 @ViewDebug.IntToString(from = PERSISTENT_ANIMATION_CACHE, to = "ANIMATION"),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006570 @ViewDebug.IntToString(from = PERSISTENT_SCROLLING_CACHE, to = "SCROLLING"),
6571 @ViewDebug.IntToString(from = PERSISTENT_ALL_CACHES, to = "ALL")
6572 })
Ashley Rose55f9f922019-01-28 19:29:36 -05006573 @InspectableProperty(enumMapping = {
6574 @EnumMap(value = PERSISTENT_NO_CACHE, name = "none"),
6575 @EnumMap(value = PERSISTENT_ANIMATION_CACHE, name = "animation"),
6576 @EnumMap(value = PERSISTENT_SCROLLING_CACHE, name = "scrolling"),
6577 @EnumMap(value = PERSISTENT_ALL_CACHES, name = "all"),
6578 })
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006579 public int getPersistentDrawingCache() {
6580 return mPersistentDrawingCache;
6581 }
6582
6583 /**
6584 * Indicates what types of drawing caches should be kept in memory after
6585 * they have been created.
6586 *
6587 * @see #getPersistentDrawingCache()
6588 * @see #setAnimationCacheEnabled(boolean)
6589 *
6590 * @param drawingCacheToKeep one or a combination of {@link #PERSISTENT_NO_CACHE},
6591 * {@link #PERSISTENT_ANIMATION_CACHE}, {@link #PERSISTENT_SCROLLING_CACHE}
6592 * and {@link #PERSISTENT_ALL_CACHES}
John Reck949cfe12017-10-09 13:27:03 -07006593 *
6594 * @deprecated The view drawing cache was largely made obsolete with the introduction of
6595 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache
6596 * layers are largely unnecessary and can easily result in a net loss in performance due to the
6597 * cost of creating and updating the layer. In the rare cases where caching layers are useful,
6598 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware
6599 * rendering. For software-rendered snapshots of a small part of the View hierarchy or
6600 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or
6601 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these
6602 * software-rendered usages are discouraged and have compatibility issues with hardware-only
6603 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE}
6604 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback
6605 * reports or unit testing the {@link PixelCopy} API is recommended.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006606 */
John Reck949cfe12017-10-09 13:27:03 -07006607 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006608 public void setPersistentDrawingCache(int drawingCacheToKeep) {
6609 mPersistentDrawingCache = drawingCacheToKeep & PERSISTENT_ALL_CACHES;
6610 }
6611
Philip Milnef091b662013-02-27 11:15:21 -08006612 private void setLayoutMode(int layoutMode, boolean explicitly) {
6613 mLayoutMode = layoutMode;
6614 setBooleanFlag(FLAG_LAYOUT_MODE_WAS_EXPLICITLY_SET, explicitly);
6615 }
6616
6617 /**
6618 * Recursively traverse the view hierarchy, resetting the layoutMode of any
6619 * descendants that had inherited a different layoutMode from a previous parent.
6620 * Recursion terminates when a descendant's mode is:
6621 * <ul>
6622 * <li>Undefined</li>
6623 * <li>The same as the root node's</li>
6624 * <li>A mode that had been explicitly set</li>
6625 * <ul/>
6626 * The first two clauses are optimizations.
6627 * @param layoutModeOfRoot
6628 */
6629 @Override
6630 void invalidateInheritedLayoutMode(int layoutModeOfRoot) {
6631 if (mLayoutMode == LAYOUT_MODE_UNDEFINED ||
6632 mLayoutMode == layoutModeOfRoot ||
Svetoslav6254f482013-06-04 17:22:14 -07006633 hasBooleanFlag(FLAG_LAYOUT_MODE_WAS_EXPLICITLY_SET)) {
Philip Milnef091b662013-02-27 11:15:21 -08006634 return;
6635 }
6636 setLayoutMode(LAYOUT_MODE_UNDEFINED, false);
6637
6638 // apply recursively
6639 for (int i = 0, N = getChildCount(); i < N; i++) {
6640 getChildAt(i).invalidateInheritedLayoutMode(layoutModeOfRoot);
6641 }
6642 }
6643
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006644 /**
Philip Milnecfb631b2012-10-26 10:51:46 -07006645 * Returns the basis of alignment during layout operations on this ViewGroup:
Philip Milne7b757812012-09-19 18:13:44 -07006646 * either {@link #LAYOUT_MODE_CLIP_BOUNDS} or {@link #LAYOUT_MODE_OPTICAL_BOUNDS}.
Philip Milnecfb631b2012-10-26 10:51:46 -07006647 * <p>
6648 * If no layoutMode was explicitly set, either programmatically or in an XML resource,
6649 * the method returns the layoutMode of the view's parent ViewGroup if such a parent exists,
6650 * otherwise the method returns a default value of {@link #LAYOUT_MODE_CLIP_BOUNDS}.
Philip Milne1557fd72012-04-04 23:41:34 -07006651 *
Philip Milnefcc6a0f2012-04-16 16:12:19 -07006652 * @return the layout mode to use during layout operations
Philip Milne1557fd72012-04-04 23:41:34 -07006653 *
6654 * @see #setLayoutMode(int)
6655 */
Ashley Rose55f9f922019-01-28 19:29:36 -05006656 @InspectableProperty(enumMapping = {
6657 @EnumMap(value = LAYOUT_MODE_CLIP_BOUNDS, name = "clipBounds"),
6658 @EnumMap(value = LAYOUT_MODE_OPTICAL_BOUNDS, name = "opticalBounds")
6659 })
Philip Milne1557fd72012-04-04 23:41:34 -07006660 public int getLayoutMode() {
Philip Milnecfb631b2012-10-26 10:51:46 -07006661 if (mLayoutMode == LAYOUT_MODE_UNDEFINED) {
Philip Milnef091b662013-02-27 11:15:21 -08006662 int inheritedLayoutMode = (mParent instanceof ViewGroup) ?
6663 ((ViewGroup) mParent).getLayoutMode() : LAYOUT_MODE_DEFAULT;
6664 setLayoutMode(inheritedLayoutMode, false);
Philip Milnecfb631b2012-10-26 10:51:46 -07006665 }
Philip Milne1557fd72012-04-04 23:41:34 -07006666 return mLayoutMode;
6667 }
6668
6669 /**
Philip Milnecfb631b2012-10-26 10:51:46 -07006670 * Sets the basis of alignment during the layout of this ViewGroup.
Philip Milne7b757812012-09-19 18:13:44 -07006671 * Valid values are either {@link #LAYOUT_MODE_CLIP_BOUNDS} or
6672 * {@link #LAYOUT_MODE_OPTICAL_BOUNDS}.
Philip Milne1557fd72012-04-04 23:41:34 -07006673 *
Philip Milnefcc6a0f2012-04-16 16:12:19 -07006674 * @param layoutMode the layout mode to use during layout operations
Philip Milne1557fd72012-04-04 23:41:34 -07006675 *
6676 * @see #getLayoutMode()
Scott Main27a85082013-06-10 10:39:48 -07006677 * @attr ref android.R.styleable#ViewGroup_layoutMode
Philip Milne1557fd72012-04-04 23:41:34 -07006678 */
6679 public void setLayoutMode(int layoutMode) {
6680 if (mLayoutMode != layoutMode) {
Philip Milnef091b662013-02-27 11:15:21 -08006681 invalidateInheritedLayoutMode(layoutMode);
6682 setLayoutMode(layoutMode, layoutMode != LAYOUT_MODE_UNDEFINED);
Philip Milne1557fd72012-04-04 23:41:34 -07006683 requestLayout();
6684 }
6685 }
6686
6687 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006688 * Returns a new set of layout parameters based on the supplied attributes set.
6689 *
6690 * @param attrs the attributes to build the layout parameters from
6691 *
6692 * @return an instance of {@link android.view.ViewGroup.LayoutParams} or one
6693 * of its descendants
6694 */
6695 public LayoutParams generateLayoutParams(AttributeSet attrs) {
6696 return new LayoutParams(getContext(), attrs);
6697 }
6698
6699 /**
6700 * Returns a safe set of layout parameters based on the supplied layout params.
6701 * When a ViewGroup is passed a View whose layout params do not pass the test of
6702 * {@link #checkLayoutParams(android.view.ViewGroup.LayoutParams)}, this method
6703 * is invoked. This method should return a new set of layout params suitable for
6704 * this ViewGroup, possibly by copying the appropriate attributes from the
6705 * specified set of layout params.
6706 *
6707 * @param p The layout parameters to convert into a suitable set of layout parameters
6708 * for this ViewGroup.
6709 *
6710 * @return an instance of {@link android.view.ViewGroup.LayoutParams} or one
6711 * of its descendants
6712 */
6713 protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
Chet Haase4610eef2015-12-03 07:38:11 -08006714 return p;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006715 }
6716
6717 /**
6718 * Returns a set of default layout parameters. These parameters are requested
6719 * when the View passed to {@link #addView(View)} has no layout parameters
6720 * already set. If null is returned, an exception is thrown from addView.
6721 *
6722 * @return a set of default layout parameters or null
6723 */
6724 protected LayoutParams generateDefaultLayoutParams() {
6725 return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
6726 }
6727
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006728 @Override
6729 protected void debug(int depth) {
6730 super.debug(depth);
6731 String output;
6732
6733 if (mFocused != null) {
6734 output = debugIndent(depth);
6735 output += "mFocused";
6736 Log.d(VIEW_LOG_TAG, output);
Vadim Tryshev01d8c492016-12-15 11:33:15 -08006737 mFocused.debug(depth + 1);
6738 }
Vadim Tryshev5ca73982017-01-04 17:24:43 -08006739 if (mDefaultFocus != null) {
Vadim Tryshev01d8c492016-12-15 11:33:15 -08006740 output = debugIndent(depth);
Vadim Tryshev5ca73982017-01-04 17:24:43 -08006741 output += "mDefaultFocus";
Vadim Tryshev01d8c492016-12-15 11:33:15 -08006742 Log.d(VIEW_LOG_TAG, output);
Vadim Tryshev5ca73982017-01-04 17:24:43 -08006743 mDefaultFocus.debug(depth + 1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006744 }
Evan Rosky53fcf112017-01-26 14:37:55 -08006745 if (mFocusedInCluster != null) {
6746 output = debugIndent(depth);
6747 output += "mFocusedInCluster";
6748 Log.d(VIEW_LOG_TAG, output);
6749 mFocusedInCluster.debug(depth + 1);
6750 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006751 if (mChildrenCount != 0) {
6752 output = debugIndent(depth);
6753 output += "{";
6754 Log.d(VIEW_LOG_TAG, output);
6755 }
6756 int count = mChildrenCount;
6757 for (int i = 0; i < count; i++) {
6758 View child = mChildren[i];
6759 child.debug(depth + 1);
6760 }
6761
6762 if (mChildrenCount != 0) {
6763 output = debugIndent(depth);
6764 output += "}";
6765 Log.d(VIEW_LOG_TAG, output);
6766 }
6767 }
6768
6769 /**
6770 * Returns the position in the group of the specified child view.
6771 *
6772 * @param child the view for which to get the position
6773 * @return a positive integer representing the position of the view in the
6774 * group, or -1 if the view does not exist in the group
6775 */
6776 public int indexOfChild(View child) {
6777 final int count = mChildrenCount;
6778 final View[] children = mChildren;
6779 for (int i = 0; i < count; i++) {
6780 if (children[i] == child) {
6781 return i;
6782 }
6783 }
6784 return -1;
6785 }
6786
6787 /**
6788 * Returns the number of children in the group.
6789 *
6790 * @return a positive integer representing the number of children in
6791 * the group
6792 */
6793 public int getChildCount() {
6794 return mChildrenCount;
6795 }
6796
6797 /**
6798 * Returns the view at the specified position in the group.
6799 *
6800 * @param index the position at which to get the view from
6801 * @return the view at the specified position or null if the position
6802 * does not exist within the group
6803 */
6804 public View getChildAt(int index) {
Adam Powell3ba8f5d62011-03-07 15:36:33 -08006805 if (index < 0 || index >= mChildrenCount) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006806 return null;
6807 }
Adam Powell3ba8f5d62011-03-07 15:36:33 -08006808 return mChildren[index];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006809 }
6810
6811 /**
6812 * Ask all of the children of this view to measure themselves, taking into
6813 * account both the MeasureSpec requirements for this view and its padding.
6814 * We skip children that are in the GONE state The heavy lifting is done in
6815 * getChildMeasureSpec.
6816 *
6817 * @param widthMeasureSpec The width requirements for this view
6818 * @param heightMeasureSpec The height requirements for this view
6819 */
6820 protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec) {
6821 final int size = mChildrenCount;
6822 final View[] children = mChildren;
6823 for (int i = 0; i < size; ++i) {
6824 final View child = children[i];
6825 if ((child.mViewFlags & VISIBILITY_MASK) != GONE) {
6826 measureChild(child, widthMeasureSpec, heightMeasureSpec);
6827 }
6828 }
6829 }
6830
6831 /**
6832 * Ask one of the children of this view to measure itself, taking into
6833 * account both the MeasureSpec requirements for this view and its padding.
6834 * The heavy lifting is done in getChildMeasureSpec.
6835 *
6836 * @param child The child to measure
6837 * @param parentWidthMeasureSpec The width requirements for this view
6838 * @param parentHeightMeasureSpec The height requirements for this view
6839 */
6840 protected void measureChild(View child, int parentWidthMeasureSpec,
6841 int parentHeightMeasureSpec) {
6842 final LayoutParams lp = child.getLayoutParams();
6843
6844 final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
6845 mPaddingLeft + mPaddingRight, lp.width);
6846 final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
6847 mPaddingTop + mPaddingBottom, lp.height);
6848
6849 child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
6850 }
6851
6852 /**
6853 * Ask one of the children of this view to measure itself, taking into
6854 * account both the MeasureSpec requirements for this view and its padding
6855 * and margins. The child must have MarginLayoutParams The heavy lifting is
6856 * done in getChildMeasureSpec.
6857 *
6858 * @param child The child to measure
6859 * @param parentWidthMeasureSpec The width requirements for this view
6860 * @param widthUsed Extra space that has been used up by the parent
6861 * horizontally (possibly by other children of the parent)
6862 * @param parentHeightMeasureSpec The height requirements for this view
6863 * @param heightUsed Extra space that has been used up by the parent
6864 * vertically (possibly by other children of the parent)
6865 */
6866 protected void measureChildWithMargins(View child,
6867 int parentWidthMeasureSpec, int widthUsed,
6868 int parentHeightMeasureSpec, int heightUsed) {
6869 final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
6870
6871 final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
6872 mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin
6873 + widthUsed, lp.width);
6874 final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
6875 mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin
6876 + heightUsed, lp.height);
6877
6878 child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
6879 }
6880
6881 /**
6882 * Does the hard part of measureChildren: figuring out the MeasureSpec to
6883 * pass to a particular child. This method figures out the right MeasureSpec
6884 * for one dimension (height or width) of one child view.
6885 *
6886 * The goal is to combine information from our MeasureSpec with the
6887 * LayoutParams of the child to get the best possible results. For example,
6888 * if the this view knows its size (because its MeasureSpec has a mode of
6889 * EXACTLY), and the child has indicated in its LayoutParams that it wants
6890 * to be the same size as the parent, the parent should ask the child to
6891 * layout given an exact size.
6892 *
6893 * @param spec The requirements for this view
6894 * @param padding The padding of this view for the current dimension and
6895 * margins, if applicable
6896 * @param childDimension How big the child wants to be in the current
6897 * dimension
6898 * @return a MeasureSpec integer for the child
6899 */
6900 public static int getChildMeasureSpec(int spec, int padding, int childDimension) {
6901 int specMode = MeasureSpec.getMode(spec);
6902 int specSize = MeasureSpec.getSize(spec);
6903
6904 int size = Math.max(0, specSize - padding);
6905
6906 int resultSize = 0;
6907 int resultMode = 0;
6908
6909 switch (specMode) {
6910 // Parent has imposed an exact size on us
6911 case MeasureSpec.EXACTLY:
6912 if (childDimension >= 0) {
6913 resultSize = childDimension;
6914 resultMode = MeasureSpec.EXACTLY;
Romain Guy980a9382010-01-08 15:06:28 -08006915 } else if (childDimension == LayoutParams.MATCH_PARENT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006916 // Child wants to be our size. So be it.
6917 resultSize = size;
6918 resultMode = MeasureSpec.EXACTLY;
6919 } else if (childDimension == LayoutParams.WRAP_CONTENT) {
6920 // Child wants to determine its own size. It can't be
6921 // bigger than us.
6922 resultSize = size;
6923 resultMode = MeasureSpec.AT_MOST;
6924 }
6925 break;
6926
6927 // Parent has imposed a maximum size on us
6928 case MeasureSpec.AT_MOST:
6929 if (childDimension >= 0) {
6930 // Child wants a specific size... so be it
6931 resultSize = childDimension;
6932 resultMode = MeasureSpec.EXACTLY;
Romain Guy980a9382010-01-08 15:06:28 -08006933 } else if (childDimension == LayoutParams.MATCH_PARENT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006934 // Child wants to be our size, but our size is not fixed.
6935 // Constrain child to not be bigger than us.
6936 resultSize = size;
6937 resultMode = MeasureSpec.AT_MOST;
6938 } else if (childDimension == LayoutParams.WRAP_CONTENT) {
6939 // Child wants to determine its own size. It can't be
6940 // bigger than us.
6941 resultSize = size;
6942 resultMode = MeasureSpec.AT_MOST;
6943 }
6944 break;
6945
6946 // Parent asked to see how big we want to be
6947 case MeasureSpec.UNSPECIFIED:
6948 if (childDimension >= 0) {
6949 // Child wants a specific size... let him have it
6950 resultSize = childDimension;
6951 resultMode = MeasureSpec.EXACTLY;
Romain Guy980a9382010-01-08 15:06:28 -08006952 } else if (childDimension == LayoutParams.MATCH_PARENT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006953 // Child wants to be our size... find out how big it should
6954 // be
Adam Powelld5dbf4b2015-06-11 13:19:24 -07006955 resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006956 resultMode = MeasureSpec.UNSPECIFIED;
6957 } else if (childDimension == LayoutParams.WRAP_CONTENT) {
6958 // Child wants to determine its own size.... find out how
6959 // big it should be
Adam Powelld5dbf4b2015-06-11 13:19:24 -07006960 resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006961 resultMode = MeasureSpec.UNSPECIFIED;
6962 }
6963 break;
6964 }
Tor Norbye67568642015-03-31 07:47:23 -07006965 //noinspection ResourceType
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006966 return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
6967 }
6968
6969
6970 /**
6971 * Removes any pending animations for views that have been removed. Call
6972 * this if you don't want animations for exiting views to stack up.
6973 */
6974 public void clearDisappearingChildren() {
John Reckca7a9da2014-03-05 16:29:07 -08006975 final ArrayList<View> disappearingChildren = mDisappearingChildren;
6976 if (disappearingChildren != null) {
6977 final int count = disappearingChildren.size();
6978 for (int i = 0; i < count; i++) {
6979 final View view = disappearingChildren.get(i);
6980 if (view.mAttachInfo != null) {
6981 view.dispatchDetachedFromWindow();
6982 }
6983 view.clearAnimation();
6984 }
6985 disappearingChildren.clear();
Chet Haaseb85967b2012-03-26 14:37:51 -07006986 invalidate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006987 }
6988 }
6989
6990 /**
6991 * Add a view which is removed from mChildren but still needs animation
6992 *
6993 * @param v View to add
6994 */
6995 private void addDisappearingView(View v) {
6996 ArrayList<View> disappearingChildren = mDisappearingChildren;
6997
6998 if (disappearingChildren == null) {
6999 disappearingChildren = mDisappearingChildren = new ArrayList<View>();
7000 }
7001
7002 disappearingChildren.add(v);
7003 }
7004
7005 /**
7006 * Cleanup a view when its animation is done. This may mean removing it from
7007 * the list of disappearing views.
7008 *
7009 * @param view The view whose animation has finished
7010 * @param animation The animation, cannot be null
7011 */
Chet Haase64a48c12012-02-13 16:33:29 -08007012 void finishAnimatingView(final View view, Animation animation) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007013 final ArrayList<View> disappearingChildren = mDisappearingChildren;
7014 if (disappearingChildren != null) {
7015 if (disappearingChildren.contains(view)) {
7016 disappearingChildren.remove(view);
7017
7018 if (view.mAttachInfo != null) {
7019 view.dispatchDetachedFromWindow();
7020 }
7021
7022 view.clearAnimation();
7023 mGroupFlags |= FLAG_INVALIDATE_REQUIRED;
7024 }
7025 }
7026
7027 if (animation != null && !animation.getFillAfter()) {
7028 view.clearAnimation();
7029 }
7030
Dianne Hackborn4702a852012-08-17 15:18:29 -07007031 if ((view.mPrivateFlags & PFLAG_ANIMATION_STARTED) == PFLAG_ANIMATION_STARTED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007032 view.onAnimationEnd();
7033 // Should be performed by onAnimationEnd() but this avoid an infinite loop,
7034 // so we'd rather be safe than sorry
Dianne Hackborn4702a852012-08-17 15:18:29 -07007035 view.mPrivateFlags &= ~PFLAG_ANIMATION_STARTED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007036 // Draw one more frame after the animation is done
7037 mGroupFlags |= FLAG_INVALIDATE_REQUIRED;
7038 }
7039 }
7040
Chet Haaseb20db3e2010-09-10 13:07:30 -07007041 /**
Chet Haaseaceafe62011-08-26 15:44:33 -07007042 * Utility function called by View during invalidation to determine whether a view that
7043 * is invisible or gone should still be invalidated because it is being transitioned (and
7044 * therefore still needs to be drawn).
7045 */
7046 boolean isViewTransitioning(View view) {
7047 return (mTransitioningViews != null && mTransitioningViews.contains(view));
7048 }
7049
7050 /**
Chet Haaseb20db3e2010-09-10 13:07:30 -07007051 * This method tells the ViewGroup that the given View object, which should have this
7052 * ViewGroup as its parent,
7053 * should be kept around (re-displayed when the ViewGroup draws its children) even if it
7054 * is removed from its parent. This allows animations, such as those used by
7055 * {@link android.app.Fragment} and {@link android.animation.LayoutTransition} to animate
7056 * the removal of views. A call to this method should always be accompanied by a later call
7057 * to {@link #endViewTransition(View)}, such as after an animation on the View has finished,
7058 * so that the View finally gets removed.
7059 *
7060 * @param view The View object to be kept visible even if it gets removed from its parent.
7061 */
7062 public void startViewTransition(View view) {
7063 if (view.mParent == this) {
7064 if (mTransitioningViews == null) {
7065 mTransitioningViews = new ArrayList<View>();
7066 }
7067 mTransitioningViews.add(view);
7068 }
7069 }
7070
7071 /**
7072 * This method should always be called following an earlier call to
7073 * {@link #startViewTransition(View)}. The given View is finally removed from its parent
7074 * and will no longer be displayed. Note that this method does not perform the functionality
7075 * of removing a view from its parent; it just discontinues the display of a View that
7076 * has previously been removed.
7077 *
7078 * @return view The View object that has been removed but is being kept around in the visible
7079 * hierarchy by an earlier call to {@link #startViewTransition(View)}.
7080 */
7081 public void endViewTransition(View view) {
7082 if (mTransitioningViews != null) {
7083 mTransitioningViews.remove(view);
7084 final ArrayList<View> disappearingChildren = mDisappearingChildren;
7085 if (disappearingChildren != null && disappearingChildren.contains(view)) {
7086 disappearingChildren.remove(view);
Chet Haase5e25c2c2010-09-16 11:15:56 -07007087 if (mVisibilityChangingChildren != null &&
7088 mVisibilityChangingChildren.contains(view)) {
7089 mVisibilityChangingChildren.remove(view);
7090 } else {
7091 if (view.mAttachInfo != null) {
7092 view.dispatchDetachedFromWindow();
7093 }
7094 if (view.mParent != null) {
7095 view.mParent = null;
7096 }
Chet Haaseb20db3e2010-09-10 13:07:30 -07007097 }
Chet Haaseb85967b2012-03-26 14:37:51 -07007098 invalidate();
Chet Haaseb20db3e2010-09-10 13:07:30 -07007099 }
7100 }
7101 }
7102
Chet Haase21cd1382010-09-01 17:42:29 -07007103 private LayoutTransition.TransitionListener mLayoutTransitionListener =
7104 new LayoutTransition.TransitionListener() {
7105 @Override
7106 public void startTransition(LayoutTransition transition, ViewGroup container,
7107 View view, int transitionType) {
7108 // We only care about disappearing items, since we need special logic to keep
7109 // those items visible after they've been 'removed'
7110 if (transitionType == LayoutTransition.DISAPPEARING) {
Chet Haaseb20db3e2010-09-10 13:07:30 -07007111 startViewTransition(view);
Chet Haase21cd1382010-09-01 17:42:29 -07007112 }
7113 }
7114
7115 @Override
7116 public void endTransition(LayoutTransition transition, ViewGroup container,
7117 View view, int transitionType) {
Chet Haaseb9895022013-04-02 15:10:58 -07007118 if (mLayoutCalledWhileSuppressed && !transition.isChangingLayout()) {
Chet Haase9c087442011-01-12 16:20:16 -08007119 requestLayout();
Chet Haaseb9895022013-04-02 15:10:58 -07007120 mLayoutCalledWhileSuppressed = false;
Chet Haase9c087442011-01-12 16:20:16 -08007121 }
Chet Haase21cd1382010-09-01 17:42:29 -07007122 if (transitionType == LayoutTransition.DISAPPEARING && mTransitioningViews != null) {
Chet Haaseb20db3e2010-09-10 13:07:30 -07007123 endViewTransition(view);
Chet Haase21cd1382010-09-01 17:42:29 -07007124 }
7125 }
7126 };
7127
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007128 /**
Chet Haaseb9895022013-04-02 15:10:58 -07007129 * Tells this ViewGroup to suppress all layout() calls until layout
7130 * suppression is disabled with a later call to suppressLayout(false).
7131 * When layout suppression is disabled, a requestLayout() call is sent
7132 * if layout() was attempted while layout was being suppressed.
Chet Haaseb9895022013-04-02 15:10:58 -07007133 */
7134 public void suppressLayout(boolean suppress) {
7135 mSuppressLayout = suppress;
7136 if (!suppress) {
7137 if (mLayoutCalledWhileSuppressed) {
7138 requestLayout();
7139 mLayoutCalledWhileSuppressed = false;
7140 }
7141 }
7142 }
7143
7144 /**
Chet Haase199acdf2013-07-24 18:40:55 -07007145 * Returns whether layout calls on this container are currently being
7146 * suppressed, due to an earlier call to {@link #suppressLayout(boolean)}.
7147 *
7148 * @return true if layout calls are currently suppressed, false otherwise.
Chet Haase199acdf2013-07-24 18:40:55 -07007149 */
7150 public boolean isLayoutSuppressed() {
7151 return mSuppressLayout;
7152 }
7153
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007154 @Override
7155 public boolean gatherTransparentRegion(Region region) {
7156 // If no transparent regions requested, we are always opaque.
Dianne Hackborn4702a852012-08-17 15:18:29 -07007157 final boolean meOpaque = (mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) == 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007158 if (meOpaque && region == null) {
7159 // The caller doesn't care about the region, so stop now.
7160 return true;
7161 }
7162 super.gatherTransparentRegion(region);
Teng-Hui Zhuf8da30d2016-08-15 10:28:20 -07007163 // Instead of naively traversing the view tree, we have to traverse according to the Z
7164 // order here. We need to go with the same order as dispatchDraw().
7165 // One example is that after surfaceView punch a hole, we will still allow other views drawn
7166 // on top of that hole. In this case, those other views should be able to cut the
7167 // transparent region into smaller area.
7168 final int childrenCount = mChildrenCount;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007169 boolean noneOfTheChildrenAreTransparent = true;
Teng-Hui Zhuf8da30d2016-08-15 10:28:20 -07007170 if (childrenCount > 0) {
7171 final ArrayList<View> preorderedList = buildOrderedChildList();
7172 final boolean customOrder = preorderedList == null
7173 && isChildrenDrawingOrderEnabled();
7174 final View[] children = mChildren;
7175 for (int i = 0; i < childrenCount; i++) {
7176 final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
7177 final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);
7178 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
7179 if (!child.gatherTransparentRegion(region)) {
7180 noneOfTheChildrenAreTransparent = false;
7181 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007182 }
7183 }
Teng-Hui Zhuf8da30d2016-08-15 10:28:20 -07007184 if (preorderedList != null) preorderedList.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007185 }
7186 return meOpaque || noneOfTheChildrenAreTransparent;
7187 }
7188
Alan Viverettebe463f22016-01-21 10:50:10 -05007189 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007190 public void requestTransparentRegion(View child) {
7191 if (child != null) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07007192 child.mPrivateFlags |= View.PFLAG_REQUEST_TRANSPARENT_REGIONS;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007193 if (mParent != null) {
7194 mParent.requestTransparentRegion(this);
7195 }
7196 }
7197 }
Romain Guy8506ab42009-06-11 17:35:47 -07007198
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007199 @Override
Adam Powell46e38fd2014-02-03 10:16:49 -08007200 public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) {
7201 insets = super.dispatchApplyWindowInsets(insets);
Jorim Jaggi15637fd2018-12-04 13:38:03 +01007202 if (View.sBrokenInsetsDispatch) {
7203 return brokenDispatchApplyWindowInsets(insets);
7204 } else {
7205 return newDispatchApplyWindowInsets(insets);
7206 }
7207 }
7208
7209 private WindowInsets brokenDispatchApplyWindowInsets(WindowInsets insets) {
Adam Powell0d9fdba2014-06-11 15:33:08 -07007210 if (!insets.isConsumed()) {
Adam Powell46e38fd2014-02-03 10:16:49 -08007211 final int count = getChildCount();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007212 for (int i = 0; i < count; i++) {
Adam Powell46e38fd2014-02-03 10:16:49 -08007213 insets = getChildAt(i).dispatchApplyWindowInsets(insets);
Adam Powell0d9fdba2014-06-11 15:33:08 -07007214 if (insets.isConsumed()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007215 break;
7216 }
7217 }
7218 }
Adam Powell46e38fd2014-02-03 10:16:49 -08007219 return insets;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007220 }
7221
Jorim Jaggi15637fd2018-12-04 13:38:03 +01007222 private WindowInsets newDispatchApplyWindowInsets(WindowInsets insets) {
7223 final int count = getChildCount();
7224 for (int i = 0; i < count; i++) {
7225 getChildAt(i).dispatchApplyWindowInsets(insets);
7226 }
7227 return insets;
7228 }
7229
Jorim Jaggi02a741f2018-12-12 17:40:19 -08007230 @Override
7231 void dispatchWindowInsetsAnimationStarted(InsetsAnimation animation) {
7232 super.dispatchWindowInsetsAnimationStarted(animation);
7233 final int count = getChildCount();
7234 for (int i = 0; i < count; i++) {
7235 getChildAt(i).dispatchWindowInsetsAnimationStarted(animation);
7236 }
7237 }
7238
7239 @Override
7240 WindowInsets dispatchWindowInsetsAnimationProgress(WindowInsets insets) {
7241 insets = super.dispatchWindowInsetsAnimationProgress(insets);
7242 final int count = getChildCount();
7243 for (int i = 0; i < count; i++) {
7244 getChildAt(i).dispatchWindowInsetsAnimationProgress(insets);
7245 }
7246 return insets;
7247 }
7248
7249 @Override
7250 void dispatchWindowInsetsAnimationFinished(InsetsAnimation animation) {
7251 super.dispatchWindowInsetsAnimationFinished(animation);
7252 final int count = getChildCount();
7253 for (int i = 0; i < count; i++) {
7254 getChildAt(i).dispatchWindowInsetsAnimationFinished(animation);
7255 }
7256 }
7257
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007258 /**
7259 * Returns the animation listener to which layout animation events are
7260 * sent.
7261 *
7262 * @return an {@link android.view.animation.Animation.AnimationListener}
7263 */
7264 public Animation.AnimationListener getLayoutAnimationListener() {
7265 return mAnimationListener;
7266 }
7267
7268 @Override
7269 protected void drawableStateChanged() {
7270 super.drawableStateChanged();
7271
7272 if ((mGroupFlags & FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE) != 0) {
7273 if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0) {
7274 throw new IllegalStateException("addStateFromChildren cannot be enabled if a"
7275 + " child has duplicateParentState set to true");
7276 }
7277
7278 final View[] children = mChildren;
7279 final int count = mChildrenCount;
7280
7281 for (int i = 0; i < count; i++) {
7282 final View child = children[i];
7283 if ((child.mViewFlags & DUPLICATE_PARENT_STATE) != 0) {
7284 child.refreshDrawableState();
7285 }
7286 }
7287 }
7288 }
7289
7290 @Override
Dianne Hackborne2136772010-11-04 15:08:59 -07007291 public void jumpDrawablesToCurrentState() {
7292 super.jumpDrawablesToCurrentState();
7293 final View[] children = mChildren;
7294 final int count = mChildrenCount;
7295 for (int i = 0; i < count; i++) {
7296 children[i].jumpDrawablesToCurrentState();
7297 }
7298 }
7299
7300 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007301 protected int[] onCreateDrawableState(int extraSpace) {
7302 if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) == 0) {
7303 return super.onCreateDrawableState(extraSpace);
7304 }
7305
7306 int need = 0;
7307 int n = getChildCount();
7308 for (int i = 0; i < n; i++) {
7309 int[] childState = getChildAt(i).getDrawableState();
7310
7311 if (childState != null) {
7312 need += childState.length;
7313 }
7314 }
7315
7316 int[] state = super.onCreateDrawableState(extraSpace + need);
7317
7318 for (int i = 0; i < n; i++) {
7319 int[] childState = getChildAt(i).getDrawableState();
7320
7321 if (childState != null) {
7322 state = mergeDrawableStates(state, childState);
7323 }
7324 }
7325
7326 return state;
7327 }
7328
7329 /**
7330 * Sets whether this ViewGroup's drawable states also include
7331 * its children's drawable states. This is used, for example, to
7332 * make a group appear to be focused when its child EditText or button
7333 * is focused.
7334 */
7335 public void setAddStatesFromChildren(boolean addsStates) {
7336 if (addsStates) {
7337 mGroupFlags |= FLAG_ADD_STATES_FROM_CHILDREN;
7338 } else {
7339 mGroupFlags &= ~FLAG_ADD_STATES_FROM_CHILDREN;
7340 }
7341
7342 refreshDrawableState();
7343 }
7344
7345 /**
7346 * Returns whether this ViewGroup's drawable states also include
7347 * its children's drawable states. This is used, for example, to
7348 * make a group appear to be focused when its child EditText or button
7349 * is focused.
7350 */
Ashley Rose55f9f922019-01-28 19:29:36 -05007351 @InspectableProperty
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007352 public boolean addStatesFromChildren() {
7353 return (mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0;
7354 }
7355
7356 /**
Jeff Smitha45746e2012-07-19 14:19:24 -05007357 * If {@link #addStatesFromChildren} is true, refreshes this group's
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007358 * drawable state (to include the states from its children).
7359 */
Alan Viverettebe463f22016-01-21 10:50:10 -05007360 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007361 public void childDrawableStateChanged(View child) {
7362 if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0) {
7363 refreshDrawableState();
7364 }
7365 }
7366
7367 /**
7368 * Specifies the animation listener to which layout animation events must
7369 * be sent. Only
7370 * {@link android.view.animation.Animation.AnimationListener#onAnimationStart(Animation)}
7371 * and
7372 * {@link android.view.animation.Animation.AnimationListener#onAnimationEnd(Animation)}
7373 * are invoked.
7374 *
7375 * @param animationListener the layout animation listener
7376 */
7377 public void setLayoutAnimationListener(Animation.AnimationListener animationListener) {
7378 mAnimationListener = animationListener;
7379 }
7380
7381 /**
Chet Haasecca2c982011-05-20 14:34:18 -07007382 * This method is called by LayoutTransition when there are 'changing' animations that need
7383 * to start after the layout/setup phase. The request is forwarded to the ViewAncestor, who
7384 * starts all pending transitions prior to the drawing phase in the current traversal.
7385 *
7386 * @param transition The LayoutTransition to be started on the next traversal.
7387 *
7388 * @hide
7389 */
7390 public void requestTransitionStart(LayoutTransition transition) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07007391 ViewRootImpl viewAncestor = getViewRootImpl();
Chet Haase1abf7fa2011-08-17 18:31:56 -07007392 if (viewAncestor != null) {
7393 viewAncestor.requestTransitionStart(transition);
7394 }
Chet Haasecca2c982011-05-20 14:34:18 -07007395 }
7396
Fabrice Di Meglio4457e852012-09-18 19:23:12 -07007397 /**
7398 * @hide
7399 */
Fabrice Di Meglio80dc53d2011-06-21 18:36:33 -07007400 @Override
Fabrice Di Meglio09ecb252013-05-03 16:51:55 -07007401 public boolean resolveRtlPropertiesIfNeeded() {
7402 final boolean result = super.resolveRtlPropertiesIfNeeded();
7403 // We dont need to resolve the children RTL properties if nothing has changed for the parent
7404 if (result) {
7405 int count = getChildCount();
7406 for (int i = 0; i < count; i++) {
7407 final View child = getChildAt(i);
7408 if (child.isLayoutDirectionInherited()) {
7409 child.resolveRtlPropertiesIfNeeded();
7410 }
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07007411 }
7412 }
Fabrice Di Meglio09ecb252013-05-03 16:51:55 -07007413 return result;
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07007414 }
7415
7416 /**
7417 * @hide
7418 */
7419 @Override
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07007420 public boolean resolveLayoutDirection() {
7421 final boolean result = super.resolveLayoutDirection();
7422 if (result) {
7423 int count = getChildCount();
7424 for (int i = 0; i < count; i++) {
7425 final View child = getChildAt(i);
7426 if (child.isLayoutDirectionInherited()) {
7427 child.resolveLayoutDirection();
7428 }
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07007429 }
7430 }
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07007431 return result;
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07007432 }
7433
7434 /**
7435 * @hide
7436 */
7437 @Override
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07007438 public boolean resolveTextDirection() {
7439 final boolean result = super.resolveTextDirection();
7440 if (result) {
7441 int count = getChildCount();
7442 for (int i = 0; i < count; i++) {
7443 final View child = getChildAt(i);
7444 if (child.isTextDirectionInherited()) {
7445 child.resolveTextDirection();
7446 }
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07007447 }
7448 }
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07007449 return result;
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07007450 }
7451
7452 /**
7453 * @hide
7454 */
7455 @Override
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07007456 public boolean resolveTextAlignment() {
7457 final boolean result = super.resolveTextAlignment();
7458 if (result) {
7459 int count = getChildCount();
7460 for (int i = 0; i < count; i++) {
7461 final View child = getChildAt(i);
7462 if (child.isTextAlignmentInherited()) {
7463 child.resolveTextAlignment();
7464 }
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07007465 }
7466 }
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07007467 return result;
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07007468 }
7469
7470 /**
7471 * @hide
7472 */
7473 @Override
Mathew Inwooda570dee2018-08-17 14:56:00 +01007474 @UnsupportedAppUsage
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07007475 public void resolvePadding() {
7476 super.resolvePadding();
7477 int count = getChildCount();
7478 for (int i = 0; i < count; i++) {
7479 final View child = getChildAt(i);
Adam Powell05f35122014-11-10 17:47:37 -08007480 if (child.isLayoutDirectionInherited() && !child.isPaddingResolved()) {
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07007481 child.resolvePadding();
7482 }
7483 }
7484 }
7485
7486 /**
7487 * @hide
7488 */
7489 @Override
7490 protected void resolveDrawables() {
7491 super.resolveDrawables();
7492 int count = getChildCount();
7493 for (int i = 0; i < count; i++) {
7494 final View child = getChildAt(i);
Adam Powell05f35122014-11-10 17:47:37 -08007495 if (child.isLayoutDirectionInherited() && !child.areDrawablesResolved()) {
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07007496 child.resolveDrawables();
7497 }
7498 }
7499 }
7500
Fabrice Di Meglio1e0ed6b2012-10-18 16:06:52 -07007501 /**
7502 * @hide
7503 */
Fabrice Di Megliofcc33482012-10-18 11:11:51 -07007504 @Override
7505 public void resolveLayoutParams() {
7506 super.resolveLayoutParams();
7507 int count = getChildCount();
7508 for (int i = 0; i < count; i++) {
7509 final View child = getChildAt(i);
7510 child.resolveLayoutParams();
7511 }
7512 }
7513
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07007514 /**
7515 * @hide
7516 */
Aurimas Liutikas80e4e182018-08-13 16:13:37 -07007517 @TestApi
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07007518 @Override
Fabrice Di Meglio4457e852012-09-18 19:23:12 -07007519 public void resetResolvedLayoutDirection() {
7520 super.resetResolvedLayoutDirection();
7521
Fabrice Di Meglio4457e852012-09-18 19:23:12 -07007522 int count = getChildCount();
Fabrice Di Meglio80dc53d2011-06-21 18:36:33 -07007523 for (int i = 0; i < count; i++) {
7524 final View child = getChildAt(i);
Fabrice Di Meglioe56ffdc2012-09-23 14:51:16 -07007525 if (child.isLayoutDirectionInherited()) {
Fabrice Di Meglio7f86c802011-07-01 15:09:24 -07007526 child.resetResolvedLayoutDirection();
Fabrice Di Meglio80dc53d2011-06-21 18:36:33 -07007527 }
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07007528 }
7529 }
7530
7531 /**
7532 * @hide
7533 */
Aurimas Liutikas80e4e182018-08-13 16:13:37 -07007534 @TestApi
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07007535 @Override
7536 public void resetResolvedTextDirection() {
7537 super.resetResolvedTextDirection();
7538
7539 int count = getChildCount();
7540 for (int i = 0; i < count; i++) {
7541 final View child = getChildAt(i);
Fabrice Di Meglio97e146c2012-09-23 15:45:16 -07007542 if (child.isTextDirectionInherited()) {
Fabrice Di Meglio22268862011-06-27 18:13:18 -07007543 child.resetResolvedTextDirection();
7544 }
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07007545 }
7546 }
7547
7548 /**
7549 * @hide
7550 */
Aurimas Liutikas80e4e182018-08-13 16:13:37 -07007551 @TestApi
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07007552 @Override
7553 public void resetResolvedTextAlignment() {
7554 super.resetResolvedTextAlignment();
7555
7556 int count = getChildCount();
7557 for (int i = 0; i < count; i++) {
7558 final View child = getChildAt(i);
Fabrice Di Meglio1a7d4872012-09-23 16:19:58 -07007559 if (child.isTextAlignmentInherited()) {
Fabrice Di Meglio9da0f8a2012-03-13 19:37:57 -07007560 child.resetResolvedTextAlignment();
7561 }
7562 }
7563 }
7564
Fabrice Di Meglio22268862011-06-27 18:13:18 -07007565 /**
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07007566 * @hide
7567 */
Aurimas Liutikas80e4e182018-08-13 16:13:37 -07007568 @TestApi
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07007569 @Override
7570 public void resetResolvedPadding() {
7571 super.resetResolvedPadding();
7572
7573 int count = getChildCount();
7574 for (int i = 0; i < count; i++) {
7575 final View child = getChildAt(i);
7576 if (child.isLayoutDirectionInherited()) {
7577 child.resetResolvedPadding();
7578 }
7579 }
7580 }
7581
7582 /**
7583 * @hide
7584 */
Aurimas Liutikas80e4e182018-08-13 16:13:37 -07007585 @TestApi
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07007586 @Override
7587 protected void resetResolvedDrawables() {
7588 super.resetResolvedDrawables();
7589
7590 int count = getChildCount();
7591 for (int i = 0; i < count; i++) {
7592 final View child = getChildAt(i);
7593 if (child.isLayoutDirectionInherited()) {
7594 child.resetResolvedDrawables();
7595 }
7596 }
7597 }
7598
7599 /**
Patrick Dubroye0a799a2011-05-04 16:19:22 -07007600 * Return true if the pressed state should be delayed for children or descendants of this
7601 * ViewGroup. Generally, this should be done for containers that can scroll, such as a List.
7602 * This prevents the pressed state from appearing when the user is actually trying to scroll
7603 * the content.
7604 *
7605 * The default implementation returns true for compatibility reasons. Subclasses that do
7606 * not scroll should generally override this method and return false.
7607 */
7608 public boolean shouldDelayChildPressedState() {
7609 return true;
7610 }
7611
Adam Powell10ba2772014-04-15 09:46:51 -07007612 /**
7613 * @inheritDoc
7614 */
7615 @Override
7616 public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
7617 return false;
7618 }
7619
7620 /**
7621 * @inheritDoc
7622 */
7623 @Override
7624 public void onNestedScrollAccepted(View child, View target, int axes) {
7625 mNestedScrollAxes = axes;
7626 }
7627
7628 /**
7629 * @inheritDoc
7630 *
7631 * <p>The default implementation of onStopNestedScroll calls
7632 * {@link #stopNestedScroll()} to halt any recursive nested scrolling in progress.</p>
7633 */
7634 @Override
7635 public void onStopNestedScroll(View child) {
7636 // Stop any recursive nested scrolling.
7637 stopNestedScroll();
Adam Powelld4a22d42015-04-16 15:44:10 -07007638 mNestedScrollAxes = 0;
Adam Powell10ba2772014-04-15 09:46:51 -07007639 }
7640
7641 /**
7642 * @inheritDoc
7643 */
7644 @Override
7645 public void onNestedScroll(View target, int dxConsumed, int dyConsumed,
7646 int dxUnconsumed, int dyUnconsumed) {
Chris Banes61d50702016-03-23 13:11:45 +00007647 // Re-dispatch up the tree by default
7648 dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, null);
Adam Powell10ba2772014-04-15 09:46:51 -07007649 }
7650
7651 /**
7652 * @inheritDoc
7653 */
7654 @Override
7655 public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
Chris Banes61d50702016-03-23 13:11:45 +00007656 // Re-dispatch up the tree by default
7657 dispatchNestedPreScroll(dx, dy, consumed, null);
Adam Powell10ba2772014-04-15 09:46:51 -07007658 }
7659
7660 /**
7661 * @inheritDoc
7662 */
7663 @Override
Adam Powellb36e4f92014-05-01 10:23:33 -07007664 public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
Chris Banes61d50702016-03-23 13:11:45 +00007665 // Re-dispatch up the tree by default
7666 return dispatchNestedFling(velocityX, velocityY, consumed);
Adam Powell10ba2772014-04-15 09:46:51 -07007667 }
7668
7669 /**
Adam Powellb72be592014-07-16 21:41:31 -07007670 * @inheritDoc
7671 */
7672 @Override
7673 public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
Chris Banes61d50702016-03-23 13:11:45 +00007674 // Re-dispatch up the tree by default
7675 return dispatchNestedPreFling(velocityX, velocityY);
Adam Powellb72be592014-07-16 21:41:31 -07007676 }
7677
7678 /**
Adam Powell10ba2772014-04-15 09:46:51 -07007679 * Return the current axes of nested scrolling for this ViewGroup.
7680 *
7681 * <p>A ViewGroup returning something other than {@link #SCROLL_AXIS_NONE} is currently
7682 * acting as a nested scrolling parent for one or more descendant views in the hierarchy.</p>
7683 *
7684 * @return Flags indicating the current axes of nested scrolling
7685 * @see #SCROLL_AXIS_HORIZONTAL
7686 * @see #SCROLL_AXIS_VERTICAL
7687 * @see #SCROLL_AXIS_NONE
7688 */
7689 public int getNestedScrollAxes() {
7690 return mNestedScrollAxes;
7691 }
7692
Philip Milned7dd8902012-01-26 16:55:30 -08007693 /** @hide */
7694 protected void onSetLayoutParams(View child, LayoutParams layoutParams) {
Robert Carr5429daa2017-04-03 19:00:26 -07007695 requestLayout();
Philip Milned7dd8902012-01-26 16:55:30 -08007696 }
7697
George Mounte1803372014-02-26 19:00:52 +00007698 /** @hide */
7699 @Override
7700 public void captureTransitioningViews(List<View> transitioningViews) {
7701 if (getVisibility() != View.VISIBLE) {
7702 return;
7703 }
7704 if (isTransitionGroup()) {
7705 transitioningViews.add(this);
7706 } else {
7707 int count = getChildCount();
7708 for (int i = 0; i < count; i++) {
7709 View child = getChildAt(i);
7710 child.captureTransitioningViews(transitioningViews);
7711 }
7712 }
7713 }
7714
7715 /** @hide */
7716 @Override
George Mountabb352a2014-05-09 10:27:20 -07007717 public void findNamedViews(Map<String, View> namedElements) {
George Mountfe361d22014-07-08 17:25:25 -07007718 if (getVisibility() != VISIBLE && mGhostView == null) {
George Mounte1803372014-02-26 19:00:52 +00007719 return;
7720 }
George Mountabb352a2014-05-09 10:27:20 -07007721 super.findNamedViews(namedElements);
George Mounte1803372014-02-26 19:00:52 +00007722 int count = getChildCount();
7723 for (int i = 0; i < count; i++) {
7724 View child = getChildAt(i);
George Mountabb352a2014-05-09 10:27:20 -07007725 child.findNamedViews(namedElements);
George Mounte1803372014-02-26 19:00:52 +00007726 }
7727 }
7728
Evan Rosky4807ae22018-03-22 16:04:15 -07007729 @Override
7730 boolean hasUnhandledKeyListener() {
7731 return (mChildUnhandledKeyListeners > 0) || super.hasUnhandledKeyListener();
7732 }
7733
7734 void incrementChildUnhandledKeyListeners() {
7735 mChildUnhandledKeyListeners += 1;
7736 if (mChildUnhandledKeyListeners == 1) {
7737 if (mParent instanceof ViewGroup) {
7738 ((ViewGroup) mParent).incrementChildUnhandledKeyListeners();
7739 }
7740 }
7741 }
7742
7743 void decrementChildUnhandledKeyListeners() {
7744 mChildUnhandledKeyListeners -= 1;
7745 if (mChildUnhandledKeyListeners == 0) {
7746 if (mParent instanceof ViewGroup) {
7747 ((ViewGroup) mParent).decrementChildUnhandledKeyListeners();
7748 }
7749 }
7750 }
7751
7752 @Override
7753 View dispatchUnhandledKeyEvent(KeyEvent evt) {
7754 if (!hasUnhandledKeyListener()) {
7755 return null;
7756 }
7757 ArrayList<View> orderedViews = buildOrderedChildList();
7758 if (orderedViews != null) {
7759 try {
7760 for (int i = orderedViews.size() - 1; i >= 0; --i) {
7761 View v = orderedViews.get(i);
7762 View consumer = v.dispatchUnhandledKeyEvent(evt);
7763 if (consumer != null) {
7764 return consumer;
7765 }
7766 }
7767 } finally {
7768 orderedViews.clear();
7769 }
7770 } else {
7771 for (int i = getChildCount() - 1; i >= 0; --i) {
7772 View v = getChildAt(i);
7773 View consumer = v.dispatchUnhandledKeyEvent(evt);
7774 if (consumer != null) {
7775 return consumer;
7776 }
7777 }
7778 }
7779 if (onUnhandledKeyEvent(evt)) {
7780 return this;
7781 }
7782 return null;
7783 }
7784
Patrick Dubroye0a799a2011-05-04 16:19:22 -07007785 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007786 * LayoutParams are used by views to tell their parents how they want to be
7787 * laid out. See
7788 * {@link android.R.styleable#ViewGroup_Layout ViewGroup Layout Attributes}
7789 * for a list of all child view attributes that this class supports.
Romain Guy8506ab42009-06-11 17:35:47 -07007790 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007791 * <p>
7792 * The base LayoutParams class just describes how big the view wants to be
7793 * for both width and height. For each dimension, it can specify one of:
7794 * <ul>
Dirk Dougherty75c66da2010-03-25 16:33:33 -07007795 * <li>FILL_PARENT (renamed MATCH_PARENT in API Level 8 and higher), which
7796 * means that the view wants to be as big as its parent (minus padding)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007797 * <li> WRAP_CONTENT, which means that the view wants to be just big enough
7798 * to enclose its content (plus padding)
Dirk Dougherty75c66da2010-03-25 16:33:33 -07007799 * <li> an exact number
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007800 * </ul>
7801 * There are subclasses of LayoutParams for different subclasses of
7802 * ViewGroup. For example, AbsoluteLayout has its own subclass of
Joe Fernandez558459f2011-10-13 16:47:36 -07007803 * LayoutParams which adds an X and Y value.</p>
7804 *
7805 * <div class="special reference">
7806 * <h3>Developer Guides</h3>
7807 * <p>For more information about creating user interface layouts, read the
7808 * <a href="{@docRoot}guide/topics/ui/declaring-layout.html">XML Layouts</a> developer
7809 * guide.</p></div>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007810 *
7811 * @attr ref android.R.styleable#ViewGroup_Layout_layout_height
7812 * @attr ref android.R.styleable#ViewGroup_Layout_layout_width
7813 */
7814 public static class LayoutParams {
7815 /**
Dirk Dougherty75c66da2010-03-25 16:33:33 -07007816 * Special value for the height or width requested by a View.
7817 * FILL_PARENT means that the view wants to be as big as its parent,
7818 * minus the parent's padding, if any. This value is deprecated
7819 * starting in API Level 8 and replaced by {@link #MATCH_PARENT}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007820 */
Romain Guy980a9382010-01-08 15:06:28 -08007821 @SuppressWarnings({"UnusedDeclaration"})
7822 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007823 public static final int FILL_PARENT = -1;
7824
7825 /**
7826 * Special value for the height or width requested by a View.
Gilles Debunnef5c6eff2010-02-09 19:08:36 -08007827 * MATCH_PARENT means that the view wants to be as big as its parent,
Dirk Dougherty75c66da2010-03-25 16:33:33 -07007828 * minus the parent's padding, if any. Introduced in API Level 8.
Romain Guy980a9382010-01-08 15:06:28 -08007829 */
7830 public static final int MATCH_PARENT = -1;
7831
7832 /**
7833 * Special value for the height or width requested by a View.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007834 * WRAP_CONTENT means that the view wants to be just large enough to fit
7835 * its own internal content, taking its own padding into account.
7836 */
7837 public static final int WRAP_CONTENT = -2;
7838
7839 /**
Dirk Dougherty75c66da2010-03-25 16:33:33 -07007840 * Information about how wide the view wants to be. Can be one of the
Mark Dolinerd0646dc2014-08-27 16:04:02 -07007841 * constants FILL_PARENT (replaced by MATCH_PARENT
7842 * in API Level 8) or WRAP_CONTENT, or an exact size.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007843 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07007844 @ViewDebug.ExportedProperty(category = "layout", mapping = {
Romain Guy980a9382010-01-08 15:06:28 -08007845 @ViewDebug.IntToString(from = MATCH_PARENT, to = "MATCH_PARENT"),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007846 @ViewDebug.IntToString(from = WRAP_CONTENT, to = "WRAP_CONTENT")
7847 })
Ashley Rosede3b4a72019-03-04 16:44:07 -05007848 @InspectableProperty(name = "layout_width", enumMapping = {
7849 @InspectableProperty.EnumMap(name = "match_parent", value = MATCH_PARENT),
7850 @InspectableProperty.EnumMap(name = "wrap_content", value = WRAP_CONTENT)
7851 })
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007852 public int width;
7853
7854 /**
Dirk Dougherty75c66da2010-03-25 16:33:33 -07007855 * Information about how tall the view wants to be. Can be one of the
Mark Dolinerd0646dc2014-08-27 16:04:02 -07007856 * constants FILL_PARENT (replaced by MATCH_PARENT
7857 * in API Level 8) or WRAP_CONTENT, or an exact size.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007858 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07007859 @ViewDebug.ExportedProperty(category = "layout", mapping = {
Romain Guy980a9382010-01-08 15:06:28 -08007860 @ViewDebug.IntToString(from = MATCH_PARENT, to = "MATCH_PARENT"),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007861 @ViewDebug.IntToString(from = WRAP_CONTENT, to = "WRAP_CONTENT")
7862 })
Ashley Rosede3b4a72019-03-04 16:44:07 -05007863 @InspectableProperty(name = "layout_height", enumMapping = {
7864 @InspectableProperty.EnumMap(name = "match_parent", value = MATCH_PARENT),
7865 @InspectableProperty.EnumMap(name = "wrap_content", value = WRAP_CONTENT)
7866 })
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007867 public int height;
7868
7869 /**
7870 * Used to animate layouts.
7871 */
7872 public LayoutAnimationController.AnimationParameters layoutAnimationParameters;
7873
7874 /**
7875 * Creates a new set of layout parameters. The values are extracted from
7876 * the supplied attributes set and context. The XML attributes mapped
7877 * to this set of layout parameters are:
7878 *
7879 * <ul>
7880 * <li><code>layout_width</code>: the width, either an exact value,
Dirk Dougherty75c66da2010-03-25 16:33:33 -07007881 * {@link #WRAP_CONTENT}, or {@link #FILL_PARENT} (replaced by
7882 * {@link #MATCH_PARENT} in API Level 8)</li>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007883 * <li><code>layout_height</code>: the height, either an exact value,
Dirk Dougherty75c66da2010-03-25 16:33:33 -07007884 * {@link #WRAP_CONTENT}, or {@link #FILL_PARENT} (replaced by
7885 * {@link #MATCH_PARENT} in API Level 8)</li>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007886 * </ul>
7887 *
7888 * @param c the application environment
7889 * @param attrs the set of attributes from which to extract the layout
7890 * parameters' values
7891 */
7892 public LayoutParams(Context c, AttributeSet attrs) {
7893 TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ViewGroup_Layout);
7894 setBaseAttributes(a,
7895 R.styleable.ViewGroup_Layout_layout_width,
7896 R.styleable.ViewGroup_Layout_layout_height);
7897 a.recycle();
7898 }
7899
7900 /**
7901 * Creates a new set of layout parameters with the specified width
7902 * and height.
7903 *
Dirk Dougherty75c66da2010-03-25 16:33:33 -07007904 * @param width the width, either {@link #WRAP_CONTENT},
7905 * {@link #FILL_PARENT} (replaced by {@link #MATCH_PARENT} in
7906 * API Level 8), or a fixed size in pixels
7907 * @param height the height, either {@link #WRAP_CONTENT},
7908 * {@link #FILL_PARENT} (replaced by {@link #MATCH_PARENT} in
7909 * API Level 8), or a fixed size in pixels
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007910 */
7911 public LayoutParams(int width, int height) {
7912 this.width = width;
7913 this.height = height;
7914 }
7915
7916 /**
7917 * Copy constructor. Clones the width and height values of the source.
7918 *
7919 * @param source The layout params to copy from.
7920 */
7921 public LayoutParams(LayoutParams source) {
7922 this.width = source.width;
7923 this.height = source.height;
7924 }
7925
7926 /**
7927 * Used internally by MarginLayoutParams.
7928 * @hide
7929 */
Mathew Inwooda570dee2018-08-17 14:56:00 +01007930 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007931 LayoutParams() {
7932 }
7933
7934 /**
Dave Burke579e1402012-10-18 20:41:55 -07007935 * Extracts the layout parameters from the supplied attributes.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007936 *
7937 * @param a the style attributes to extract the parameters from
7938 * @param widthAttr the identifier of the width attribute
7939 * @param heightAttr the identifier of the height attribute
7940 */
7941 protected void setBaseAttributes(TypedArray a, int widthAttr, int heightAttr) {
Dave Burke579e1402012-10-18 20:41:55 -07007942 width = a.getLayoutDimension(widthAttr, "layout_width");
7943 height = a.getLayoutDimension(heightAttr, "layout_height");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007944 }
7945
7946 /**
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007947 * Resolve layout parameters depending on the layout direction. Subclasses that care about
7948 * layoutDirection changes should override this method. The default implementation does
7949 * nothing.
7950 *
7951 * @param layoutDirection the direction of the layout
7952 *
7953 * {@link View#LAYOUT_DIRECTION_LTR}
7954 * {@link View#LAYOUT_DIRECTION_RTL}
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007955 */
Fabrice Di Meglio2918ab62012-10-10 16:39:25 -07007956 public void resolveLayoutDirection(int layoutDirection) {
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007957 }
7958
7959 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007960 * Returns a String representation of this set of layout parameters.
7961 *
7962 * @param output the String to prepend to the internal representation
7963 * @return a String with the following format: output +
7964 * "ViewGroup.LayoutParams={ width=WIDTH, height=HEIGHT }"
Romain Guy8506ab42009-06-11 17:35:47 -07007965 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007966 * @hide
7967 */
7968 public String debug(String output) {
7969 return output + "ViewGroup.LayoutParams={ width="
7970 + sizeToString(width) + ", height=" + sizeToString(height) + " }";
7971 }
7972
7973 /**
Philip Milne10ca24a2012-04-23 15:38:27 -07007974 * Use {@code canvas} to draw suitable debugging annotations for these LayoutParameters.
7975 *
7976 * @param view the view that contains these layout parameters
7977 * @param canvas the canvas on which to draw
Alan Viverette2d7771c2018-01-31 17:04:31 -05007978 *
7979 * @hide
Philip Milne10ca24a2012-04-23 15:38:27 -07007980 */
Philip Milne7b757812012-09-19 18:13:44 -07007981 public void onDebugDraw(View view, Canvas canvas, Paint paint) {
Philip Milne10ca24a2012-04-23 15:38:27 -07007982 }
7983
7984 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007985 * Converts the specified size to a readable String.
7986 *
7987 * @param size the size to convert
7988 * @return a String instance representing the supplied size
Romain Guy8506ab42009-06-11 17:35:47 -07007989 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007990 * @hide
7991 */
7992 protected static String sizeToString(int size) {
7993 if (size == WRAP_CONTENT) {
7994 return "wrap-content";
7995 }
Romain Guy980a9382010-01-08 15:06:28 -08007996 if (size == MATCH_PARENT) {
7997 return "match-parent";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007998 }
7999 return String.valueOf(size);
8000 }
Siva Velusamy0d857b92015-04-22 10:23:56 -07008001
8002 /** @hide */
8003 void encode(@NonNull ViewHierarchyEncoder encoder) {
8004 encoder.beginObject(this);
8005 encodeProperties(encoder);
8006 encoder.endObject();
8007 }
8008
8009 /** @hide */
8010 protected void encodeProperties(@NonNull ViewHierarchyEncoder encoder) {
8011 encoder.addProperty("width", width);
8012 encoder.addProperty("height", height);
8013 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008014 }
8015
8016 /**
8017 * Per-child layout information for layouts that support margins.
8018 * See
8019 * {@link android.R.styleable#ViewGroup_MarginLayout ViewGroup Margin Layout Attributes}
8020 * for a list of all child view attributes that this class supports.
Chet Haase353d3972017-06-29 07:54:19 -07008021 *
8022 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_margin
8023 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginHorizontal
8024 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginVertical
8025 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginLeft
8026 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginTop
8027 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginRight
8028 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginBottom
8029 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
8030 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008031 */
8032 public static class MarginLayoutParams extends ViewGroup.LayoutParams {
8033 /**
Adam Powella7a735f2014-10-09 12:54:52 -07008034 * The left margin in pixels of the child. Margin values should be positive.
Philip Milned7dd8902012-01-26 16:55:30 -08008035 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
8036 * to this field.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008037 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07008038 @ViewDebug.ExportedProperty(category = "layout")
Ashley Rosede3b4a72019-03-04 16:44:07 -05008039 @InspectableProperty(name = "layout_marginLeft")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008040 public int leftMargin;
8041
8042 /**
Adam Powella7a735f2014-10-09 12:54:52 -07008043 * The top margin in pixels of the child. Margin values should be positive.
Philip Milned7dd8902012-01-26 16:55:30 -08008044 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
8045 * to this field.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008046 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07008047 @ViewDebug.ExportedProperty(category = "layout")
Ashley Rosede3b4a72019-03-04 16:44:07 -05008048 @InspectableProperty(name = "layout_marginTop")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008049 public int topMargin;
8050
8051 /**
Adam Powella7a735f2014-10-09 12:54:52 -07008052 * The right margin in pixels of the child. Margin values should be positive.
Philip Milned7dd8902012-01-26 16:55:30 -08008053 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
8054 * to this field.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008055 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07008056 @ViewDebug.ExportedProperty(category = "layout")
Ashley Rosede3b4a72019-03-04 16:44:07 -05008057 @InspectableProperty(name = "layout_marginRight")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008058 public int rightMargin;
8059
8060 /**
Adam Powella7a735f2014-10-09 12:54:52 -07008061 * The bottom margin in pixels of the child. Margin values should be positive.
Philip Milned7dd8902012-01-26 16:55:30 -08008062 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
8063 * to this field.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008064 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07008065 @ViewDebug.ExportedProperty(category = "layout")
Ashley Rosede3b4a72019-03-04 16:44:07 -05008066 @InspectableProperty(name = "layout_marginBottom")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008067 public int bottomMargin;
8068
8069 /**
Adam Powella7a735f2014-10-09 12:54:52 -07008070 * The start margin in pixels of the child. Margin values should be positive.
Fabrice Di Meglio54546f22012-02-14 16:26:16 -08008071 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
8072 * to this field.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07008073 */
8074 @ViewDebug.ExportedProperty(category = "layout")
Mathew Inwooda570dee2018-08-17 14:56:00 +01008075 @UnsupportedAppUsage
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07008076 private int startMargin = DEFAULT_MARGIN_RELATIVE;
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07008077
8078 /**
Adam Powella7a735f2014-10-09 12:54:52 -07008079 * The end margin in pixels of the child. Margin values should be positive.
Fabrice Di Meglio54546f22012-02-14 16:26:16 -08008080 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
8081 * to this field.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07008082 */
8083 @ViewDebug.ExportedProperty(category = "layout")
Mathew Inwooda570dee2018-08-17 14:56:00 +01008084 @UnsupportedAppUsage
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07008085 private int endMargin = DEFAULT_MARGIN_RELATIVE;
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07008086
8087 /**
8088 * The default start and end margin.
Fabrice Di Megliof443f982012-07-13 20:24:03 -07008089 * @hide
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07008090 */
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07008091 public static final int DEFAULT_MARGIN_RELATIVE = Integer.MIN_VALUE;
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07008092
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008093 /**
8094 * Bit 0: layout direction
8095 * Bit 1: layout direction
8096 * Bit 2: left margin undefined
8097 * Bit 3: right margin undefined
8098 * Bit 4: is RTL compatibility mode
8099 * Bit 5: need resolution
8100 *
8101 * Bit 6 to 7 not used
8102 *
8103 * @hide
8104 */
8105 @ViewDebug.ExportedProperty(category = "layout", flagMapping = {
8106 @ViewDebug.FlagToString(mask = LAYOUT_DIRECTION_MASK,
8107 equals = LAYOUT_DIRECTION_MASK, name = "LAYOUT_DIRECTION"),
8108 @ViewDebug.FlagToString(mask = LEFT_MARGIN_UNDEFINED_MASK,
8109 equals = LEFT_MARGIN_UNDEFINED_MASK, name = "LEFT_MARGIN_UNDEFINED_MASK"),
8110 @ViewDebug.FlagToString(mask = RIGHT_MARGIN_UNDEFINED_MASK,
8111 equals = RIGHT_MARGIN_UNDEFINED_MASK, name = "RIGHT_MARGIN_UNDEFINED_MASK"),
8112 @ViewDebug.FlagToString(mask = RTL_COMPATIBILITY_MODE_MASK,
8113 equals = RTL_COMPATIBILITY_MODE_MASK, name = "RTL_COMPATIBILITY_MODE_MASK"),
8114 @ViewDebug.FlagToString(mask = NEED_RESOLUTION_MASK,
8115 equals = NEED_RESOLUTION_MASK, name = "NEED_RESOLUTION_MASK")
Jon Miranda4597e982014-07-29 07:25:49 -07008116 }, formatToHexString = true)
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008117 byte mMarginFlags;
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07008118
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008119 private static final int LAYOUT_DIRECTION_MASK = 0x00000003;
8120 private static final int LEFT_MARGIN_UNDEFINED_MASK = 0x00000004;
8121 private static final int RIGHT_MARGIN_UNDEFINED_MASK = 0x00000008;
8122 private static final int RTL_COMPATIBILITY_MODE_MASK = 0x00000010;
8123 private static final int NEED_RESOLUTION_MASK = 0x00000020;
Fabrice Di Megliof443f982012-07-13 20:24:03 -07008124
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008125 private static final int DEFAULT_MARGIN_RESOLVED = 0;
8126 private static final int UNDEFINED_MARGIN = DEFAULT_MARGIN_RELATIVE;
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07008127
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07008128 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008129 * Creates a new set of layout parameters. The values are extracted from
8130 * the supplied attributes set and context.
8131 *
8132 * @param c the application environment
8133 * @param attrs the set of attributes from which to extract the layout
8134 * parameters' values
8135 */
8136 public MarginLayoutParams(Context c, AttributeSet attrs) {
8137 super();
8138
8139 TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ViewGroup_MarginLayout);
8140 setBaseAttributes(a,
8141 R.styleable.ViewGroup_MarginLayout_layout_width,
8142 R.styleable.ViewGroup_MarginLayout_layout_height);
8143
8144 int margin = a.getDimensionPixelSize(
8145 com.android.internal.R.styleable.ViewGroup_MarginLayout_layout_margin, -1);
8146 if (margin >= 0) {
8147 leftMargin = margin;
8148 topMargin = margin;
8149 rightMargin= margin;
8150 bottomMargin = margin;
8151 } else {
Chet Haase40b2de52016-11-28 16:11:42 -08008152 int horizontalMargin = a.getDimensionPixelSize(
8153 R.styleable.ViewGroup_MarginLayout_layout_marginHorizontal, -1);
8154 int verticalMargin = a.getDimensionPixelSize(
8155 R.styleable.ViewGroup_MarginLayout_layout_marginVertical, -1);
8156
8157 if (horizontalMargin >= 0) {
8158 leftMargin = horizontalMargin;
8159 rightMargin = horizontalMargin;
8160 } else {
8161 leftMargin = a.getDimensionPixelSize(
8162 R.styleable.ViewGroup_MarginLayout_layout_marginLeft,
8163 UNDEFINED_MARGIN);
8164 if (leftMargin == UNDEFINED_MARGIN) {
8165 mMarginFlags |= LEFT_MARGIN_UNDEFINED_MASK;
8166 leftMargin = DEFAULT_MARGIN_RESOLVED;
8167 }
8168 rightMargin = a.getDimensionPixelSize(
8169 R.styleable.ViewGroup_MarginLayout_layout_marginRight,
8170 UNDEFINED_MARGIN);
8171 if (rightMargin == UNDEFINED_MARGIN) {
8172 mMarginFlags |= RIGHT_MARGIN_UNDEFINED_MASK;
8173 rightMargin = DEFAULT_MARGIN_RESOLVED;
8174 }
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07008175 }
8176
Chet Haasecb3d0232017-05-24 18:27:14 -07008177 startMargin = a.getDimensionPixelSize(
8178 R.styleable.ViewGroup_MarginLayout_layout_marginStart,
8179 DEFAULT_MARGIN_RELATIVE);
8180 endMargin = a.getDimensionPixelSize(
8181 R.styleable.ViewGroup_MarginLayout_layout_marginEnd,
8182 DEFAULT_MARGIN_RELATIVE);
8183
Chet Haase40b2de52016-11-28 16:11:42 -08008184 if (verticalMargin >= 0) {
8185 topMargin = verticalMargin;
8186 bottomMargin = verticalMargin;
8187 } else {
8188 topMargin = a.getDimensionPixelSize(
8189 R.styleable.ViewGroup_MarginLayout_layout_marginTop,
8190 DEFAULT_MARGIN_RESOLVED);
8191 bottomMargin = a.getDimensionPixelSize(
8192 R.styleable.ViewGroup_MarginLayout_layout_marginBottom,
8193 DEFAULT_MARGIN_RESOLVED);
8194 }
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07008195
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008196 if (isMarginRelative()) {
8197 mMarginFlags |= NEED_RESOLUTION_MASK;
8198 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008199 }
8200
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07008201 final boolean hasRtlSupport = c.getApplicationInfo().hasRtlSupport();
8202 final int targetSdkVersion = c.getApplicationInfo().targetSdkVersion;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008203 if (targetSdkVersion < JELLY_BEAN_MR1 || !hasRtlSupport) {
8204 mMarginFlags |= RTL_COMPATIBILITY_MODE_MASK;
8205 }
8206
8207 // Layout direction is LTR by default
8208 mMarginFlags |= LAYOUT_DIRECTION_LTR;
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07008209
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008210 a.recycle();
8211 }
8212
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008213 public MarginLayoutParams(int width, int height) {
8214 super(width, height);
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07008215
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008216 mMarginFlags |= LEFT_MARGIN_UNDEFINED_MASK;
8217 mMarginFlags |= RIGHT_MARGIN_UNDEFINED_MASK;
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07008218
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008219 mMarginFlags &= ~NEED_RESOLUTION_MASK;
8220 mMarginFlags &= ~RTL_COMPATIBILITY_MODE_MASK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008221 }
8222
8223 /**
8224 * Copy constructor. Clones the width, height and margin values of the source.
8225 *
8226 * @param source The layout params to copy from.
8227 */
8228 public MarginLayoutParams(MarginLayoutParams source) {
8229 this.width = source.width;
8230 this.height = source.height;
8231
8232 this.leftMargin = source.leftMargin;
8233 this.topMargin = source.topMargin;
8234 this.rightMargin = source.rightMargin;
8235 this.bottomMargin = source.bottomMargin;
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07008236 this.startMargin = source.startMargin;
8237 this.endMargin = source.endMargin;
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07008238
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008239 this.mMarginFlags = source.mMarginFlags;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008240 }
8241
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008242 public MarginLayoutParams(LayoutParams source) {
8243 super(source);
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07008244
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008245 mMarginFlags |= LEFT_MARGIN_UNDEFINED_MASK;
8246 mMarginFlags |= RIGHT_MARGIN_UNDEFINED_MASK;
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07008247
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008248 mMarginFlags &= ~NEED_RESOLUTION_MASK;
8249 mMarginFlags &= ~RTL_COMPATIBILITY_MODE_MASK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008250 }
8251
8252 /**
Adam Powelld7600832014-07-01 15:22:50 -07008253 * @hide Used internally.
8254 */
8255 public final void copyMarginsFrom(MarginLayoutParams source) {
8256 this.leftMargin = source.leftMargin;
8257 this.topMargin = source.topMargin;
8258 this.rightMargin = source.rightMargin;
8259 this.bottomMargin = source.bottomMargin;
8260 this.startMargin = source.startMargin;
8261 this.endMargin = source.endMargin;
8262
8263 this.mMarginFlags = source.mMarginFlags;
8264 }
8265
8266 /**
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07008267 * Sets the margins, in pixels. A call to {@link android.view.View#requestLayout()} needs
8268 * to be done so that the new margins are taken into account. Left and right margins may be
koprivadebd4ee2018-09-13 10:59:46 -07008269 * overridden by {@link android.view.View#requestLayout()} depending on layout direction.
Adam Powella7a735f2014-10-09 12:54:52 -07008270 * Margin values should be positive.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008271 *
8272 * @param left the left margin size
8273 * @param top the top margin size
8274 * @param right the right margin size
8275 * @param bottom the bottom margin size
8276 *
8277 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginLeft
8278 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginTop
8279 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginRight
8280 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginBottom
8281 */
8282 public void setMargins(int left, int top, int right, int bottom) {
8283 leftMargin = left;
8284 topMargin = top;
8285 rightMargin = right;
8286 bottomMargin = bottom;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008287 mMarginFlags &= ~LEFT_MARGIN_UNDEFINED_MASK;
8288 mMarginFlags &= ~RIGHT_MARGIN_UNDEFINED_MASK;
8289 if (isMarginRelative()) {
8290 mMarginFlags |= NEED_RESOLUTION_MASK;
8291 } else {
8292 mMarginFlags &= ~NEED_RESOLUTION_MASK;
8293 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008294 }
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07008295
8296 /**
8297 * Sets the relative margins, in pixels. A call to {@link android.view.View#requestLayout()}
8298 * needs to be done so that the new relative margins are taken into account. Left and right
koprivadebd4ee2018-09-13 10:59:46 -07008299 * margins may be overridden by {@link android.view.View#requestLayout()} depending on
8300 * layout direction. Margin values should be positive.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07008301 *
8302 * @param start the start margin size
8303 * @param top the top margin size
8304 * @param end the right margin size
8305 * @param bottom the bottom margin size
8306 *
8307 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
8308 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginTop
8309 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
8310 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginBottom
8311 *
8312 * @hide
8313 */
Mathew Inwooda570dee2018-08-17 14:56:00 +01008314 @UnsupportedAppUsage
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07008315 public void setMarginsRelative(int start, int top, int end, int bottom) {
8316 startMargin = start;
8317 topMargin = top;
8318 endMargin = end;
8319 bottomMargin = bottom;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008320 mMarginFlags |= NEED_RESOLUTION_MASK;
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07008321 }
8322
8323 /**
Adam Powella7a735f2014-10-09 12:54:52 -07008324 * Sets the relative start margin. Margin values should be positive.
Fabrice Di Meglioa40627d2012-09-11 16:47:21 -07008325 *
Fabrice Di Meglio61a21772012-09-12 16:33:13 -07008326 * @param start the start margin size
Fabrice Di Meglioa40627d2012-09-11 16:47:21 -07008327 *
8328 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
8329 */
8330 public void setMarginStart(int start) {
8331 startMargin = start;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008332 mMarginFlags |= NEED_RESOLUTION_MASK;
Fabrice Di Meglioa40627d2012-09-11 16:47:21 -07008333 }
8334
8335 /**
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07008336 * Returns the start margin in pixels.
8337 *
8338 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
8339 *
8340 * @return the start margin in pixels.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07008341 */
8342 public int getMarginStart() {
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07008343 if (startMargin != DEFAULT_MARGIN_RELATIVE) return startMargin;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008344 if ((mMarginFlags & NEED_RESOLUTION_MASK) == NEED_RESOLUTION_MASK) {
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07008345 doResolveMargins();
8346 }
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008347 switch(mMarginFlags & LAYOUT_DIRECTION_MASK) {
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07008348 case View.LAYOUT_DIRECTION_RTL:
8349 return rightMargin;
8350 case View.LAYOUT_DIRECTION_LTR:
8351 default:
8352 return leftMargin;
8353 }
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07008354 }
8355
8356 /**
Adam Powella7a735f2014-10-09 12:54:52 -07008357 * Sets the relative end margin. Margin values should be positive.
Fabrice Di Meglioa40627d2012-09-11 16:47:21 -07008358 *
Fabrice Di Meglio61a21772012-09-12 16:33:13 -07008359 * @param end the end margin size
Fabrice Di Meglioa40627d2012-09-11 16:47:21 -07008360 *
8361 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
8362 */
8363 public void setMarginEnd(int end) {
8364 endMargin = end;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008365 mMarginFlags |= NEED_RESOLUTION_MASK;
Fabrice Di Meglioa40627d2012-09-11 16:47:21 -07008366 }
8367
8368 /**
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07008369 * Returns the end margin in pixels.
8370 *
8371 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
8372 *
8373 * @return the end margin in pixels.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07008374 */
8375 public int getMarginEnd() {
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07008376 if (endMargin != DEFAULT_MARGIN_RELATIVE) return endMargin;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008377 if ((mMarginFlags & NEED_RESOLUTION_MASK) == NEED_RESOLUTION_MASK) {
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07008378 doResolveMargins();
8379 }
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008380 switch(mMarginFlags & LAYOUT_DIRECTION_MASK) {
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07008381 case View.LAYOUT_DIRECTION_RTL:
8382 return leftMargin;
8383 case View.LAYOUT_DIRECTION_LTR:
8384 default:
8385 return rightMargin;
8386 }
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07008387 }
8388
8389 /**
8390 * Check if margins are relative.
8391 *
8392 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
8393 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
8394 *
Fabrice Di Megliof443f982012-07-13 20:24:03 -07008395 * @return true if either marginStart or marginEnd has been set.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07008396 */
8397 public boolean isMarginRelative() {
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07008398 return (startMargin != DEFAULT_MARGIN_RELATIVE || endMargin != DEFAULT_MARGIN_RELATIVE);
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07008399 }
8400
8401 /**
Fabrice Di Megliof443f982012-07-13 20:24:03 -07008402 * Set the layout direction
8403 * @param layoutDirection the layout direction.
8404 * Should be either {@link View#LAYOUT_DIRECTION_LTR}
8405 * or {@link View#LAYOUT_DIRECTION_RTL}.
8406 */
8407 public void setLayoutDirection(int layoutDirection) {
8408 if (layoutDirection != View.LAYOUT_DIRECTION_LTR &&
8409 layoutDirection != View.LAYOUT_DIRECTION_RTL) return;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008410 if (layoutDirection != (mMarginFlags & LAYOUT_DIRECTION_MASK)) {
8411 mMarginFlags &= ~LAYOUT_DIRECTION_MASK;
8412 mMarginFlags |= (layoutDirection & LAYOUT_DIRECTION_MASK);
8413 if (isMarginRelative()) {
8414 mMarginFlags |= NEED_RESOLUTION_MASK;
8415 } else {
8416 mMarginFlags &= ~NEED_RESOLUTION_MASK;
8417 }
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07008418 }
Fabrice Di Megliof443f982012-07-13 20:24:03 -07008419 }
8420
8421 /**
8422 * Retuns the layout direction. Can be either {@link View#LAYOUT_DIRECTION_LTR} or
8423 * {@link View#LAYOUT_DIRECTION_RTL}.
8424 *
8425 * @return the layout direction.
8426 */
8427 public int getLayoutDirection() {
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008428 return (mMarginFlags & LAYOUT_DIRECTION_MASK);
Fabrice Di Megliof443f982012-07-13 20:24:03 -07008429 }
8430
8431 /**
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07008432 * This will be called by {@link android.view.View#requestLayout()}. Left and Right margins
Fabrice Di Meglio98aec1c2012-02-13 16:54:05 -08008433 * may be overridden depending on layout direction.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07008434 */
8435 @Override
Fabrice Di Meglio2918ab62012-10-10 16:39:25 -07008436 public void resolveLayoutDirection(int layoutDirection) {
Fabrice Di Megliof443f982012-07-13 20:24:03 -07008437 setLayoutDirection(layoutDirection);
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07008438
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07008439 // No relative margin or pre JB-MR1 case or no need to resolve, just dont do anything
8440 // Will use the left and right margins if no relative margin is defined.
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008441 if (!isMarginRelative() ||
8442 (mMarginFlags & NEED_RESOLUTION_MASK) != NEED_RESOLUTION_MASK) return;
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07008443
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07008444 // Proceed with resolution
8445 doResolveMargins();
8446 }
8447
8448 private void doResolveMargins() {
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008449 if ((mMarginFlags & RTL_COMPATIBILITY_MODE_MASK) == RTL_COMPATIBILITY_MODE_MASK) {
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07008450 // if left or right margins are not defined and if we have some start or end margin
8451 // defined then use those start and end margins.
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008452 if ((mMarginFlags & LEFT_MARGIN_UNDEFINED_MASK) == LEFT_MARGIN_UNDEFINED_MASK
8453 && startMargin > DEFAULT_MARGIN_RELATIVE) {
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07008454 leftMargin = startMargin;
8455 }
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008456 if ((mMarginFlags & RIGHT_MARGIN_UNDEFINED_MASK) == RIGHT_MARGIN_UNDEFINED_MASK
8457 && endMargin > DEFAULT_MARGIN_RELATIVE) {
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07008458 rightMargin = endMargin;
8459 }
8460 } else {
8461 // We have some relative margins (either the start one or the end one or both). So use
8462 // them and override what has been defined for left and right margins. If either start
8463 // or end margin is not defined, just set it to default "0".
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008464 switch(mMarginFlags & LAYOUT_DIRECTION_MASK) {
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07008465 case View.LAYOUT_DIRECTION_RTL:
8466 leftMargin = (endMargin > DEFAULT_MARGIN_RELATIVE) ?
8467 endMargin : DEFAULT_MARGIN_RESOLVED;
8468 rightMargin = (startMargin > DEFAULT_MARGIN_RELATIVE) ?
8469 startMargin : DEFAULT_MARGIN_RESOLVED;
8470 break;
8471 case View.LAYOUT_DIRECTION_LTR:
8472 default:
8473 leftMargin = (startMargin > DEFAULT_MARGIN_RELATIVE) ?
8474 startMargin : DEFAULT_MARGIN_RESOLVED;
8475 rightMargin = (endMargin > DEFAULT_MARGIN_RELATIVE) ?
8476 endMargin : DEFAULT_MARGIN_RESOLVED;
8477 break;
8478 }
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07008479 }
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008480 mMarginFlags &= ~NEED_RESOLUTION_MASK;
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07008481 }
Philip Milne10ca24a2012-04-23 15:38:27 -07008482
Fabrice Di Meglio03b8d3a2012-09-27 17:05:27 -07008483 /**
8484 * @hide
8485 */
8486 public boolean isLayoutRtl() {
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008487 return ((mMarginFlags & LAYOUT_DIRECTION_MASK) == View.LAYOUT_DIRECTION_RTL);
Fabrice Di Megliof443f982012-07-13 20:24:03 -07008488 }
8489
Alan Viverette2d7771c2018-01-31 17:04:31 -05008490 /**
8491 * @hide
8492 */
Philip Milne10ca24a2012-04-23 15:38:27 -07008493 @Override
Philip Milne7b757812012-09-19 18:13:44 -07008494 public void onDebugDraw(View view, Canvas canvas, Paint paint) {
8495 Insets oi = isLayoutModeOptical(view.mParent) ? view.getOpticalInsets() : Insets.NONE;
8496
8497 fillDifference(canvas,
8498 view.getLeft() + oi.left,
8499 view.getTop() + oi.top,
8500 view.getRight() - oi.right,
8501 view.getBottom() - oi.bottom,
8502 leftMargin,
8503 topMargin,
8504 rightMargin,
8505 bottomMargin,
8506 paint);
Philip Milne10ca24a2012-04-23 15:38:27 -07008507 }
Siva Velusamy0d857b92015-04-22 10:23:56 -07008508
8509 /** @hide */
8510 @Override
8511 protected void encodeProperties(@NonNull ViewHierarchyEncoder encoder) {
8512 super.encodeProperties(encoder);
8513 encoder.addProperty("leftMargin", leftMargin);
8514 encoder.addProperty("topMargin", topMargin);
8515 encoder.addProperty("rightMargin", rightMargin);
8516 encoder.addProperty("bottomMargin", bottomMargin);
8517 encoder.addProperty("startMargin", startMargin);
8518 encoder.addProperty("endMargin", endMargin);
8519 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008520 }
Adam Powell2b342f02010-08-18 18:14:13 -07008521
Jeff Brown20e987b2010-08-23 12:01:02 -07008522 /* Describes a touched view and the ids of the pointers that it has captured.
8523 *
8524 * This code assumes that pointer ids are always in the range 0..31 such that
8525 * it can use a bitfield to track which pointer ids are present.
8526 * As it happens, the lower layers of the input dispatch pipeline also use the
8527 * same trick so the assumption should be safe here...
8528 */
8529 private static final class TouchTarget {
8530 private static final int MAX_RECYCLED = 32;
Romain Guy6410c0a2013-06-17 11:21:58 -07008531 private static final Object sRecycleLock = new Object[0];
Jeff Brown20e987b2010-08-23 12:01:02 -07008532 private static TouchTarget sRecycleBin;
8533 private static int sRecycledCount;
Adam Powell2b342f02010-08-18 18:14:13 -07008534
Jeff Brown20e987b2010-08-23 12:01:02 -07008535 public static final int ALL_POINTER_IDS = -1; // all ones
Adam Powell2b342f02010-08-18 18:14:13 -07008536
Jeff Brown20e987b2010-08-23 12:01:02 -07008537 // The touched child view.
Mathew Inwooda570dee2018-08-17 14:56:00 +01008538 @UnsupportedAppUsage
Jeff Brown20e987b2010-08-23 12:01:02 -07008539 public View child;
8540
8541 // The combined bit mask of pointer ids for all pointers captured by the target.
8542 public int pointerIdBits;
8543
8544 // The next target in the target list.
8545 public TouchTarget next;
8546
Mathew Inwooda570dee2018-08-17 14:56:00 +01008547 @UnsupportedAppUsage
Jeff Brown20e987b2010-08-23 12:01:02 -07008548 private TouchTarget() {
Adam Powell2b342f02010-08-18 18:14:13 -07008549 }
8550
Alan Viverettea7b85e62016-01-22 10:14:02 -05008551 public static TouchTarget obtain(@NonNull View child, int pointerIdBits) {
8552 if (child == null) {
8553 throw new IllegalArgumentException("child must be non-null");
8554 }
8555
Jeff Brown20e987b2010-08-23 12:01:02 -07008556 final TouchTarget target;
8557 synchronized (sRecycleLock) {
Adam Powell816c3be2010-08-23 18:00:05 -07008558 if (sRecycleBin == null) {
Jeff Brown20e987b2010-08-23 12:01:02 -07008559 target = new TouchTarget();
Adam Powell816c3be2010-08-23 18:00:05 -07008560 } else {
Jeff Brown20e987b2010-08-23 12:01:02 -07008561 target = sRecycleBin;
8562 sRecycleBin = target.next;
8563 sRecycledCount--;
8564 target.next = null;
Adam Powell816c3be2010-08-23 18:00:05 -07008565 }
Adam Powell816c3be2010-08-23 18:00:05 -07008566 }
Jeff Brown20e987b2010-08-23 12:01:02 -07008567 target.child = child;
8568 target.pointerIdBits = pointerIdBits;
8569 return target;
8570 }
Adam Powell816c3be2010-08-23 18:00:05 -07008571
Jeff Brown20e987b2010-08-23 12:01:02 -07008572 public void recycle() {
Alan Viverettea7b85e62016-01-22 10:14:02 -05008573 if (child == null) {
8574 throw new IllegalStateException("already recycled once");
8575 }
8576
Jeff Brown20e987b2010-08-23 12:01:02 -07008577 synchronized (sRecycleLock) {
8578 if (sRecycledCount < MAX_RECYCLED) {
8579 next = sRecycleBin;
8580 sRecycleBin = this;
8581 sRecycledCount += 1;
Patrick Dubroyfb0547d22010-10-19 17:36:18 -07008582 } else {
8583 next = null;
Adam Powell816c3be2010-08-23 18:00:05 -07008584 }
Patrick Dubroyfb0547d22010-10-19 17:36:18 -07008585 child = null;
Adam Powell816c3be2010-08-23 18:00:05 -07008586 }
8587 }
Adam Powell2b342f02010-08-18 18:14:13 -07008588 }
Jeff Brown87b7f802011-06-21 18:35:45 -07008589
8590 /* Describes a hovered view. */
8591 private static final class HoverTarget {
8592 private static final int MAX_RECYCLED = 32;
Romain Guy6410c0a2013-06-17 11:21:58 -07008593 private static final Object sRecycleLock = new Object[0];
Jeff Brown87b7f802011-06-21 18:35:45 -07008594 private static HoverTarget sRecycleBin;
8595 private static int sRecycledCount;
8596
8597 // The hovered child view.
8598 public View child;
8599
8600 // The next target in the target list.
8601 public HoverTarget next;
8602
8603 private HoverTarget() {
8604 }
8605
Alan Viverettea7b85e62016-01-22 10:14:02 -05008606 public static HoverTarget obtain(@NonNull View child) {
8607 if (child == null) {
8608 throw new IllegalArgumentException("child must be non-null");
8609 }
8610
Jeff Brown87b7f802011-06-21 18:35:45 -07008611 final HoverTarget target;
8612 synchronized (sRecycleLock) {
8613 if (sRecycleBin == null) {
8614 target = new HoverTarget();
8615 } else {
8616 target = sRecycleBin;
8617 sRecycleBin = target.next;
Alan Viverettea7b85e62016-01-22 10:14:02 -05008618 sRecycledCount--;
Jeff Brown87b7f802011-06-21 18:35:45 -07008619 target.next = null;
8620 }
8621 }
8622 target.child = child;
8623 return target;
8624 }
8625
8626 public void recycle() {
Alan Viverettea7b85e62016-01-22 10:14:02 -05008627 if (child == null) {
8628 throw new IllegalStateException("already recycled once");
8629 }
8630
Jeff Brown87b7f802011-06-21 18:35:45 -07008631 synchronized (sRecycleLock) {
8632 if (sRecycledCount < MAX_RECYCLED) {
8633 next = sRecycleBin;
8634 sRecycleBin = this;
8635 sRecycledCount += 1;
8636 } else {
8637 next = null;
8638 }
8639 child = null;
8640 }
8641 }
8642 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07008643
8644 /**
Svet Ganov2f8fb1f2017-03-13 00:21:04 -07008645 * Pooled class that to hold the children for autifill.
8646 */
Felipe Leme01297692019-01-29 18:16:23 -08008647 private static class ChildListForAutoFillOrContentCapture extends ArrayList<View> {
Svet Ganov2f8fb1f2017-03-13 00:21:04 -07008648 private static final int MAX_POOL_SIZE = 32;
8649
Felipe Leme01297692019-01-29 18:16:23 -08008650 private static final Pools.SimplePool<ChildListForAutoFillOrContentCapture> sPool =
Svet Ganov2f8fb1f2017-03-13 00:21:04 -07008651 new Pools.SimplePool<>(MAX_POOL_SIZE);
8652
Felipe Leme01297692019-01-29 18:16:23 -08008653 public static ChildListForAutoFillOrContentCapture obtain() {
8654 ChildListForAutoFillOrContentCapture list = sPool.acquire();
Svet Ganov2f8fb1f2017-03-13 00:21:04 -07008655 if (list == null) {
Felipe Leme01297692019-01-29 18:16:23 -08008656 list = new ChildListForAutoFillOrContentCapture();
Svet Ganov2f8fb1f2017-03-13 00:21:04 -07008657 }
8658 return list;
8659 }
8660
8661 public void recycle() {
8662 clear();
8663 sPool.release(this);
8664 }
8665 }
8666
8667 /**
Svetoslav Ganov42138042012-03-20 11:51:39 -07008668 * Pooled class that orderes the children of a ViewGroup from start
8669 * to end based on how they are laid out and the layout direction.
8670 */
8671 static class ChildListForAccessibility {
8672
8673 private static final int MAX_POOL_SIZE = 32;
8674
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08008675 private static final SynchronizedPool<ChildListForAccessibility> sPool =
8676 new SynchronizedPool<ChildListForAccessibility>(MAX_POOL_SIZE);
Svetoslav Ganov42138042012-03-20 11:51:39 -07008677
8678 private final ArrayList<View> mChildren = new ArrayList<View>();
8679
8680 private final ArrayList<ViewLocationHolder> mHolders = new ArrayList<ViewLocationHolder>();
8681
8682 public static ChildListForAccessibility obtain(ViewGroup parent, boolean sort) {
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08008683 ChildListForAccessibility list = sPool.acquire();
8684 if (list == null) {
8685 list = new ChildListForAccessibility();
Svetoslav Ganov42138042012-03-20 11:51:39 -07008686 }
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08008687 list.init(parent, sort);
8688 return list;
Svetoslav Ganov42138042012-03-20 11:51:39 -07008689 }
8690
8691 public void recycle() {
Svetoslav Ganov42138042012-03-20 11:51:39 -07008692 clear();
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08008693 sPool.release(this);
Svetoslav Ganov42138042012-03-20 11:51:39 -07008694 }
8695
8696 public int getChildCount() {
8697 return mChildren.size();
8698 }
8699
8700 public View getChildAt(int index) {
8701 return mChildren.get(index);
8702 }
8703
Svetoslav Ganov42138042012-03-20 11:51:39 -07008704 private void init(ViewGroup parent, boolean sort) {
8705 ArrayList<View> children = mChildren;
8706 final int childCount = parent.getChildCount();
8707 for (int i = 0; i < childCount; i++) {
8708 View child = parent.getChildAt(i);
8709 children.add(child);
8710 }
8711 if (sort) {
8712 ArrayList<ViewLocationHolder> holders = mHolders;
8713 for (int i = 0; i < childCount; i++) {
8714 View child = children.get(i);
8715 ViewLocationHolder holder = ViewLocationHolder.obtain(parent, child);
8716 holders.add(holder);
8717 }
Svetoslav88e447b2014-10-09 15:49:02 -07008718 sort(holders);
Svetoslav Ganov42138042012-03-20 11:51:39 -07008719 for (int i = 0; i < childCount; i++) {
8720 ViewLocationHolder holder = holders.get(i);
8721 children.set(i, holder.mView);
8722 holder.recycle();
8723 }
8724 holders.clear();
8725 }
8726 }
8727
Svetoslav88e447b2014-10-09 15:49:02 -07008728 private void sort(ArrayList<ViewLocationHolder> holders) {
8729 // This is gross but the least risky solution. The current comparison
8730 // strategy breaks transitivity but produces very good results. Coming
8731 // up with a new strategy requires time which we do not have, so ...
8732 try {
8733 ViewLocationHolder.setComparisonStrategy(
8734 ViewLocationHolder.COMPARISON_STRATEGY_STRIPE);
8735 Collections.sort(holders);
8736 } catch (IllegalArgumentException iae) {
8737 // Note that in practice this occurs extremely rarely in a couple
8738 // of pathological cases.
8739 ViewLocationHolder.setComparisonStrategy(
8740 ViewLocationHolder.COMPARISON_STRATEGY_LOCATION);
8741 Collections.sort(holders);
8742 }
8743 }
8744
Svetoslav Ganov42138042012-03-20 11:51:39 -07008745 private void clear() {
8746 mChildren.clear();
8747 }
8748 }
8749
8750 /**
8751 * Pooled class that holds a View and its location with respect to
8752 * a specified root. This enables sorting of views based on their
8753 * coordinates without recomputing the position relative to the root
8754 * on every comparison.
8755 */
8756 static class ViewLocationHolder implements Comparable<ViewLocationHolder> {
8757
8758 private static final int MAX_POOL_SIZE = 32;
8759
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08008760 private static final SynchronizedPool<ViewLocationHolder> sPool =
8761 new SynchronizedPool<ViewLocationHolder>(MAX_POOL_SIZE);
Svetoslav Ganov42138042012-03-20 11:51:39 -07008762
Svetoslav88e447b2014-10-09 15:49:02 -07008763 public static final int COMPARISON_STRATEGY_STRIPE = 1;
8764
8765 public static final int COMPARISON_STRATEGY_LOCATION = 2;
8766
8767 private static int sComparisonStrategy = COMPARISON_STRATEGY_STRIPE;
8768
Svetoslav Ganov42138042012-03-20 11:51:39 -07008769 private final Rect mLocation = new Rect();
8770
Phil Weaver86b32602018-05-10 18:00:18 -07008771 private ViewGroup mRoot;
8772
Svetoslav Ganov42138042012-03-20 11:51:39 -07008773 public View mView;
8774
8775 private int mLayoutDirection;
8776
8777 public static ViewLocationHolder obtain(ViewGroup root, View view) {
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08008778 ViewLocationHolder holder = sPool.acquire();
8779 if (holder == null) {
8780 holder = new ViewLocationHolder();
Svetoslav Ganov42138042012-03-20 11:51:39 -07008781 }
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08008782 holder.init(root, view);
8783 return holder;
Svetoslav Ganov42138042012-03-20 11:51:39 -07008784 }
8785
Svetoslav88e447b2014-10-09 15:49:02 -07008786 public static void setComparisonStrategy(int strategy) {
8787 sComparisonStrategy = strategy;
8788 }
8789
Svetoslav Ganov42138042012-03-20 11:51:39 -07008790 public void recycle() {
Svetoslav Ganov42138042012-03-20 11:51:39 -07008791 clear();
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08008792 sPool.release(this);
Svetoslav Ganov42138042012-03-20 11:51:39 -07008793 }
8794
8795 @Override
8796 public int compareTo(ViewLocationHolder another) {
8797 // This instance is greater than an invalid argument.
8798 if (another == null) {
8799 return 1;
8800 }
Svetoslav88e447b2014-10-09 15:49:02 -07008801
Phil Weaver86b32602018-05-10 18:00:18 -07008802 int boundsResult = compareBoundsOfTree(this, another);
8803 if (boundsResult != 0) {
8804 return boundsResult;
8805 }
8806
8807 // Just break the tie somehow. The accessibility ids are unique
8808 // and stable, hence this is deterministic tie breaking.
8809 return mView.getAccessibilityViewId() - another.mView.getAccessibilityViewId();
8810 }
8811
8812 /**
8813 * Compare two views based on their bounds. Use the bounds of their children to break ties.
8814 *
8815 * @param holder1 Holder of first view to compare
Phil Weaver6adf3a12018-08-21 16:08:42 -07008816 * @param holder2 Holder of second view to compare. Must have the same root as holder1.
Phil Weaver86b32602018-05-10 18:00:18 -07008817 * @return The compare result, with equality if no good comparison was found.
8818 */
8819 private static int compareBoundsOfTree(
8820 ViewLocationHolder holder1, ViewLocationHolder holder2) {
Svetoslav88e447b2014-10-09 15:49:02 -07008821 if (sComparisonStrategy == COMPARISON_STRATEGY_STRIPE) {
8822 // First is above second.
Phil Weaver86b32602018-05-10 18:00:18 -07008823 if (holder1.mLocation.bottom - holder2.mLocation.top <= 0) {
Svetoslav88e447b2014-10-09 15:49:02 -07008824 return -1;
8825 }
8826 // First is below second.
Phil Weaver86b32602018-05-10 18:00:18 -07008827 if (holder1.mLocation.top - holder2.mLocation.bottom >= 0) {
Svetoslav88e447b2014-10-09 15:49:02 -07008828 return 1;
8829 }
8830 }
8831
Svetoslav04cab1b2014-08-25 18:35:57 -07008832 // We are ordering left-to-right, top-to-bottom.
Phil Weaver86b32602018-05-10 18:00:18 -07008833 if (holder1.mLayoutDirection == LAYOUT_DIRECTION_LTR) {
8834 final int leftDifference = holder1.mLocation.left - holder2.mLocation.left;
Svetoslav Ganov42138042012-03-20 11:51:39 -07008835 if (leftDifference != 0) {
8836 return leftDifference;
8837 }
8838 } else { // RTL
Phil Weaver86b32602018-05-10 18:00:18 -07008839 final int rightDifference = holder1.mLocation.right - holder2.mLocation.right;
Svetoslav Ganov42138042012-03-20 11:51:39 -07008840 if (rightDifference != 0) {
8841 return -rightDifference;
8842 }
8843 }
Svetoslav04cab1b2014-08-25 18:35:57 -07008844 // We are ordering left-to-right, top-to-bottom.
Phil Weaver86b32602018-05-10 18:00:18 -07008845 final int topDifference = holder1.mLocation.top - holder2.mLocation.top;
Svetoslav04cab1b2014-08-25 18:35:57 -07008846 if (topDifference != 0) {
8847 return topDifference;
8848 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07008849 // Break tie by height.
Phil Weaver86b32602018-05-10 18:00:18 -07008850 final int heightDiference = holder1.mLocation.height() - holder2.mLocation.height();
Svetoslav Ganov42138042012-03-20 11:51:39 -07008851 if (heightDiference != 0) {
8852 return -heightDiference;
8853 }
8854 // Break tie by width.
Phil Weaver86b32602018-05-10 18:00:18 -07008855 final int widthDifference = holder1.mLocation.width() - holder2.mLocation.width();
8856 if (widthDifference != 0) {
8857 return -widthDifference;
Svetoslav Ganov42138042012-03-20 11:51:39 -07008858 }
Phil Weaver86b32602018-05-10 18:00:18 -07008859
8860 // Find a child of each view with different screen bounds.
8861 final Rect view1Bounds = new Rect();
8862 final Rect view2Bounds = new Rect();
8863 final Rect tempRect = new Rect();
8864 holder1.mView.getBoundsOnScreen(view1Bounds, true);
8865 holder2.mView.getBoundsOnScreen(view2Bounds, true);
8866 final View child1 = holder1.mView.findViewByPredicateTraversal((view) -> {
8867 view.getBoundsOnScreen(tempRect, true);
8868 return !tempRect.equals(view1Bounds);
8869 }, null);
8870 final View child2 = holder2.mView.findViewByPredicateTraversal((view) -> {
8871 view.getBoundsOnScreen(tempRect, true);
8872 return !tempRect.equals(view2Bounds);
8873 }, null);
8874
8875
8876 // Compare the children recursively
8877 if ((child1 != null) && (child2 != null)) {
8878 final ViewLocationHolder childHolder1 =
8879 ViewLocationHolder.obtain(holder1.mRoot, child1);
8880 final ViewLocationHolder childHolder2 =
8881 ViewLocationHolder.obtain(holder1.mRoot, child2);
8882 return compareBoundsOfTree(childHolder1, childHolder2);
8883 }
8884
8885 // If only one has a child, use that one
8886 if (child1 != null) {
8887 return 1;
8888 }
8889
8890 if (child2 != null) {
8891 return -1;
8892 }
8893
8894 // Give up
8895 return 0;
Svetoslav Ganov42138042012-03-20 11:51:39 -07008896 }
8897
8898 private void init(ViewGroup root, View view) {
8899 Rect viewLocation = mLocation;
8900 view.getDrawingRect(viewLocation);
8901 root.offsetDescendantRectToMyCoords(view, viewLocation);
8902 mView = view;
Phil Weaver86b32602018-05-10 18:00:18 -07008903 mRoot = root;
Fabrice Di Meglioe56ffdc2012-09-23 14:51:16 -07008904 mLayoutDirection = root.getLayoutDirection();
Svetoslav Ganov42138042012-03-20 11:51:39 -07008905 }
8906
8907 private void clear() {
8908 mView = null;
Phil Weaver6adf3a12018-08-21 16:08:42 -07008909 mRoot = null;
Svetoslav Ganov42138042012-03-20 11:51:39 -07008910 mLocation.set(0, 0, 0, 0);
8911 }
8912 }
Romain Guycbc67742012-04-27 16:12:57 -07008913
Romain Guy6410c0a2013-06-17 11:21:58 -07008914 private static void drawRect(Canvas canvas, Paint paint, int x1, int y1, int x2, int y2) {
Romain Guycbc67742012-04-27 16:12:57 -07008915 if (sDebugLines== null) {
Romain Guy6410c0a2013-06-17 11:21:58 -07008916 // TODO: This won't work with multiple UI threads in a single process
Romain Guycbc67742012-04-27 16:12:57 -07008917 sDebugLines = new float[16];
8918 }
8919
Romain Guycbc67742012-04-27 16:12:57 -07008920 sDebugLines[0] = x1;
8921 sDebugLines[1] = y1;
8922 sDebugLines[2] = x2;
8923 sDebugLines[3] = y1;
8924
8925 sDebugLines[4] = x2;
8926 sDebugLines[5] = y1;
8927 sDebugLines[6] = x2;
Philip Milne7b757812012-09-19 18:13:44 -07008928 sDebugLines[7] = y2;
Romain Guycbc67742012-04-27 16:12:57 -07008929
Philip Milne7b757812012-09-19 18:13:44 -07008930 sDebugLines[8] = x2;
Romain Guycbc67742012-04-27 16:12:57 -07008931 sDebugLines[9] = y2;
8932 sDebugLines[10] = x1;
8933 sDebugLines[11] = y2;
8934
Philip Milne7b757812012-09-19 18:13:44 -07008935 sDebugLines[12] = x1;
8936 sDebugLines[13] = y2;
Romain Guycbc67742012-04-27 16:12:57 -07008937 sDebugLines[14] = x1;
8938 sDebugLines[15] = y1;
8939
Philip Milne7b757812012-09-19 18:13:44 -07008940 canvas.drawLines(sDebugLines, paint);
Romain Guycbc67742012-04-27 16:12:57 -07008941 }
Siva Velusamy0d857b92015-04-22 10:23:56 -07008942
8943 /** @hide */
8944 @Override
Mathew Inwooda570dee2018-08-17 14:56:00 +01008945 @UnsupportedAppUsage
Siva Velusamy0d857b92015-04-22 10:23:56 -07008946 protected void encodeProperties(@NonNull ViewHierarchyEncoder encoder) {
8947 super.encodeProperties(encoder);
8948
8949 encoder.addProperty("focus:descendantFocusability", getDescendantFocusability());
8950 encoder.addProperty("drawing:clipChildren", getClipChildren());
8951 encoder.addProperty("drawing:clipToPadding", getClipToPadding());
8952 encoder.addProperty("drawing:childrenDrawingOrderEnabled", isChildrenDrawingOrderEnabled());
8953 encoder.addProperty("drawing:persistentDrawingCache", getPersistentDrawingCache());
8954
8955 int n = getChildCount();
8956 encoder.addProperty("meta:__childCount__", (short)n);
8957 for (int i = 0; i < n; i++) {
8958 encoder.addPropertyKey("meta:__child__" + i);
8959 getChildAt(i).encode(encoder);
8960 }
8961 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008962}