blob: 379ef5b18dc7c0fa9658099788caa4d657828ea2 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.view;
18
Aurimas Liutikas67e2ae82016-10-11 18:17:42 -070019import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
20
Chet Haase21cd1382010-09-01 17:42:29 -070021import android.animation.LayoutTransition;
Chris Craik9de95db2017-01-18 17:59:23 -080022import android.annotation.CallSuper;
Tor Norbye7b9c9122013-05-30 16:48:33 -070023import android.annotation.IdRes;
Alan Viverette922e1c62015-05-05 17:18:27 -070024import android.annotation.NonNull;
Evan Rosky3ac64632017-02-13 18:04:43 -080025import android.annotation.TestApi;
Tor Norbye83c68962015-03-10 20:55:31 -070026import android.annotation.UiThread;
Vadim Trysheva61efa42016-09-28 15:15:52 -070027import android.content.ClipData;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028import android.content.Context;
Clara Bayarrid5bf3ed2015-03-27 17:32:45 +000029import android.content.Intent;
Adam Powellff0d2982014-07-10 20:34:14 -070030import android.content.pm.PackageManager;
Dianne Hackborne36d6e22010-02-17 19:46:25 -080031import android.content.res.Configuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032import android.content.res.TypedArray;
33import android.graphics.Bitmap;
34import android.graphics.Canvas;
Philip Milne10ca24a2012-04-23 15:38:27 -070035import android.graphics.Color;
36import android.graphics.Insets;
Adam Powell6e346362010-07-23 10:18:23 -070037import android.graphics.Matrix;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038import android.graphics.Paint;
Christopher Tatea53146c2010-09-07 11:57:52 -070039import android.graphics.PointF;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040import android.graphics.Rect;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041import android.graphics.RectF;
svetoslavganov75986cf2009-05-14 22:28:01 -070042import android.graphics.Region;
Jeff Brown995e7742010-12-22 16:59:36 -080043import android.os.Build;
Adam Powellb6ab0982015-01-07 17:00:12 -080044import android.os.Bundle;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045import android.os.Parcelable;
46import android.os.SystemClock;
47import android.util.AttributeSet;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048import android.util.Log;
Svet Ganov2f8fb1f2017-03-13 00:21:04 -070049import android.util.Pools;
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -080050import android.util.Pools.SynchronizedPool;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051import android.util.SparseArray;
Dianne Hackborn6ff55fc2015-08-05 18:07:31 -070052import android.util.SparseBooleanArray;
svetoslavganov75986cf2009-05-14 22:28:01 -070053import android.view.accessibility.AccessibilityEvent;
Phil Weaver4d3eec412016-09-01 16:28:34 -070054import android.view.accessibility.AccessibilityManager;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070055import android.view.accessibility.AccessibilityNodeInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056import android.view.animation.Animation;
57import android.view.animation.AnimationUtils;
58import android.view.animation.LayoutAnimationController;
59import android.view.animation.Transformation;
Chet Haasecb3d0232017-05-24 18:27:14 -070060
Romain Guy0211a0a2011-02-14 16:34:59 -080061import com.android.internal.R;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062
63import java.util.ArrayList;
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -080064import java.util.Collection;
Svetoslav Ganov42138042012-03-20 11:51:39 -070065import java.util.Collections;
Christopher Tate86cab1b2011-01-13 20:28:55 -080066import java.util.HashSet;
George Mounte1803372014-02-26 19:00:52 +000067import java.util.List;
68import java.util.Map;
Paul Duffinca4964c2017-02-07 15:04:10 +000069import java.util.function.Predicate;
Keisuke Kuroyanagid85bc502016-01-21 14:50:38 +090070
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080071/**
72 * <p>
73 * A <code>ViewGroup</code> is a special view that can contain other views
74 * (called children.) The view group is the base class for layouts and views
75 * containers. This class also defines the
76 * {@link android.view.ViewGroup.LayoutParams} class which serves as the base
77 * class for layouts parameters.
78 * </p>
79 *
80 * <p>
81 * Also see {@link LayoutParams} for layout attributes.
82 * </p>
Romain Guyd6a463a2009-05-21 23:10:10 -070083 *
Joe Fernandez558459f2011-10-13 16:47:36 -070084 * <div class="special reference">
85 * <h3>Developer Guides</h3>
86 * <p>For more information about creating user interface layouts, read the
87 * <a href="{@docRoot}guide/topics/ui/declaring-layout.html">XML Layouts</a> developer
88 * guide.</p></div>
89 *
Dianne Hackborn7caab0f2013-03-06 13:47:04 -080090 * <p>Here is a complete implementation of a custom ViewGroup that implements
91 * a simple {@link android.widget.FrameLayout} along with the ability to stack
92 * children in left and right gutters.</p>
93 *
94 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/CustomLayout.java
95 * Complete}
96 *
97 * <p>If you are implementing XML layout attributes as shown in the example, this is the
98 * corresponding definition for them that would go in <code>res/values/attrs.xml</code>:</p>
99 *
100 * {@sample development/samples/ApiDemos/res/values/attrs.xml CustomLayout}
101 *
102 * <p>Finally the layout manager can be used in an XML layout like so:</p>
103 *
104 * {@sample development/samples/ApiDemos/res/layout/custom_layout.xml Complete}
105 *
Romain Guyd6a463a2009-05-21 23:10:10 -0700106 * @attr ref android.R.styleable#ViewGroup_clipChildren
107 * @attr ref android.R.styleable#ViewGroup_clipToPadding
108 * @attr ref android.R.styleable#ViewGroup_layoutAnimation
109 * @attr ref android.R.styleable#ViewGroup_animationCache
110 * @attr ref android.R.styleable#ViewGroup_persistentDrawingCache
111 * @attr ref android.R.styleable#ViewGroup_alwaysDrawnWithCache
112 * @attr ref android.R.styleable#ViewGroup_addStatesFromChildren
113 * @attr ref android.R.styleable#ViewGroup_descendantFocusability
Chet Haase13cc1202010-09-03 15:39:20 -0700114 * @attr ref android.R.styleable#ViewGroup_animateLayoutChanges
Scott Main27a85082013-06-10 10:39:48 -0700115 * @attr ref android.R.styleable#ViewGroup_splitMotionEvents
116 * @attr ref android.R.styleable#ViewGroup_layoutMode
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800117 */
Tor Norbye83c68962015-03-10 20:55:31 -0700118@UiThread
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800119public abstract class ViewGroup extends View implements ViewParent, ViewManager {
Adam Powell539ee872012-02-03 19:00:49 -0800120 private static final String TAG = "ViewGroup";
Chet Haase21cd1382010-09-01 17:42:29 -0700121
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800122 private static final boolean DBG = false;
Gilles Debunnecea45132011-11-24 02:19:27 +0100123
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800124 /**
125 * Views which have been hidden or removed which need to be animated on
126 * their way out.
127 * This field should be made private, so it is hidden from the SDK.
128 * {@hide}
129 */
130 protected ArrayList<View> mDisappearingChildren;
131
132 /**
133 * Listener used to propagate events indicating when children are added
134 * and/or removed from a view group.
135 * This field should be made private, so it is hidden from the SDK.
136 * {@hide}
137 */
138 protected OnHierarchyChangeListener mOnHierarchyChangeListener;
139
140 // The view contained within this ViewGroup that has or contains focus.
141 private View mFocused;
Vadim Tryshev5ca73982017-01-04 17:24:43 -0800142 // The view contained within this ViewGroup (excluding nested keyboard navigation clusters)
143 // that is or contains a default-focus view.
144 private View mDefaultFocus;
Evan Rosky53fcf112017-01-26 14:37:55 -0800145 // The last child of this ViewGroup which held focus within the current cluster
Evan Rosky6c286be2017-04-19 17:23:32 -0700146 View mFocusedInCluster;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800147
Chet Haase48460322010-06-11 14:22:25 -0700148 /**
149 * A Transformation used when drawing children, to
150 * apply on the child being drawn.
151 */
Romain Guyf6991302013-06-05 17:19:01 -0700152 private Transformation mChildTransformation;
Chet Haase48460322010-06-11 14:22:25 -0700153
154 /**
155 * Used to track the current invalidation region.
156 */
Chet Haase64a48c12012-02-13 16:33:29 -0800157 RectF mInvalidateRegion;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800158
Chet Haase48460322010-06-11 14:22:25 -0700159 /**
160 * A Transformation used to calculate a correct
161 * invalidation area when the application is autoscaled.
162 */
Chet Haase64a48c12012-02-13 16:33:29 -0800163 Transformation mInvalidationTransformation;
Chet Haase48460322010-06-11 14:22:25 -0700164
Vadim Tryshevef128112016-09-16 14:05:53 -0700165 // Current frontmost child that can accept drag and lies under the drag location.
166 // Used only to generate ENTER/EXIT events for pre-Nougat aps.
167 private View mCurrentDragChild;
168
Christopher Tate86cab1b2011-01-13 20:28:55 -0800169 // Metadata about the ongoing drag
Vadim Tryshev1a68dc92015-07-20 17:01:50 -0700170 private DragEvent mCurrentDragStartEvent;
171 private boolean mIsInterestedInDrag;
172 private HashSet<View> mChildrenInterestedInDrag;
Christopher Tatea53146c2010-09-07 11:57:52 -0700173
174 // Used during drag dispatch
Romain Guy6410c0a2013-06-17 11:21:58 -0700175 private PointF mLocalPoint;
Christopher Tatea53146c2010-09-07 11:57:52 -0700176
Alan Viveretteb942b6f2014-12-08 10:37:39 -0800177 // Lazily-created holder for point computations.
178 private float[] mTempPoint;
179
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800180 // Layout animation
181 private LayoutAnimationController mLayoutAnimationController;
182 private Animation.AnimationListener mAnimationListener;
183
Jeff Brown20e987b2010-08-23 12:01:02 -0700184 // First touch target in the linked list of touch targets.
185 private TouchTarget mFirstTouchTarget;
186
Joe Onorato03ab0c72011-01-06 15:46:27 -0800187 // For debugging only. You can see these in hierarchyviewer.
Romain Guye95003e2011-01-09 13:53:06 -0800188 @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
Joe Onorato03ab0c72011-01-06 15:46:27 -0800189 @ViewDebug.ExportedProperty(category = "events")
190 private long mLastTouchDownTime;
191 @ViewDebug.ExportedProperty(category = "events")
192 private int mLastTouchDownIndex = -1;
Romain Guye95003e2011-01-09 13:53:06 -0800193 @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
Joe Onorato03ab0c72011-01-06 15:46:27 -0800194 @ViewDebug.ExportedProperty(category = "events")
195 private float mLastTouchDownX;
Romain Guye95003e2011-01-09 13:53:06 -0800196 @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
Joe Onorato03ab0c72011-01-06 15:46:27 -0800197 @ViewDebug.ExportedProperty(category = "events")
198 private float mLastTouchDownY;
199
Jeff Brown87b7f802011-06-21 18:35:45 -0700200 // First hover target in the linked list of hover targets.
201 // The hover targets are children which have received ACTION_HOVER_ENTER.
202 // They might not have actually handled the hover event, but we will
203 // continue sending hover events to them as long as the pointer remains over
204 // their bounds and the view group does not intercept hover.
205 private HoverTarget mFirstHoverTarget;
Jeff Browna032cc02011-03-07 16:56:21 -0800206
Jeff Brown10b62902011-06-20 16:40:37 -0700207 // True if the view group itself received a hover event.
208 // It might not have actually handled the hover event.
209 private boolean mHoveredSelf;
210
Vladislav Kaznacheevf847ee32016-11-21 14:11:00 -0800211 // The child capable of showing a tooltip and currently under the pointer.
212 private View mTooltipHoverTarget;
213
214 // True if the view group is capable of showing a tooltip and the pointer is directly
215 // over the view group but not one of its child views.
216 private boolean mTooltipHoveredSelf;
217
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800218 /**
219 * Internal flags.
Romain Guy8506ab42009-06-11 17:35:47 -0700220 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800221 * This field should be made private, so it is hidden from the SDK.
222 * {@hide}
223 */
Romain Guy2440e672012-08-07 14:43:43 -0700224 @ViewDebug.ExportedProperty(flagMapping = {
225 @ViewDebug.FlagToString(mask = FLAG_CLIP_CHILDREN, equals = FLAG_CLIP_CHILDREN,
226 name = "CLIP_CHILDREN"),
227 @ViewDebug.FlagToString(mask = FLAG_CLIP_TO_PADDING, equals = FLAG_CLIP_TO_PADDING,
228 name = "CLIP_TO_PADDING"),
229 @ViewDebug.FlagToString(mask = FLAG_PADDING_NOT_NULL, equals = FLAG_PADDING_NOT_NULL,
230 name = "PADDING_NOT_NULL")
Jon Miranda4597e982014-07-29 07:25:49 -0700231 }, formatToHexString = true)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800232 protected int mGroupFlags;
233
Philip Milne7b757812012-09-19 18:13:44 -0700234 /**
235 * Either {@link #LAYOUT_MODE_CLIP_BOUNDS} or {@link #LAYOUT_MODE_OPTICAL_BOUNDS}.
Philip Milne1557fd72012-04-04 23:41:34 -0700236 */
Philip Milnecfb631b2012-10-26 10:51:46 -0700237 private int mLayoutMode = LAYOUT_MODE_UNDEFINED;
Philip Milne1557fd72012-04-04 23:41:34 -0700238
Romain Guy33f6beb2012-02-16 19:24:51 -0800239 /**
240 * NOTE: If you change the flags below make sure to reflect the changes
241 * the DisplayList class
242 */
Filip Gruszczynskia33bdf32015-11-19 18:22:16 -0800243
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800244 // When set, ViewGroup invalidates only the child's rectangle
245 // Set by default
Chet Haase64a48c12012-02-13 16:33:29 -0800246 static final int FLAG_CLIP_CHILDREN = 0x1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800247
248 // When set, ViewGroup excludes the padding area from the invalidate rectangle
249 // Set by default
250 private static final int FLAG_CLIP_TO_PADDING = 0x2;
251
252 // When set, dispatchDraw() will invoke invalidate(); this is set by drawChild() when
253 // a child needs to be invalidated and FLAG_OPTIMIZE_INVALIDATE is set
Chet Haase64a48c12012-02-13 16:33:29 -0800254 static final int FLAG_INVALIDATE_REQUIRED = 0x4;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800255
256 // When set, dispatchDraw() will run the layout animation and unset the flag
257 private static final int FLAG_RUN_ANIMATION = 0x8;
258
259 // When set, there is either no layout animation on the ViewGroup or the layout
260 // animation is over
261 // Set by default
Chet Haase64a48c12012-02-13 16:33:29 -0800262 static final int FLAG_ANIMATION_DONE = 0x10;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800263
264 // If set, this ViewGroup has padding; if unset there is no padding and we don't need
265 // to clip it, even if FLAG_CLIP_TO_PADDING is set
266 private static final int FLAG_PADDING_NOT_NULL = 0x20;
267
Chris Craik5a6bbae2015-04-10 17:41:34 -0700268 /** @deprecated - functionality removed */
Aurimas Liutikas514c5ef2016-05-24 15:22:55 -0700269 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800270 private static final int FLAG_ANIMATION_CACHE = 0x40;
271
272 // When set, this ViewGroup converts calls to invalidate(Rect) to invalidate() during a
273 // layout animation; this avoid clobbering the hierarchy
274 // Automatically set when the layout animation starts, depending on the animation's
275 // characteristics
Chet Haase64a48c12012-02-13 16:33:29 -0800276 static final int FLAG_OPTIMIZE_INVALIDATE = 0x80;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800277
278 // When set, the next call to drawChild() will clear mChildTransformation's matrix
Chet Haase64a48c12012-02-13 16:33:29 -0800279 static final int FLAG_CLEAR_TRANSFORMATION = 0x100;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800280
281 // When set, this ViewGroup invokes mAnimationListener.onAnimationEnd() and removes
282 // the children's Bitmap caches if necessary
283 // This flag is set when the layout animation is over (after FLAG_ANIMATION_DONE is set)
284 private static final int FLAG_NOTIFY_ANIMATION_LISTENER = 0x200;
285
286 /**
287 * When set, the drawing method will call {@link #getChildDrawingOrder(int, int)}
288 * to get the index of the child to draw for that iteration.
Filip Gruszczynskia33bdf32015-11-19 18:22:16 -0800289 *
Romain Guy293451e2009-11-04 13:59:48 -0800290 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800291 */
292 protected static final int FLAG_USE_CHILD_DRAWING_ORDER = 0x400;
Romain Guy8506ab42009-06-11 17:35:47 -0700293
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800294 /**
295 * When set, this ViewGroup supports static transformations on children; this causes
296 * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} to be
297 * invoked when a child is drawn.
298 *
299 * Any subclass overriding
300 * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} should
301 * set this flags in {@link #mGroupFlags}.
Romain Guy8506ab42009-06-11 17:35:47 -0700302 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800303 * {@hide}
304 */
305 protected static final int FLAG_SUPPORT_STATIC_TRANSFORMATIONS = 0x800;
306
John Reckfb5899d2014-08-15 18:51:27 -0700307 // UNUSED FLAG VALUE: 0x1000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800308
309 /**
310 * When set, this ViewGroup's drawable states also include those
311 * of its children.
312 */
313 private static final int FLAG_ADD_STATES_FROM_CHILDREN = 0x2000;
314
Chris Craik5a6bbae2015-04-10 17:41:34 -0700315 /** @deprecated functionality removed */
Aurimas Liutikas514c5ef2016-05-24 15:22:55 -0700316 @Deprecated
Chris Craik5a6bbae2015-04-10 17:41:34 -0700317 private static final int FLAG_ALWAYS_DRAWN_WITH_CACHE = 0x4000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800318
Chris Craik5a6bbae2015-04-10 17:41:34 -0700319 /** @deprecated functionality removed */
Aurimas Liutikas514c5ef2016-05-24 15:22:55 -0700320 @Deprecated
Chris Craik5a6bbae2015-04-10 17:41:34 -0700321 private static final int FLAG_CHILDREN_DRAWN_WITH_CACHE = 0x8000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800322
323 /**
324 * When set, this group will go through its list of children to notify them of
325 * any drawable state change.
326 */
327 private static final int FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE = 0x10000;
328
329 private static final int FLAG_MASK_FOCUSABILITY = 0x60000;
330
331 /**
332 * This view will get focus before any of its descendants.
333 */
334 public static final int FOCUS_BEFORE_DESCENDANTS = 0x20000;
335
336 /**
337 * This view will get focus only if none of its descendants want it.
338 */
339 public static final int FOCUS_AFTER_DESCENDANTS = 0x40000;
340
341 /**
342 * This view will block any of its descendants from getting focus, even
343 * if they are focusable.
344 */
345 public static final int FOCUS_BLOCK_DESCENDANTS = 0x60000;
346
347 /**
348 * Used to map between enum in attrubutes and flag values.
349 */
350 private static final int[] DESCENDANT_FOCUSABILITY_FLAGS =
351 {FOCUS_BEFORE_DESCENDANTS, FOCUS_AFTER_DESCENDANTS,
352 FOCUS_BLOCK_DESCENDANTS};
353
354 /**
355 * When set, this ViewGroup should not intercept touch events.
Adam Powell110486f2010-06-22 17:14:44 -0700356 * {@hide}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800357 */
Adam Powell110486f2010-06-22 17:14:44 -0700358 protected static final int FLAG_DISALLOW_INTERCEPT = 0x80000;
Romain Guy8506ab42009-06-11 17:35:47 -0700359
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800360 /**
Adam Powell2b342f02010-08-18 18:14:13 -0700361 * When set, this ViewGroup will split MotionEvents to multiple child Views when appropriate.
362 */
Adam Powellf37df072010-09-17 16:22:49 -0700363 private static final int FLAG_SPLIT_MOTION_EVENTS = 0x200000;
Adam Powell2b342f02010-08-18 18:14:13 -0700364
365 /**
Adam Powell4b867882011-09-16 12:59:46 -0700366 * When set, this ViewGroup will not dispatch onAttachedToWindow calls
367 * to children when adding new views. This is used to prevent multiple
368 * onAttached calls when a ViewGroup adds children in its own onAttached method.
369 */
370 private static final int FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW = 0x400000;
371
372 /**
Philip Milnecfb631b2012-10-26 10:51:46 -0700373 * When true, indicates that a layoutMode has been explicitly set, either with
374 * an explicit call to {@link #setLayoutMode(int)} in code or from an XML resource.
375 * This distinguishes the situation in which a layout mode was inherited from
376 * one of the ViewGroup's ancestors and cached locally.
377 */
378 private static final int FLAG_LAYOUT_MODE_WAS_EXPLICITLY_SET = 0x800000;
379
Chris Craikb49f4462014-03-20 12:44:20 -0700380 static final int FLAG_IS_TRANSITION_GROUP = 0x1000000;
Chris Craikd863a102013-12-19 13:31:15 -0800381
Chris Craikb49f4462014-03-20 12:44:20 -0700382 static final int FLAG_IS_TRANSITION_GROUP_SET = 0x2000000;
George Mount0a778ed2013-12-13 13:35:36 -0800383
Chris Craikd863a102013-12-19 13:31:15 -0800384 /**
Adam Powellff0d2982014-07-10 20:34:14 -0700385 * When set, focus will not be permitted to enter this group if a touchscreen is present.
386 */
387 static final int FLAG_TOUCHSCREEN_BLOCKS_FOCUS = 0x4000000;
388
389 /**
Clara Bayarri4423d912015-03-02 19:42:48 +0000390 * When true, indicates that a call to startActionModeForChild was made with the type parameter
391 * and should not be ignored. This helps in backwards compatibility with the existing method
392 * without a type.
393 *
394 * @see #startActionModeForChild(View, android.view.ActionMode.Callback)
395 * @see #startActionModeForChild(View, android.view.ActionMode.Callback, int)
396 */
397 private static final int FLAG_START_ACTION_MODE_FOR_CHILD_IS_TYPED = 0x8000000;
398
399 /**
400 * When true, indicates that a call to startActionModeForChild was made without the type
401 * parameter. This helps in backwards compatibility with the existing method
402 * without a type.
403 *
404 * @see #startActionModeForChild(View, android.view.ActionMode.Callback)
405 * @see #startActionModeForChild(View, android.view.ActionMode.Callback, int)
406 */
407 private static final int FLAG_START_ACTION_MODE_FOR_CHILD_IS_NOT_TYPED = 0x10000000;
408
409 /**
Adam Powell2af189a2016-02-05 15:52:02 -0800410 * When set, indicates that a call to showContextMenuForChild was made with explicit
411 * coordinates within the initiating child view.
412 */
413 private static final int FLAG_SHOW_CONTEXT_MENU_WITH_COORDS = 0x20000000;
414
415 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800416 * Indicates which types of drawing caches are to be kept in memory.
417 * This field should be made private, so it is hidden from the SDK.
418 * {@hide}
419 */
420 protected int mPersistentDrawingCache;
421
422 /**
423 * Used to indicate that no drawing cache should be kept in memory.
424 */
425 public static final int PERSISTENT_NO_CACHE = 0x0;
426
427 /**
428 * Used to indicate that the animation drawing cache should be kept in memory.
429 */
430 public static final int PERSISTENT_ANIMATION_CACHE = 0x1;
431
432 /**
433 * Used to indicate that the scrolling drawing cache should be kept in memory.
434 */
435 public static final int PERSISTENT_SCROLLING_CACHE = 0x2;
436
437 /**
438 * Used to indicate that all drawing caches should be kept in memory.
439 */
440 public static final int PERSISTENT_ALL_CACHES = 0x3;
441
Philip Milne1557fd72012-04-04 23:41:34 -0700442 // Layout Modes
443
Philip Milnecfb631b2012-10-26 10:51:46 -0700444 private static final int LAYOUT_MODE_UNDEFINED = -1;
445
Philip Milne1557fd72012-04-04 23:41:34 -0700446 /**
447 * This constant is a {@link #setLayoutMode(int) layoutMode}.
Philip Milne7a23b492012-04-24 22:12:36 -0700448 * Clip bounds are the raw values of {@link #getLeft() left}, {@link #getTop() top},
Philip Milne1557fd72012-04-04 23:41:34 -0700449 * {@link #getRight() right} and {@link #getBottom() bottom}.
450 */
Philip Milne7b757812012-09-19 18:13:44 -0700451 public static final int LAYOUT_MODE_CLIP_BOUNDS = 0;
Philip Milne1557fd72012-04-04 23:41:34 -0700452
453 /**
454 * This constant is a {@link #setLayoutMode(int) layoutMode}.
Philip Milne7a23b492012-04-24 22:12:36 -0700455 * Optical bounds describe where a widget appears to be. They sit inside the clip
456 * bounds which need to cover a larger area to allow other effects,
457 * such as shadows and glows, to be drawn.
Philip Milne1557fd72012-04-04 23:41:34 -0700458 */
Philip Milne7b757812012-09-19 18:13:44 -0700459 public static final int LAYOUT_MODE_OPTICAL_BOUNDS = 1;
460
461 /** @hide */
Philip Milnecfb631b2012-10-26 10:51:46 -0700462 public static int LAYOUT_MODE_DEFAULT = LAYOUT_MODE_CLIP_BOUNDS;
Philip Milne1557fd72012-04-04 23:41:34 -0700463
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800464 /**
465 * We clip to padding when FLAG_CLIP_TO_PADDING and FLAG_PADDING_NOT_NULL
466 * are set at the same time.
467 */
468 protected static final int CLIP_TO_PADDING_MASK = FLAG_CLIP_TO_PADDING | FLAG_PADDING_NOT_NULL;
469
470 // Index of the child's left position in the mLocation array
471 private static final int CHILD_LEFT_INDEX = 0;
472 // Index of the child's top position in the mLocation array
473 private static final int CHILD_TOP_INDEX = 1;
474
475 // Child views of this ViewGroup
476 private View[] mChildren;
477 // Number of valid children in the mChildren array, the rest should be null or not
478 // considered as children
479 private int mChildrenCount;
480
Chet Haaseb9895022013-04-02 15:10:58 -0700481 // Whether layout calls are currently being suppressed, controlled by calls to
482 // suppressLayout()
483 boolean mSuppressLayout = false;
484
485 // Whether any layout calls have actually been suppressed while mSuppressLayout
486 // has been true. This tracks whether we need to issue a requestLayout() when
487 // layout is later re-enabled.
488 private boolean mLayoutCalledWhileSuppressed = false;
489
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800490 private static final int ARRAY_INITIAL_CAPACITY = 12;
491 private static final int ARRAY_CAPACITY_INCREMENT = 12;
492
Romain Guycbc67742012-04-27 16:12:57 -0700493 private static float[] sDebugLines;
Philip Milne604f4402012-04-24 19:27:11 -0700494
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800495 // Used to draw cached views
Chet Haase64a48c12012-02-13 16:33:29 -0800496 Paint mCachePaint;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800497
Chet Haase21cd1382010-09-01 17:42:29 -0700498 // Used to animate add/remove changes in layout
499 private LayoutTransition mTransition;
500
501 // The set of views that are currently being transitioned. This list is used to track views
502 // being removed that should not actually be removed from the parent yet because they are
503 // being animated.
504 private ArrayList<View> mTransitioningViews;
505
Chet Haase5e25c2c2010-09-16 11:15:56 -0700506 // List of children changing visibility. This is used to potentially keep rendering
507 // views during a transition when they otherwise would have become gone/invisible
508 private ArrayList<View> mVisibilityChangingChildren;
509
Chris Craikab008f02014-05-23 17:55:03 -0700510 // Temporary holder of presorted children, only used for
511 // input/software draw dispatch for correctly Z ordering.
512 private ArrayList<View> mPreSortedChildren;
513
Adam Powell539ee872012-02-03 19:00:49 -0800514 // Indicates how many of this container's child subtrees contain transient state
515 @ViewDebug.ExportedProperty(category = "layout")
516 private int mChildCountWithTransientState = 0;
517
Adam Powell10ba2772014-04-15 09:46:51 -0700518 /**
519 * Currently registered axes for nested scrolling. Flag set consisting of
520 * {@link #SCROLL_AXIS_HORIZONTAL} {@link #SCROLL_AXIS_VERTICAL} or {@link #SCROLL_AXIS_NONE}
521 * for null.
522 */
523 private int mNestedScrollAxes;
524
Chet Haasec633d2f2015-04-07 10:29:39 -0700525 // Used to manage the list of transient views, added by addTransientView()
526 private List<Integer> mTransientIndices = null;
527 private List<View> mTransientViews = null;
528
529
Clara Bayarri4423d912015-03-02 19:42:48 +0000530 /**
531 * Empty ActionMode used as a sentinel in recursive entries to startActionModeForChild.
532 *
533 * @see #startActionModeForChild(View, android.view.ActionMode.Callback)
534 * @see #startActionModeForChild(View, android.view.ActionMode.Callback, int)
535 */
536 private static final ActionMode SENTINEL_ACTION_MODE = new ActionMode() {
537 @Override
538 public void setTitle(CharSequence title) {}
539
540 @Override
541 public void setTitle(int resId) {}
542
543 @Override
544 public void setSubtitle(CharSequence subtitle) {}
545
546 @Override
547 public void setSubtitle(int resId) {}
548
549 @Override
550 public void setCustomView(View view) {}
551
552 @Override
553 public void invalidate() {}
554
555 @Override
556 public void finish() {}
557
558 @Override
559 public Menu getMenu() {
560 return null;
561 }
562
563 @Override
564 public CharSequence getTitle() {
565 return null;
566 }
567
568 @Override
569 public CharSequence getSubtitle() {
570 return null;
571 }
572
573 @Override
574 public View getCustomView() {
575 return null;
576 }
577
578 @Override
579 public MenuInflater getMenuInflater() {
580 return null;
581 }
582 };
583
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800584 public ViewGroup(Context context) {
Alan Viveretted6479ec2013-09-10 17:03:02 -0700585 this(context, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800586 }
587
588 public ViewGroup(Context context, AttributeSet attrs) {
Alan Viveretted6479ec2013-09-10 17:03:02 -0700589 this(context, attrs, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800590 }
591
Alan Viverette617feb92013-09-09 18:09:13 -0700592 public ViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {
Alan Viveretted6479ec2013-09-10 17:03:02 -0700593 this(context, attrs, defStyleAttr, 0);
Alan Viverette617feb92013-09-09 18:09:13 -0700594 }
595
596 public ViewGroup(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
597 super(context, attrs, defStyleAttr, defStyleRes);
Felipe Lemed04a6972017-03-02 12:56:18 -0800598
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800599 initViewGroup();
Alan Viveretted6479ec2013-09-10 17:03:02 -0700600 initFromAttributes(context, attrs, defStyleAttr, defStyleRes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800601 }
602
603 private void initViewGroup() {
604 // ViewGroup doesn't draw by default
Philip Milne10ca24a2012-04-23 15:38:27 -0700605 if (!debugDraw()) {
606 setFlags(WILL_NOT_DRAW, DRAW_MASK);
607 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800608 mGroupFlags |= FLAG_CLIP_CHILDREN;
609 mGroupFlags |= FLAG_CLIP_TO_PADDING;
610 mGroupFlags |= FLAG_ANIMATION_DONE;
Chris Craikf6ce8fd2015-05-11 15:33:11 -0700611 mGroupFlags |= FLAG_ANIMATION_CACHE;
612 mGroupFlags |= FLAG_ALWAYS_DRAWN_WITH_CACHE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800613
Jeff Brown995e7742010-12-22 16:59:36 -0800614 if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB) {
615 mGroupFlags |= FLAG_SPLIT_MOTION_EVENTS;
616 }
617
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800618 setDescendantFocusability(FOCUS_BEFORE_DESCENDANTS);
619
620 mChildren = new View[ARRAY_INITIAL_CAPACITY];
621 mChildrenCount = 0;
622
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800623 mPersistentDrawingCache = PERSISTENT_SCROLLING_CACHE;
624 }
625
Alan Viveretted6479ec2013-09-10 17:03:02 -0700626 private void initFromAttributes(
627 Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
Filip Gruszczyńskib50cea02014-03-05 17:54:58 -0800628 final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ViewGroup, defStyleAttr,
629 defStyleRes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800630
631 final int N = a.getIndexCount();
632 for (int i = 0; i < N; i++) {
633 int attr = a.getIndex(i);
634 switch (attr) {
635 case R.styleable.ViewGroup_clipChildren:
636 setClipChildren(a.getBoolean(attr, true));
637 break;
638 case R.styleable.ViewGroup_clipToPadding:
639 setClipToPadding(a.getBoolean(attr, true));
640 break;
641 case R.styleable.ViewGroup_animationCache:
642 setAnimationCacheEnabled(a.getBoolean(attr, true));
643 break;
644 case R.styleable.ViewGroup_persistentDrawingCache:
645 setPersistentDrawingCache(a.getInt(attr, PERSISTENT_SCROLLING_CACHE));
646 break;
647 case R.styleable.ViewGroup_addStatesFromChildren:
648 setAddStatesFromChildren(a.getBoolean(attr, false));
649 break;
650 case R.styleable.ViewGroup_alwaysDrawnWithCache:
651 setAlwaysDrawnWithCacheEnabled(a.getBoolean(attr, true));
652 break;
653 case R.styleable.ViewGroup_layoutAnimation:
654 int id = a.getResourceId(attr, -1);
655 if (id > 0) {
656 setLayoutAnimation(AnimationUtils.loadLayoutAnimation(mContext, id));
657 }
658 break;
659 case R.styleable.ViewGroup_descendantFocusability:
660 setDescendantFocusability(DESCENDANT_FOCUSABILITY_FLAGS[a.getInt(attr, 0)]);
661 break;
Adam Powell2b342f02010-08-18 18:14:13 -0700662 case R.styleable.ViewGroup_splitMotionEvents:
663 setMotionEventSplittingEnabled(a.getBoolean(attr, false));
664 break;
Chet Haase13cc1202010-09-03 15:39:20 -0700665 case R.styleable.ViewGroup_animateLayoutChanges:
666 boolean animateLayoutChanges = a.getBoolean(attr, false);
667 if (animateLayoutChanges) {
668 setLayoutTransition(new LayoutTransition());
669 }
670 break;
Philip Milne7b757812012-09-19 18:13:44 -0700671 case R.styleable.ViewGroup_layoutMode:
Philip Milnecfb631b2012-10-26 10:51:46 -0700672 setLayoutMode(a.getInt(attr, LAYOUT_MODE_UNDEFINED));
Philip Milne7b757812012-09-19 18:13:44 -0700673 break;
George Mount0a778ed2013-12-13 13:35:36 -0800674 case R.styleable.ViewGroup_transitionGroup:
675 setTransitionGroup(a.getBoolean(attr, false));
676 break;
Adam Powellff0d2982014-07-10 20:34:14 -0700677 case R.styleable.ViewGroup_touchscreenBlocksFocus:
678 setTouchscreenBlocksFocus(a.getBoolean(attr, false));
679 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800680 }
681 }
682
683 a.recycle();
684 }
685
686 /**
687 * Gets the descendant focusability of this view group. The descendant
688 * focusability defines the relationship between this view group and its
689 * descendants when looking for a view to take focus in
690 * {@link #requestFocus(int, android.graphics.Rect)}.
691 *
692 * @return one of {@link #FOCUS_BEFORE_DESCENDANTS}, {@link #FOCUS_AFTER_DESCENDANTS},
693 * {@link #FOCUS_BLOCK_DESCENDANTS}.
694 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -0700695 @ViewDebug.ExportedProperty(category = "focus", mapping = {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800696 @ViewDebug.IntToString(from = FOCUS_BEFORE_DESCENDANTS, to = "FOCUS_BEFORE_DESCENDANTS"),
697 @ViewDebug.IntToString(from = FOCUS_AFTER_DESCENDANTS, to = "FOCUS_AFTER_DESCENDANTS"),
698 @ViewDebug.IntToString(from = FOCUS_BLOCK_DESCENDANTS, to = "FOCUS_BLOCK_DESCENDANTS")
699 })
700 public int getDescendantFocusability() {
701 return mGroupFlags & FLAG_MASK_FOCUSABILITY;
702 }
703
704 /**
705 * Set the descendant focusability of this view group. This defines the relationship
706 * between this view group and its descendants when looking for a view to
707 * take focus in {@link #requestFocus(int, android.graphics.Rect)}.
708 *
709 * @param focusability one of {@link #FOCUS_BEFORE_DESCENDANTS}, {@link #FOCUS_AFTER_DESCENDANTS},
710 * {@link #FOCUS_BLOCK_DESCENDANTS}.
711 */
712 public void setDescendantFocusability(int focusability) {
713 switch (focusability) {
714 case FOCUS_BEFORE_DESCENDANTS:
715 case FOCUS_AFTER_DESCENDANTS:
716 case FOCUS_BLOCK_DESCENDANTS:
717 break;
718 default:
719 throw new IllegalArgumentException("must be one of FOCUS_BEFORE_DESCENDANTS, "
720 + "FOCUS_AFTER_DESCENDANTS, FOCUS_BLOCK_DESCENDANTS");
721 }
722 mGroupFlags &= ~FLAG_MASK_FOCUSABILITY;
723 mGroupFlags |= (focusability & FLAG_MASK_FOCUSABILITY);
724 }
725
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800726 @Override
727 void handleFocusGainInternal(int direction, Rect previouslyFocusedRect) {
728 if (mFocused != null) {
Alan Viverette223622a2013-12-17 13:29:02 -0800729 mFocused.unFocus(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800730 mFocused = null;
Evan Rosky53fcf112017-01-26 14:37:55 -0800731 mFocusedInCluster = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800732 }
733 super.handleFocusGainInternal(direction, previouslyFocusedRect);
734 }
735
Alan Viverettebe463f22016-01-21 10:50:10 -0500736 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800737 public void requestChildFocus(View child, View focused) {
738 if (DBG) {
739 System.out.println(this + " requestChildFocus()");
740 }
741 if (getDescendantFocusability() == FOCUS_BLOCK_DESCENDANTS) {
742 return;
743 }
744
745 // Unfocus us, if necessary
Alan Viverette223622a2013-12-17 13:29:02 -0800746 super.unFocus(focused);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800747
748 // We had a previous notion of who had focus. Clear it.
749 if (mFocused != child) {
750 if (mFocused != null) {
Alan Viverette223622a2013-12-17 13:29:02 -0800751 mFocused.unFocus(focused);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800752 }
753
754 mFocused = child;
755 }
756 if (mParent != null) {
757 mParent.requestChildFocus(this, focused);
758 }
759 }
760
Vadim Tryshev5ca73982017-01-04 17:24:43 -0800761 void setDefaultFocus(View child) {
Evan Rosky53fcf112017-01-26 14:37:55 -0800762 // Stop at any higher view which is explicitly focused-by-default
763 if (mDefaultFocus != null && mDefaultFocus.isFocusedByDefault()) {
Vadim Tryshev5ca73982017-01-04 17:24:43 -0800764 return;
Vadim Tryshev01d8c492016-12-15 11:33:15 -0800765 }
Vadim Tryshev5ca73982017-01-04 17:24:43 -0800766
767 mDefaultFocus = child;
768
769 if (mParent instanceof ViewGroup) {
770 ((ViewGroup) mParent).setDefaultFocus(this);
771 }
772 }
773
774 /**
Evan Rosky53fcf112017-01-26 14:37:55 -0800775 * Clears the default-focus chain from {@param child} up to the first parent which has another
776 * default-focusable branch below it or until there is no default-focus chain.
777 *
778 * @param child
Vadim Tryshev5ca73982017-01-04 17:24:43 -0800779 */
Evan Rosky53fcf112017-01-26 14:37:55 -0800780 void clearDefaultFocus(View child) {
781 // Stop at any higher view which is explicitly focused-by-default
782 if (mDefaultFocus != child && mDefaultFocus != null
783 && mDefaultFocus.isFocusedByDefault()) {
784 return;
785 }
786
787 mDefaultFocus = null;
788
789 // Search child siblings for default focusables.
790 for (int i = 0; i < mChildrenCount; ++i) {
791 View sibling = mChildren[i];
792 if (sibling.isFocusedByDefault()) {
793 mDefaultFocus = sibling;
794 return;
795 } else if (mDefaultFocus == null && sibling.hasDefaultFocus()) {
796 mDefaultFocus = sibling;
797 }
798 }
799
800 if (mParent instanceof ViewGroup) {
801 ((ViewGroup) mParent).clearDefaultFocus(this);
802 }
803 }
804
805 @Override
806 boolean hasDefaultFocus() {
807 return mDefaultFocus != null || super.hasDefaultFocus();
808 }
809
Evan Rosky0e8a6832017-04-10 12:35:15 -0700810 /**
811 * Removes {@code child} (and associated focusedInCluster chain) from the cluster containing
812 * it.
813 * <br>
814 * This is intended to be run on {@code child}'s immediate parent. This is necessary because
815 * the chain is sometimes cleared after {@code child} has been detached.
816 */
817 void clearFocusedInCluster(View child) {
Evan Rosky53fcf112017-01-26 14:37:55 -0800818 if (mFocusedInCluster != child) {
Vadim Tryshev5ca73982017-01-04 17:24:43 -0800819 return;
820 }
Evan Rosky0e8a6832017-04-10 12:35:15 -0700821 View top = findKeyboardNavigationCluster();
822 ViewParent parent = this;
823 do {
824 ((ViewGroup) parent).mFocusedInCluster = null;
Evan Rosky6c286be2017-04-19 17:23:32 -0700825 if (parent == top) {
826 break;
827 }
Evan Rosky0e8a6832017-04-10 12:35:15 -0700828 parent = parent.getParent();
Evan Rosky6c286be2017-04-19 17:23:32 -0700829 } while (parent instanceof ViewGroup);
Vadim Tryshev5ca73982017-01-04 17:24:43 -0800830 }
831
832 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800833 public void focusableViewAvailable(View v) {
834 if (mParent != null
835 // shortcut: don't report a new focusable view if we block our descendants from
Evan Rosky2ae1bf52017-05-11 11:18:45 -0700836 // getting focus or if we're not visible
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800837 && (getDescendantFocusability() != FOCUS_BLOCK_DESCENDANTS)
Evan Rosky2ae1bf52017-05-11 11:18:45 -0700838 && ((mViewFlags & VISIBILITY_MASK) == VISIBLE)
Adam Powell88c11752014-07-21 17:19:16 -0700839 && (isFocusableInTouchMode() || !shouldBlockFocusForTouchscreen())
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800840 // shortcut: don't report a new focusable view if we already are focused
841 // (and we don't prefer our descendants)
842 //
843 // note: knowing that mFocused is non-null is not a good enough reason
844 // to break the traversal since in that case we'd actually have to find
845 // the focused view and make sure it wasn't FOCUS_AFTER_DESCENDANTS and
Joe Onoratoc6cc0f82011-04-12 11:53:13 -0700846 // an ancestor of v; this will get checked for at ViewAncestor
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800847 && !(isFocused() && getDescendantFocusability() != FOCUS_AFTER_DESCENDANTS)) {
848 mParent.focusableViewAvailable(v);
849 }
850 }
851
Alan Viverettebe463f22016-01-21 10:50:10 -0500852 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800853 public boolean showContextMenuForChild(View originalView) {
Adam Powell2af189a2016-02-05 15:52:02 -0800854 if (isShowingContextMenuWithCoords()) {
855 // We're being called for compatibility. Return false and let the version
856 // with coordinates recurse up.
857 return false;
858 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800859 return mParent != null && mParent.showContextMenuForChild(originalView);
860 }
861
Adam Powell2af189a2016-02-05 15:52:02 -0800862 /**
863 * @hide used internally for compatibility with existing app code only
864 */
865 public final boolean isShowingContextMenuWithCoords() {
866 return (mGroupFlags & FLAG_SHOW_CONTEXT_MENU_WITH_COORDS) != 0;
867 }
868
Oren Blasberged391262015-09-01 12:12:51 -0700869 @Override
870 public boolean showContextMenuForChild(View originalView, float x, float y) {
Adam Powell2af189a2016-02-05 15:52:02 -0800871 try {
872 mGroupFlags |= FLAG_SHOW_CONTEXT_MENU_WITH_COORDS;
873 if (showContextMenuForChild(originalView)) {
874 return true;
875 }
876 } finally {
877 mGroupFlags &= ~FLAG_SHOW_CONTEXT_MENU_WITH_COORDS;
878 }
Oren Blasberged391262015-09-01 12:12:51 -0700879 return mParent != null && mParent.showContextMenuForChild(originalView, x, y);
880 }
881
Clara Bayarri4423d912015-03-02 19:42:48 +0000882 @Override
Adam Powell6e346362010-07-23 10:18:23 -0700883 public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback) {
Clara Bayarri4423d912015-03-02 19:42:48 +0000884 if ((mGroupFlags & FLAG_START_ACTION_MODE_FOR_CHILD_IS_TYPED) == 0) {
885 // This is the original call.
886 try {
887 mGroupFlags |= FLAG_START_ACTION_MODE_FOR_CHILD_IS_NOT_TYPED;
888 return startActionModeForChild(originalView, callback, ActionMode.TYPE_PRIMARY);
889 } finally {
890 mGroupFlags &= ~FLAG_START_ACTION_MODE_FOR_CHILD_IS_NOT_TYPED;
891 }
892 } else {
893 // We are being called from the new method with type.
894 return SENTINEL_ACTION_MODE;
895 }
896 }
897
Clara Bayarri4423d912015-03-02 19:42:48 +0000898 @Override
899 public ActionMode startActionModeForChild(
900 View originalView, ActionMode.Callback callback, int type) {
Adam Powelle9fd6d22015-06-01 11:26:32 -0700901 if ((mGroupFlags & FLAG_START_ACTION_MODE_FOR_CHILD_IS_NOT_TYPED) == 0
902 && type == ActionMode.TYPE_PRIMARY) {
Clara Bayarri4423d912015-03-02 19:42:48 +0000903 ActionMode mode;
904 try {
905 mGroupFlags |= FLAG_START_ACTION_MODE_FOR_CHILD_IS_TYPED;
906 mode = startActionModeForChild(originalView, callback);
907 } finally {
908 mGroupFlags &= ~FLAG_START_ACTION_MODE_FOR_CHILD_IS_TYPED;
909 }
910 if (mode != SENTINEL_ACTION_MODE) {
911 return mode;
912 }
913 }
914 if (mParent != null) {
915 try {
916 return mParent.startActionModeForChild(originalView, callback, type);
917 } catch (AbstractMethodError ame) {
918 // Custom view parents might not implement this method.
919 return mParent.startActionModeForChild(originalView, callback);
920 }
921 }
922 return null;
Adam Powell6e346362010-07-23 10:18:23 -0700923 }
924
925 /**
Clara Bayarrid5bf3ed2015-03-27 17:32:45 +0000926 * @hide
927 */
928 @Override
929 public boolean dispatchActivityResult(
930 String who, int requestCode, int resultCode, Intent data) {
931 if (super.dispatchActivityResult(who, requestCode, resultCode, data)) {
932 return true;
933 }
934 int childCount = getChildCount();
935 for (int i = 0; i < childCount; i++) {
936 View child = getChildAt(i);
937 if (child.dispatchActivityResult(who, requestCode, resultCode, data)) {
938 return true;
939 }
940 }
941 return false;
942 }
943
944 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800945 * Find the nearest view in the specified direction that wants to take
946 * focus.
947 *
948 * @param focused The view that currently has focus
949 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and
950 * FOCUS_RIGHT, or 0 for not applicable.
951 */
Alan Viverettebe463f22016-01-21 10:50:10 -0500952 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800953 public View focusSearch(View focused, int direction) {
Vadim Tryshevb5ced222017-01-17 19:31:35 -0800954 if (isRootNamespace()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800955 // root namespace means we should consider ourselves the top of the
956 // tree for focus searching; otherwise we could be focus searching
Vadim Tryshev418b1fc2016-11-28 18:26:24 -0800957 // into other tabs. see LocalActivityManager and TabHost for more info.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800958 return FocusFinder.getInstance().findNextFocus(this, focused, direction);
959 } else if (mParent != null) {
960 return mParent.focusSearch(focused, direction);
961 }
962 return null;
963 }
964
Alan Viverettebe463f22016-01-21 10:50:10 -0500965 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800966 public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
967 return false;
968 }
969
Svetoslav Ganov42138042012-03-20 11:51:39 -0700970 @Override
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700971 public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event) {
Svetoslav Ganov42138042012-03-20 11:51:39 -0700972 ViewParent parent = mParent;
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700973 if (parent == null) {
974 return false;
975 }
976 final boolean propagate = onRequestSendAccessibilityEvent(child, event);
977 if (!propagate) {
978 return false;
979 }
980 return parent.requestSendAccessibilityEvent(this, event);
981 }
982
983 /**
984 * Called when a child has requested sending an {@link AccessibilityEvent} and
985 * gives an opportunity to its parent to augment the event.
Svetoslav Ganov031d9c12011-09-09 16:41:13 -0700986 * <p>
Adam Powell2fcbbd02011-09-28 18:56:43 -0700987 * If an {@link android.view.View.AccessibilityDelegate} has been specified via calling
988 * {@link android.view.View#setAccessibilityDelegate(android.view.View.AccessibilityDelegate)} its
989 * {@link android.view.View.AccessibilityDelegate#onRequestSendAccessibilityEvent(ViewGroup, View, AccessibilityEvent)}
Svetoslav Ganov031d9c12011-09-09 16:41:13 -0700990 * is responsible for handling this call.
991 * </p>
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700992 *
993 * @param child The child which requests sending the event.
994 * @param event The event to be sent.
995 * @return True if the event should be sent.
996 *
997 * @see #requestSendAccessibilityEvent(View, AccessibilityEvent)
998 */
999 public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
Svetoslav Ganov031d9c12011-09-09 16:41:13 -07001000 if (mAccessibilityDelegate != null) {
1001 return mAccessibilityDelegate.onRequestSendAccessibilityEvent(this, child, event);
1002 } else {
1003 return onRequestSendAccessibilityEventInternal(child, event);
1004 }
1005 }
1006
1007 /**
1008 * @see #onRequestSendAccessibilityEvent(View, AccessibilityEvent)
1009 *
1010 * Note: Called from the default {@link View.AccessibilityDelegate}.
Alan Viverettea54956a2015-01-07 16:05:02 -08001011 *
1012 * @hide
Svetoslav Ganov031d9c12011-09-09 16:41:13 -07001013 */
Alan Viverettea54956a2015-01-07 16:05:02 -08001014 public boolean onRequestSendAccessibilityEventInternal(View child, AccessibilityEvent event) {
Svetoslav Ganov736c2752011-04-22 18:30:36 -07001015 return true;
1016 }
1017
1018 /**
Adam Powell539ee872012-02-03 19:00:49 -08001019 * Called when a child view has changed whether or not it is tracking transient state.
Adam Powell539ee872012-02-03 19:00:49 -08001020 */
Alan Viverettebe463f22016-01-21 10:50:10 -05001021 @Override
Adam Powell539ee872012-02-03 19:00:49 -08001022 public void childHasTransientStateChanged(View child, boolean childHasTransientState) {
1023 final boolean oldHasTransientState = hasTransientState();
1024 if (childHasTransientState) {
1025 mChildCountWithTransientState++;
1026 } else {
1027 mChildCountWithTransientState--;
1028 }
1029
1030 final boolean newHasTransientState = hasTransientState();
1031 if (mParent != null && oldHasTransientState != newHasTransientState) {
1032 try {
1033 mParent.childHasTransientStateChanged(this, newHasTransientState);
1034 } catch (AbstractMethodError e) {
1035 Log.e(TAG, mParent.getClass().getSimpleName() +
1036 " does not fully implement ViewParent", e);
1037 }
1038 }
1039 }
1040
Adam Powell539ee872012-02-03 19:00:49 -08001041 @Override
1042 public boolean hasTransientState() {
1043 return mChildCountWithTransientState > 0 || super.hasTransientState();
1044 }
1045
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001046 @Override
1047 public boolean dispatchUnhandledMove(View focused, int direction) {
1048 return mFocused != null &&
1049 mFocused.dispatchUnhandledMove(focused, direction);
1050 }
1051
Alan Viverettebe463f22016-01-21 10:50:10 -05001052 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001053 public void clearChildFocus(View child) {
1054 if (DBG) {
1055 System.out.println(this + " clearChildFocus()");
1056 }
1057
1058 mFocused = null;
1059 if (mParent != null) {
1060 mParent.clearChildFocus(this);
1061 }
1062 }
1063
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001064 @Override
1065 public void clearFocus() {
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08001066 if (DBG) {
1067 System.out.println(this + " clearFocus()");
1068 }
1069 if (mFocused == null) {
1070 super.clearFocus();
1071 } else {
Svetoslav Ganovb552d892012-06-02 14:35:02 -07001072 View focused = mFocused;
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08001073 mFocused = null;
Svetoslav Ganovb552d892012-06-02 14:35:02 -07001074 focused.clearFocus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001075 }
1076 }
1077
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001078 @Override
Alan Viverette223622a2013-12-17 13:29:02 -08001079 void unFocus(View focused) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001080 if (DBG) {
1081 System.out.println(this + " unFocus()");
1082 }
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08001083 if (mFocused == null) {
Alan Viverette223622a2013-12-17 13:29:02 -08001084 super.unFocus(focused);
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08001085 } else {
Alan Viverette223622a2013-12-17 13:29:02 -08001086 mFocused.unFocus(focused);
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08001087 mFocused = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001088 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001089 }
1090
1091 /**
1092 * Returns the focused child of this view, if any. The child may have focus
1093 * or contain focus.
1094 *
1095 * @return the focused child or null.
1096 */
1097 public View getFocusedChild() {
1098 return mFocused;
1099 }
1100
Adam Powell88c11752014-07-21 17:19:16 -07001101 View getDeepestFocusedChild() {
1102 View v = this;
1103 while (v != null) {
1104 if (v.isFocused()) {
1105 return v;
1106 }
1107 v = v instanceof ViewGroup ? ((ViewGroup) v).getFocusedChild() : null;
1108 }
1109 return null;
1110 }
1111
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001112 /**
1113 * Returns true if this view has or contains focus
1114 *
1115 * @return true if this view has or contains focus
1116 */
1117 @Override
1118 public boolean hasFocus() {
Dianne Hackborn4702a852012-08-17 15:18:29 -07001119 return (mPrivateFlags & PFLAG_FOCUSED) != 0 || mFocused != null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001120 }
1121
1122 /*
1123 * (non-Javadoc)
1124 *
1125 * @see android.view.View#findFocus()
1126 */
1127 @Override
1128 public View findFocus() {
1129 if (DBG) {
1130 System.out.println("Find focus in " + this + ": flags="
1131 + isFocused() + ", child=" + mFocused);
1132 }
1133
1134 if (isFocused()) {
1135 return this;
1136 }
1137
1138 if (mFocused != null) {
1139 return mFocused.findFocus();
1140 }
1141 return null;
1142 }
1143
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001144 @Override
Adam Powell0f552f42017-02-03 11:50:42 -08001145 boolean hasFocusable(boolean allowAutoFocus, boolean dispatchExplicit) {
Alan Viverette7485a9b2017-02-27 11:55:53 -05001146 // This should probably be super.hasFocusable, but that would change
1147 // behavior. Historically, we have not checked the ancestor views for
1148 // shouldBlockFocusForTouchscreen() in ViewGroup.hasFocusable.
1149
1150 // Invisible and gone views are never focusable.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001151 if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) {
1152 return false;
1153 }
1154
Alan Viverette7485a9b2017-02-27 11:55:53 -05001155 // Only use effective focusable value when allowed.
1156 if ((allowAutoFocus || getFocusable() != FOCUSABLE_AUTO) && isFocusable()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001157 return true;
1158 }
1159
Alan Viverette7485a9b2017-02-27 11:55:53 -05001160 // Determine whether we have a focused descendant.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001161 final int descendantFocusability = getDescendantFocusability();
Adam Powell88c11752014-07-21 17:19:16 -07001162 if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) {
Evan Rosky2ae1bf52017-05-11 11:18:45 -07001163 return hasFocusableChild(dispatchExplicit);
1164 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001165
Evan Rosky2ae1bf52017-05-11 11:18:45 -07001166 return false;
1167 }
Adam Powell0f552f42017-02-03 11:50:42 -08001168
Evan Rosky2ae1bf52017-05-11 11:18:45 -07001169 boolean hasFocusableChild(boolean dispatchExplicit) {
1170 // Determine whether we have a focusable descendant.
1171 final int count = mChildrenCount;
1172 final View[] children = mChildren;
1173
1174 for (int i = 0; i < count; i++) {
1175 final View child = children[i];
1176
1177 // In case the subclass has overridden has[Explicit]Focusable, dispatch
1178 // to the expected one for each child even though we share logic here.
1179 if ((dispatchExplicit && child.hasExplicitFocusable())
1180 || (!dispatchExplicit && child.hasFocusable())) {
1181 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001182 }
1183 }
1184
1185 return false;
1186 }
1187
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001188 @Override
svetoslavganov75986cf2009-05-14 22:28:01 -07001189 public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001190 final int focusableCount = views.size();
1191
1192 final int descendantFocusability = getDescendantFocusability();
Evan Rosky18b886e2017-02-15 13:26:51 -08001193 final boolean blockFocusForTouchscreen = shouldBlockFocusForTouchscreen();
1194 final boolean focusSelf = (isFocusableInTouchMode() || !blockFocusForTouchscreen);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001195
Evan Rosky3b94bf52017-01-10 17:05:28 -08001196 if (descendantFocusability == FOCUS_BLOCK_DESCENDANTS) {
1197 if (focusSelf) {
1198 super.addFocusables(views, direction, focusableMode);
Adam Powell88c11752014-07-21 17:19:16 -07001199 }
Evan Rosky3b94bf52017-01-10 17:05:28 -08001200 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001201 }
1202
Evan Rosky18b886e2017-02-15 13:26:51 -08001203 if (blockFocusForTouchscreen) {
Evan Rosky3b94bf52017-01-10 17:05:28 -08001204 focusableMode |= FOCUSABLES_TOUCH_MODE;
1205 }
1206
1207 if ((descendantFocusability == FOCUS_BEFORE_DESCENDANTS) && focusSelf) {
1208 super.addFocusables(views, direction, focusableMode);
1209 }
1210
1211 int count = 0;
1212 final View[] children = new View[mChildrenCount];
1213 for (int i = 0; i < mChildrenCount; ++i) {
1214 View child = mChildren[i];
1215 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
1216 children[count++] = child;
1217 }
1218 }
Evan Roskyd114e0f2017-03-23 11:20:04 -07001219 FocusFinder.sort(children, 0, count, this, isLayoutRtl());
Evan Rosky3b94bf52017-01-10 17:05:28 -08001220 for (int i = 0; i < count; ++i) {
1221 children[i].addFocusables(views, direction, focusableMode);
1222 }
1223
1224 // When set to FOCUS_AFTER_DESCENDANTS, we only add ourselves if
1225 // there aren't any focusable descendants. this is
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001226 // to avoid the focus search finding layouts when a more precise search
1227 // among the focusable children would be more interesting.
Evan Rosky3b94bf52017-01-10 17:05:28 -08001228 if ((descendantFocusability == FOCUS_AFTER_DESCENDANTS) && focusSelf
1229 && focusableCount == views.size()) {
svetoslavganov75986cf2009-05-14 22:28:01 -07001230 super.addFocusables(views, direction, focusableMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001231 }
1232 }
1233
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08001234 @Override
Vadim Tryshevb5ced222017-01-17 19:31:35 -08001235 public void addKeyboardNavigationClusters(Collection<View> views, int direction) {
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08001236 final int focusableCount = views.size();
1237
Evan Rosky18b886e2017-02-15 13:26:51 -08001238 if (isKeyboardNavigationCluster()) {
1239 // Cluster-navigation can enter a touchscreenBlocksFocus cluster, so temporarily
1240 // disable touchscreenBlocksFocus to evaluate whether it contains focusables.
1241 final boolean blockedFocus = getTouchscreenBlocksFocus();
1242 try {
1243 setTouchscreenBlocksFocusNoRefocus(false);
1244 super.addKeyboardNavigationClusters(views, direction);
1245 } finally {
1246 setTouchscreenBlocksFocusNoRefocus(blockedFocus);
1247 }
1248 } else {
1249 super.addKeyboardNavigationClusters(views, direction);
1250 }
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08001251
1252 if (focusableCount != views.size()) {
Vadim Tryshev311a5b52017-01-05 18:54:11 -08001253 // No need to look for groups inside a group.
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08001254 return;
1255 }
1256
1257 if (getDescendantFocusability() == FOCUS_BLOCK_DESCENDANTS) {
1258 return;
1259 }
1260
Evan Roskybd10c522017-03-27 15:50:38 -07001261 int count = 0;
1262 final View[] visibleChildren = new View[mChildrenCount];
1263 for (int i = 0; i < mChildrenCount; ++i) {
1264 final View child = mChildren[i];
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08001265 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
Evan Roskybd10c522017-03-27 15:50:38 -07001266 visibleChildren[count++] = child;
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08001267 }
1268 }
Evan Roskyd114e0f2017-03-23 11:20:04 -07001269 FocusFinder.sort(visibleChildren, 0, count, this, isLayoutRtl());
Evan Roskybd10c522017-03-27 15:50:38 -07001270 for (int i = 0; i < count; ++i) {
1271 visibleChildren[i].addKeyboardNavigationClusters(views, direction);
1272 }
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08001273 }
1274
Adam Powellff0d2982014-07-10 20:34:14 -07001275 /**
1276 * Set whether this ViewGroup should ignore focus requests for itself and its children.
1277 * If this option is enabled and the ViewGroup or a descendant currently has focus, focus
1278 * will proceed forward.
1279 *
1280 * @param touchscreenBlocksFocus true to enable blocking focus in the presence of a touchscreen
1281 */
1282 public void setTouchscreenBlocksFocus(boolean touchscreenBlocksFocus) {
1283 if (touchscreenBlocksFocus) {
1284 mGroupFlags |= FLAG_TOUCHSCREEN_BLOCKS_FOCUS;
Evan Rosky0e8a6832017-04-10 12:35:15 -07001285 if (hasFocus() && !isKeyboardNavigationCluster()) {
Adam Powell88c11752014-07-21 17:19:16 -07001286 final View focusedChild = getDeepestFocusedChild();
1287 if (!focusedChild.isFocusableInTouchMode()) {
1288 final View newFocus = focusSearch(FOCUS_FORWARD);
1289 if (newFocus != null) {
1290 newFocus.requestFocus();
1291 }
Adam Powellff0d2982014-07-10 20:34:14 -07001292 }
1293 }
1294 } else {
1295 mGroupFlags &= ~FLAG_TOUCHSCREEN_BLOCKS_FOCUS;
1296 }
1297 }
1298
Evan Rosky18b886e2017-02-15 13:26:51 -08001299 private void setTouchscreenBlocksFocusNoRefocus(boolean touchscreenBlocksFocus) {
1300 if (touchscreenBlocksFocus) {
1301 mGroupFlags |= FLAG_TOUCHSCREEN_BLOCKS_FOCUS;
1302 } else {
1303 mGroupFlags &= ~FLAG_TOUCHSCREEN_BLOCKS_FOCUS;
1304 }
1305 }
1306
Adam Powellff0d2982014-07-10 20:34:14 -07001307 /**
1308 * Check whether this ViewGroup should ignore focus requests for itself and its children.
1309 */
Evan Roskyecb63fc2017-04-13 16:57:18 -07001310 @ViewDebug.ExportedProperty(category = "focus")
Adam Powellff0d2982014-07-10 20:34:14 -07001311 public boolean getTouchscreenBlocksFocus() {
1312 return (mGroupFlags & FLAG_TOUCHSCREEN_BLOCKS_FOCUS) != 0;
1313 }
1314
1315 boolean shouldBlockFocusForTouchscreen() {
Evan Rosky18b886e2017-02-15 13:26:51 -08001316 // There is a special case for keyboard-navigation clusters. We allow cluster navigation
1317 // to jump into blockFocusForTouchscreen ViewGroups which are clusters. Once in the
1318 // cluster, focus is free to move around within it.
Adam Powellff0d2982014-07-10 20:34:14 -07001319 return getTouchscreenBlocksFocus() &&
Evan Rosky18b886e2017-02-15 13:26:51 -08001320 mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN)
Evan Rosky0e8a6832017-04-10 12:35:15 -07001321 && !(isKeyboardNavigationCluster()
1322 && (hasFocus() || (findKeyboardNavigationCluster() != this)));
Adam Powellff0d2982014-07-10 20:34:14 -07001323 }
1324
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001325 @Override
Svetoslav Ganovea515ae2011-09-14 18:15:32 -07001326 public void findViewsWithText(ArrayList<View> outViews, CharSequence text, int flags) {
1327 super.findViewsWithText(outViews, text, flags);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001328 final int childrenCount = mChildrenCount;
1329 final View[] children = mChildren;
1330 for (int i = 0; i < childrenCount; i++) {
1331 View child = children[i];
Svetoslav Ganovea515ae2011-09-14 18:15:32 -07001332 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE
Dianne Hackborn4702a852012-08-17 15:18:29 -07001333 && (child.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
Svetoslav Ganovea515ae2011-09-14 18:15:32 -07001334 child.findViewsWithText(outViews, text, flags);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001335 }
1336 }
1337 }
1338
Svetoslav5b578da2013-05-08 14:23:32 -07001339 /** @hide */
Svetoslav Ganov2cdedff2011-10-03 14:18:42 -07001340 @Override
Svetoslav5b578da2013-05-08 14:23:32 -07001341 public View findViewByAccessibilityIdTraversal(int accessibilityId) {
Svetoslav Ganov2cdedff2011-10-03 14:18:42 -07001342 View foundView = super.findViewByAccessibilityIdTraversal(accessibilityId);
1343 if (foundView != null) {
1344 return foundView;
1345 }
Svetoslav6cc46272015-06-03 11:38:30 -07001346
1347 if (getAccessibilityNodeProvider() != null) {
1348 return null;
1349 }
1350
Svetoslav Ganov2cdedff2011-10-03 14:18:42 -07001351 final int childrenCount = mChildrenCount;
1352 final View[] children = mChildren;
1353 for (int i = 0; i < childrenCount; i++) {
1354 View child = children[i];
1355 foundView = child.findViewByAccessibilityIdTraversal(accessibilityId);
1356 if (foundView != null) {
1357 return foundView;
1358 }
1359 }
Svetoslav6cc46272015-06-03 11:38:30 -07001360
Svetoslav Ganov2cdedff2011-10-03 14:18:42 -07001361 return null;
1362 }
1363
Phil Weaver846cda932017-06-15 10:10:06 -07001364 /** @hide */
1365 @Override
1366 public View findViewByAutofillIdTraversal(int autofillId) {
1367 View foundView = super.findViewByAutofillIdTraversal(autofillId);
1368 if (foundView != null) {
1369 return foundView;
1370 }
1371
1372 final int childrenCount = mChildrenCount;
1373 final View[] children = mChildren;
1374 for (int i = 0; i < childrenCount; i++) {
1375 View child = children[i];
1376 foundView = child.findViewByAutofillIdTraversal(autofillId);
1377 if (foundView != null) {
1378 return foundView;
1379 }
1380 }
1381
1382 return null;
1383 }
1384
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001385 @Override
1386 public void dispatchWindowFocusChanged(boolean hasFocus) {
1387 super.dispatchWindowFocusChanged(hasFocus);
1388 final int count = mChildrenCount;
1389 final View[] children = mChildren;
1390 for (int i = 0; i < count; i++) {
1391 children[i].dispatchWindowFocusChanged(hasFocus);
1392 }
1393 }
1394
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001395 @Override
1396 public void addTouchables(ArrayList<View> views) {
1397 super.addTouchables(views);
1398
1399 final int count = mChildrenCount;
1400 final View[] children = mChildren;
1401
1402 for (int i = 0; i < count; i++) {
1403 final View child = children[i];
1404 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
1405 child.addTouchables(views);
1406 }
1407 }
1408 }
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001409
1410 /**
1411 * @hide
1412 */
1413 @Override
1414 public void makeOptionalFitsSystemWindows() {
1415 super.makeOptionalFitsSystemWindows();
1416 final int count = mChildrenCount;
1417 final View[] children = mChildren;
1418 for (int i = 0; i < count; i++) {
1419 children[i].makeOptionalFitsSystemWindows();
1420 }
1421 }
1422
Romain Guy43c9cdf2010-01-27 13:53:55 -08001423 @Override
1424 public void dispatchDisplayHint(int hint) {
1425 super.dispatchDisplayHint(hint);
1426 final int count = mChildrenCount;
1427 final View[] children = mChildren;
1428 for (int i = 0; i < count; i++) {
1429 children[i].dispatchDisplayHint(hint);
1430 }
1431 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001432
1433 /**
Chet Haase0d299362012-01-26 10:51:48 -08001434 * Called when a view's visibility has changed. Notify the parent to take any appropriate
1435 * action.
1436 *
1437 * @param child The view whose visibility has changed
1438 * @param oldVisibility The previous visibility value (GONE, INVISIBLE, or VISIBLE).
1439 * @param newVisibility The new visibility value (GONE, INVISIBLE, or VISIBLE).
Chet Haase5e25c2c2010-09-16 11:15:56 -07001440 * @hide
Chet Haase5e25c2c2010-09-16 11:15:56 -07001441 */
Chet Haase0d299362012-01-26 10:51:48 -08001442 protected void onChildVisibilityChanged(View child, int oldVisibility, int newVisibility) {
Chet Haase5e25c2c2010-09-16 11:15:56 -07001443 if (mTransition != null) {
Chet Haase0d299362012-01-26 10:51:48 -08001444 if (newVisibility == VISIBLE) {
1445 mTransition.showChild(this, child, oldVisibility);
Chet Haase5e25c2c2010-09-16 11:15:56 -07001446 } else {
Chet Haase0d299362012-01-26 10:51:48 -08001447 mTransition.hideChild(this, child, newVisibility);
Chet Haase5e25c2c2010-09-16 11:15:56 -07001448 if (mTransitioningViews != null && mTransitioningViews.contains(child)) {
Chet Haaseddbb3462012-06-19 13:54:29 -07001449 // Only track this on disappearing views - appearing views are already visible
1450 // and don't need special handling during drawChild()
1451 if (mVisibilityChangingChildren == null) {
1452 mVisibilityChangingChildren = new ArrayList<View>();
1453 }
1454 mVisibilityChangingChildren.add(child);
Chet Haase5e25c2c2010-09-16 11:15:56 -07001455 addDisappearingView(child);
1456 }
1457 }
1458 }
Christopher Tate86cab1b2011-01-13 20:28:55 -08001459
1460 // in all cases, for drags
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001461 if (newVisibility == VISIBLE && mCurrentDragStartEvent != null) {
1462 if (!mChildrenInterestedInDrag.contains(child)) {
1463 notifyChildOfDragStart(child);
Christopher Tate86cab1b2011-01-13 20:28:55 -08001464 }
1465 }
Chet Haase5e25c2c2010-09-16 11:15:56 -07001466 }
1467
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001468 @Override
Adam Powell326d8082009-12-09 15:10:07 -08001469 protected void dispatchVisibilityChanged(View changedView, int visibility) {
1470 super.dispatchVisibilityChanged(changedView, visibility);
1471 final int count = mChildrenCount;
1472 final View[] children = mChildren;
1473 for (int i = 0; i < count; i++) {
1474 children[i].dispatchVisibilityChanged(changedView, visibility);
1475 }
1476 }
1477
Adam Powell326d8082009-12-09 15:10:07 -08001478 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001479 public void dispatchWindowVisibilityChanged(int visibility) {
1480 super.dispatchWindowVisibilityChanged(visibility);
1481 final int count = mChildrenCount;
1482 final View[] children = mChildren;
1483 for (int i = 0; i < count; i++) {
1484 children[i].dispatchWindowVisibilityChanged(visibility);
1485 }
1486 }
1487
Dianne Hackborne36d6e22010-02-17 19:46:25 -08001488 @Override
Adam Powell9c146bf2016-03-15 17:35:00 -07001489 boolean dispatchVisibilityAggregated(boolean isVisible) {
1490 isVisible = super.dispatchVisibilityAggregated(isVisible);
Adam Powell41d96902016-03-15 14:43:19 -07001491 final int count = mChildrenCount;
1492 final View[] children = mChildren;
1493 for (int i = 0; i < count; i++) {
Adam Powell9c146bf2016-03-15 17:35:00 -07001494 // Only dispatch to visible children. Not visible children and their subtrees already
1495 // know that they aren't visible and that's not going to change as a result of
1496 // whatever triggered this dispatch.
1497 if (children[i].getVisibility() == VISIBLE) {
1498 children[i].dispatchVisibilityAggregated(isVisible);
Adam Powell41d96902016-03-15 14:43:19 -07001499 }
1500 }
Adam Powell9c146bf2016-03-15 17:35:00 -07001501 return isVisible;
Adam Powell41d96902016-03-15 14:43:19 -07001502 }
1503
1504 @Override
Dianne Hackborne36d6e22010-02-17 19:46:25 -08001505 public void dispatchConfigurationChanged(Configuration newConfig) {
1506 super.dispatchConfigurationChanged(newConfig);
1507 final int count = mChildrenCount;
1508 final View[] children = mChildren;
1509 for (int i = 0; i < count; i++) {
1510 children[i].dispatchConfigurationChanged(newConfig);
1511 }
1512 }
Filip Gruszczynskia33bdf32015-11-19 18:22:16 -08001513
Alan Viverettebe463f22016-01-21 10:50:10 -05001514 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001515 public void recomputeViewAttributes(View child) {
Joe Onorato664644d2011-01-23 17:53:23 -08001516 if (mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) {
1517 ViewParent parent = mParent;
1518 if (parent != null) parent.recomputeViewAttributes(this);
1519 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001520 }
Romain Guy8506ab42009-06-11 17:35:47 -07001521
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001522 @Override
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001523 void dispatchCollectViewAttributes(AttachInfo attachInfo, int visibility) {
1524 if ((visibility & VISIBILITY_MASK) == VISIBLE) {
1525 super.dispatchCollectViewAttributes(attachInfo, visibility);
1526 final int count = mChildrenCount;
1527 final View[] children = mChildren;
1528 for (int i = 0; i < count; i++) {
1529 final View child = children[i];
1530 child.dispatchCollectViewAttributes(attachInfo,
1531 visibility | (child.mViewFlags&VISIBILITY_MASK));
1532 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001533 }
1534 }
1535
Alan Viverettebe463f22016-01-21 10:50:10 -05001536 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001537 public void bringChildToFront(View child) {
Alan Viverette77bb6f12015-02-11 17:24:33 -08001538 final int index = indexOfChild(child);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001539 if (index >= 0) {
1540 removeFromArray(index);
1541 addInArray(child, mChildrenCount);
1542 child.mParent = this;
Chet Haasecb96db82013-09-04 10:21:46 -07001543 requestLayout();
1544 invalidate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001545 }
1546 }
1547
Romain Guy6410c0a2013-06-17 11:21:58 -07001548 private PointF getLocalPoint() {
1549 if (mLocalPoint == null) mLocalPoint = new PointF();
1550 return mLocalPoint;
1551 }
1552
Vadim Tryshevef128112016-09-16 14:05:53 -07001553 @Override
1554 boolean dispatchDragEnterExitInPreN(DragEvent event) {
1555 if (event.mAction == DragEvent.ACTION_DRAG_EXITED && mCurrentDragChild != null) {
1556 // The drag exited a sub-tree of views; notify of the exit all descendants that are in
1557 // entered state.
1558 // We don't need this recursive delivery for ENTERED events because they get generated
1559 // from the recursive delivery of LOCATION/DROP events, and hence, don't need their own
1560 // recursion.
1561 mCurrentDragChild.dispatchDragEnterExitInPreN(event);
1562 mCurrentDragChild = null;
1563 }
1564 return mIsInterestedInDrag && super.dispatchDragEnterExitInPreN(event);
1565 }
1566
Steve Block8a7259b2012-03-01 11:24:41 +00001567 // TODO: Write real docs
Christopher Tatea53146c2010-09-07 11:57:52 -07001568 @Override
1569 public boolean dispatchDragEvent(DragEvent event) {
1570 boolean retval = false;
1571 final float tx = event.mX;
1572 final float ty = event.mY;
Vadim Trysheva61efa42016-09-28 15:15:52 -07001573 final ClipData td = event.mClipData;
Christopher Tatea53146c2010-09-07 11:57:52 -07001574
Christopher Tatea53146c2010-09-07 11:57:52 -07001575 // Dispatch down the view hierarchy
Romain Guy6410c0a2013-06-17 11:21:58 -07001576 final PointF localPoint = getLocalPoint();
1577
Christopher Tatea53146c2010-09-07 11:57:52 -07001578 switch (event.mAction) {
1579 case DragEvent.ACTION_DRAG_STARTED: {
Vadim Tryshevef128112016-09-16 14:05:53 -07001580 // Clear the state to recalculate which views we drag over.
1581 mCurrentDragChild = null;
1582
Christopher Tate86cab1b2011-01-13 20:28:55 -08001583 // Set up our tracking of drag-started notifications
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001584 mCurrentDragStartEvent = DragEvent.obtain(event);
1585 if (mChildrenInterestedInDrag == null) {
1586 mChildrenInterestedInDrag = new HashSet<View>();
Christopher Tate86cab1b2011-01-13 20:28:55 -08001587 } else {
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001588 mChildrenInterestedInDrag.clear();
Christopher Tate86cab1b2011-01-13 20:28:55 -08001589 }
1590
Christopher Tatea53146c2010-09-07 11:57:52 -07001591 // Now dispatch down to our children, caching the responses
Christopher Tatea53146c2010-09-07 11:57:52 -07001592 final int count = mChildrenCount;
1593 final View[] children = mChildren;
1594 for (int i = 0; i < count; i++) {
Christopher Tate2c095f32010-10-04 14:13:40 -07001595 final View child = children[i];
Christopher Tate3d4bf172011-03-28 16:16:46 -07001596 child.mPrivateFlags2 &= ~View.DRAG_MASK;
Christopher Tate2c095f32010-10-04 14:13:40 -07001597 if (child.getVisibility() == VISIBLE) {
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001598 if (notifyChildOfDragStart(children[i])) {
1599 retval = true;
Christopher Tate2c095f32010-10-04 14:13:40 -07001600 }
Christopher Tatea53146c2010-09-07 11:57:52 -07001601 }
1602 }
1603
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001604 // Notify itself of the drag start.
1605 mIsInterestedInDrag = super.dispatchDragEvent(event);
1606 if (mIsInterestedInDrag) {
Christopher Tatea53146c2010-09-07 11:57:52 -07001607 retval = true;
1608 }
Yorke Lee0394b212016-03-10 18:20:04 -08001609
1610 if (!retval) {
1611 // Neither us nor any of our children are interested in this drag, so stop tracking
1612 // the current drag event.
1613 mCurrentDragStartEvent.recycle();
1614 mCurrentDragStartEvent = null;
1615 }
Christopher Tatea53146c2010-09-07 11:57:52 -07001616 } break;
1617
1618 case DragEvent.ACTION_DRAG_ENDED: {
Christopher Tate86cab1b2011-01-13 20:28:55 -08001619 // Release the bookkeeping now that the drag lifecycle has ended
Vadim Tryshev15177892015-12-18 08:01:00 -08001620 final HashSet<View> childrenInterestedInDrag = mChildrenInterestedInDrag;
1621 if (childrenInterestedInDrag != null) {
1622 for (View child : childrenInterestedInDrag) {
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001623 // If a child was interested in the ongoing drag, it's told that it's over
1624 if (child.dispatchDragEvent(event)) {
1625 retval = true;
1626 }
Christopher Tate1fc014f2011-01-19 12:56:26 -08001627 }
Vadim Tryshev15177892015-12-18 08:01:00 -08001628 childrenInterestedInDrag.clear();
1629 }
1630 if (mCurrentDragStartEvent != null) {
1631 mCurrentDragStartEvent.recycle();
1632 mCurrentDragStartEvent = null;
Christopher Tate1fc014f2011-01-19 12:56:26 -08001633 }
Christopher Tate86cab1b2011-01-13 20:28:55 -08001634
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001635 if (mIsInterestedInDrag) {
1636 if (super.dispatchDragEvent(event)) {
1637 retval = true;
1638 }
1639 mIsInterestedInDrag = false;
Christopher Tatea53146c2010-09-07 11:57:52 -07001640 }
1641 } break;
1642
Vadim Tryshev1edc6daf2016-09-15 16:19:15 -07001643 case DragEvent.ACTION_DRAG_LOCATION:
1644 case DragEvent.ACTION_DROP: {
Christopher Tatea53146c2010-09-07 11:57:52 -07001645 // Find the [possibly new] drag target
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001646 View target = findFrontmostDroppableChildAt(event.mX, event.mY, localPoint);
Vadim Tryshevef128112016-09-16 14:05:53 -07001647
1648 if (target != mCurrentDragChild) {
Vadim Tryshev45bee6b2016-09-19 11:00:37 -07001649 if (sCascadedDragDrop) {
Vadim Tryshevef128112016-09-16 14:05:53 -07001650 // For pre-Nougat apps, make sure that the whole hierarchy of views that contain
1651 // the drag location is kept in the state between ENTERED and EXITED events.
1652 // (Starting with N, only the innermost view will be in that state).
1653
1654 final int action = event.mAction;
1655 // Position should not be available for ACTION_DRAG_ENTERED and
1656 // ACTION_DRAG_EXITED.
1657 event.mX = 0;
1658 event.mY = 0;
Vadim Trysheva61efa42016-09-28 15:15:52 -07001659 event.mClipData = null;
Vadim Tryshevef128112016-09-16 14:05:53 -07001660
1661 if (mCurrentDragChild != null) {
1662 event.mAction = DragEvent.ACTION_DRAG_EXITED;
1663 mCurrentDragChild.dispatchDragEnterExitInPreN(event);
1664 }
1665
1666 if (target != null) {
1667 event.mAction = DragEvent.ACTION_DRAG_ENTERED;
1668 target.dispatchDragEnterExitInPreN(event);
1669 }
1670
1671 event.mAction = action;
1672 event.mX = tx;
1673 event.mY = ty;
Vadim Trysheva61efa42016-09-28 15:15:52 -07001674 event.mClipData = td;
Vadim Tryshevef128112016-09-16 14:05:53 -07001675 }
1676 mCurrentDragChild = target;
1677 }
1678
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001679 if (target == null && mIsInterestedInDrag) {
1680 target = this;
1681 }
Christopher Tatea53146c2010-09-07 11:57:52 -07001682
Vadim Tryshev1edc6daf2016-09-15 16:19:15 -07001683 // Dispatch the actual drag notice, localized into the target coordinates.
Christopher Tatea53146c2010-09-07 11:57:52 -07001684 if (target != null) {
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001685 if (target != this) {
1686 event.mX = localPoint.x;
1687 event.mY = localPoint.y;
Christopher Tatea53146c2010-09-07 11:57:52 -07001688
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001689 retval = target.dispatchDragEvent(event);
Christopher Tatea53146c2010-09-07 11:57:52 -07001690
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001691 event.mX = tx;
1692 event.mY = ty;
Vadim Tryshev1edc6daf2016-09-15 16:19:15 -07001693
Vadim Tryshev45bee6b2016-09-19 11:00:37 -07001694 if (mIsInterestedInDrag) {
1695 final boolean eventWasConsumed;
1696 if (sCascadedDragDrop) {
1697 eventWasConsumed = retval;
1698 } else {
1699 eventWasConsumed = event.mEventHandlerWasCalled;
1700 }
1701
1702 if (!eventWasConsumed) {
1703 retval = super.dispatchDragEvent(event);
1704 }
Vadim Tryshev1edc6daf2016-09-15 16:19:15 -07001705 }
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001706 } else {
1707 retval = super.dispatchDragEvent(event);
1708 }
Christopher Tatea53146c2010-09-07 11:57:52 -07001709 }
1710 } break;
Christopher Tatea53146c2010-09-07 11:57:52 -07001711 }
1712
Christopher Tatea53146c2010-09-07 11:57:52 -07001713 return retval;
1714 }
1715
1716 // Find the frontmost child view that lies under the given point, and calculate
1717 // the position within its own local coordinate system.
1718 View findFrontmostDroppableChildAt(float x, float y, PointF outLocalPoint) {
Christopher Tatea53146c2010-09-07 11:57:52 -07001719 final int count = mChildrenCount;
1720 final View[] children = mChildren;
1721 for (int i = count - 1; i >= 0; i--) {
1722 final View child = children[i];
Christopher Tate3d4bf172011-03-28 16:16:46 -07001723 if (!child.canAcceptDrag()) {
Christopher Tatea53146c2010-09-07 11:57:52 -07001724 continue;
1725 }
1726
Christopher Tate2c095f32010-10-04 14:13:40 -07001727 if (isTransformedTouchPointInView(x, y, child, outLocalPoint)) {
Christopher Tatea53146c2010-09-07 11:57:52 -07001728 return child;
1729 }
1730 }
1731 return null;
1732 }
1733
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001734 boolean notifyChildOfDragStart(View child) {
1735 // The caller guarantees that the child is not in mChildrenInterestedInDrag yet.
1736
Christopher Tate86cab1b2011-01-13 20:28:55 -08001737 if (ViewDebug.DEBUG_DRAG) {
1738 Log.d(View.VIEW_LOG_TAG, "Sending drag-started to view: " + child);
1739 }
1740
Vladislav Kaznacheevc2449702016-05-16 12:57:15 -07001741 final float tx = mCurrentDragStartEvent.mX;
1742 final float ty = mCurrentDragStartEvent.mY;
1743
1744 final float[] point = getTempPoint();
1745 point[0] = tx;
1746 point[1] = ty;
1747 transformPointToViewLocal(point, child);
1748
1749 mCurrentDragStartEvent.mX = point[0];
1750 mCurrentDragStartEvent.mY = point[1];
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001751 final boolean canAccept = child.dispatchDragEvent(mCurrentDragStartEvent);
Vladislav Kaznacheevc2449702016-05-16 12:57:15 -07001752 mCurrentDragStartEvent.mX = tx;
1753 mCurrentDragStartEvent.mY = ty;
Vadim Tryshev1edc6daf2016-09-15 16:19:15 -07001754 mCurrentDragStartEvent.mEventHandlerWasCalled = false;
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07001755 if (canAccept) {
1756 mChildrenInterestedInDrag.add(child);
1757 if (!child.canAcceptDrag()) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07001758 child.mPrivateFlags2 |= View.PFLAG2_DRAG_CAN_ACCEPT;
Christopher Tate3d4bf172011-03-28 16:16:46 -07001759 child.refreshDrawableState();
1760 }
Christopher Tate86cab1b2011-01-13 20:28:55 -08001761 }
Christopher Tate3d4bf172011-03-28 16:16:46 -07001762 return canAccept;
Christopher Tate86cab1b2011-01-13 20:28:55 -08001763 }
1764
Joe Onorato664644d2011-01-23 17:53:23 -08001765 @Override
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001766 public void dispatchWindowSystemUiVisiblityChanged(int visible) {
1767 super.dispatchWindowSystemUiVisiblityChanged(visible);
1768
1769 final int count = mChildrenCount;
1770 final View[] children = mChildren;
1771 for (int i=0; i <count; i++) {
1772 final View child = children[i];
1773 child.dispatchWindowSystemUiVisiblityChanged(visible);
1774 }
1775 }
1776
1777 @Override
Joe Onorato664644d2011-01-23 17:53:23 -08001778 public void dispatchSystemUiVisibilityChanged(int visible) {
1779 super.dispatchSystemUiVisibilityChanged(visible);
1780
1781 final int count = mChildrenCount;
1782 final View[] children = mChildren;
1783 for (int i=0; i <count; i++) {
1784 final View child = children[i];
1785 child.dispatchSystemUiVisibilityChanged(visible);
1786 }
1787 }
1788
Dianne Hackborn9a230e02011-10-06 11:51:27 -07001789 @Override
Dianne Hackborncf675782012-05-10 15:07:24 -07001790 boolean updateLocalSystemUiVisibility(int localValue, int localChanges) {
1791 boolean changed = super.updateLocalSystemUiVisibility(localValue, localChanges);
Dianne Hackborn9a230e02011-10-06 11:51:27 -07001792
1793 final int count = mChildrenCount;
1794 final View[] children = mChildren;
1795 for (int i=0; i <count; i++) {
1796 final View child = children[i];
Dianne Hackborncf675782012-05-10 15:07:24 -07001797 changed |= child.updateLocalSystemUiVisibility(localValue, localChanges);
Dianne Hackborn9a230e02011-10-06 11:51:27 -07001798 }
Dianne Hackborncf675782012-05-10 15:07:24 -07001799 return changed;
Dianne Hackborn9a230e02011-10-06 11:51:27 -07001800 }
1801
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001802 @Override
1803 public boolean dispatchKeyEventPreIme(KeyEvent event) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07001804 if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
1805 == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001806 return super.dispatchKeyEventPreIme(event);
Dianne Hackborn4702a852012-08-17 15:18:29 -07001807 } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
1808 == PFLAG_HAS_BOUNDS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001809 return mFocused.dispatchKeyEventPreIme(event);
1810 }
1811 return false;
1812 }
1813
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001814 @Override
1815 public boolean dispatchKeyEvent(KeyEvent event) {
Jeff Brown21bc5c92011-02-28 18:27:14 -08001816 if (mInputEventConsistencyVerifier != null) {
1817 mInputEventConsistencyVerifier.onKeyEvent(event, 1);
1818 }
1819
Dianne Hackborn4702a852012-08-17 15:18:29 -07001820 if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
1821 == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001822 if (super.dispatchKeyEvent(event)) {
1823 return true;
1824 }
Dianne Hackborn4702a852012-08-17 15:18:29 -07001825 } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
1826 == PFLAG_HAS_BOUNDS) {
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001827 if (mFocused.dispatchKeyEvent(event)) {
1828 return true;
1829 }
1830 }
1831
1832 if (mInputEventConsistencyVerifier != null) {
1833 mInputEventConsistencyVerifier.onUnhandledEvent(event, 1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001834 }
1835 return false;
1836 }
1837
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001838 @Override
1839 public boolean dispatchKeyShortcutEvent(KeyEvent event) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07001840 if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
1841 == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001842 return super.dispatchKeyShortcutEvent(event);
Dianne Hackborn4702a852012-08-17 15:18:29 -07001843 } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
1844 == PFLAG_HAS_BOUNDS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001845 return mFocused.dispatchKeyShortcutEvent(event);
1846 }
1847 return false;
1848 }
1849
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001850 @Override
1851 public boolean dispatchTrackballEvent(MotionEvent event) {
Jeff Brown21bc5c92011-02-28 18:27:14 -08001852 if (mInputEventConsistencyVerifier != null) {
1853 mInputEventConsistencyVerifier.onTrackballEvent(event, 1);
1854 }
1855
Dianne Hackborn4702a852012-08-17 15:18:29 -07001856 if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
1857 == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001858 if (super.dispatchTrackballEvent(event)) {
1859 return true;
1860 }
Dianne Hackborn4702a852012-08-17 15:18:29 -07001861 } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
1862 == PFLAG_HAS_BOUNDS) {
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001863 if (mFocused.dispatchTrackballEvent(event)) {
1864 return true;
1865 }
1866 }
1867
1868 if (mInputEventConsistencyVerifier != null) {
1869 mInputEventConsistencyVerifier.onUnhandledEvent(event, 1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001870 }
1871 return false;
1872 }
1873
Jun Mukai1db53972015-09-11 18:08:31 -07001874 @Override
Vladislav Kaznacheev3787de12016-12-21 10:36:35 -08001875 public boolean dispatchCapturedPointerEvent(MotionEvent event) {
1876 if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
1877 == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
1878 if (super.dispatchCapturedPointerEvent(event)) {
1879 return true;
1880 }
1881 } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
1882 == PFLAG_HAS_BOUNDS) {
1883 if (mFocused.dispatchCapturedPointerEvent(event)) {
1884 return true;
1885 }
1886 }
1887 return false;
1888 }
1889
1890 @Override
1891 public void dispatchPointerCaptureChanged(boolean hasCapture) {
1892 exitHoverTargets();
1893
1894 super.dispatchPointerCaptureChanged(hasCapture);
1895 final int count = mChildrenCount;
1896 final View[] children = mChildren;
1897 for (int i = 0; i < count; i++) {
1898 children[i].dispatchPointerCaptureChanged(hasCapture);
1899 }
1900 }
1901
1902 @Override
Michael Wrighte051f6f2016-05-13 17:44:16 +01001903 public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) {
1904 final float x = event.getX(pointerIndex);
1905 final float y = event.getY(pointerIndex);
Keisuke Kuroyanagid85bc502016-01-21 14:50:38 +09001906 if (isOnScrollbarThumb(x, y) || isDraggingScrollBar()) {
Michael Wrighte051f6f2016-05-13 17:44:16 +01001907 return PointerIcon.getSystemIcon(mContext, PointerIcon.TYPE_ARROW);
Keisuke Kuroyanagid85bc502016-01-21 14:50:38 +09001908 }
Jun Mukai1db53972015-09-11 18:08:31 -07001909 // Check what the child under the pointer says about the pointer.
1910 final int childrenCount = mChildrenCount;
1911 if (childrenCount != 0) {
1912 final ArrayList<View> preorderedList = buildOrderedChildList();
1913 final boolean customOrder = preorderedList == null
1914 && isChildrenDrawingOrderEnabled();
1915 final View[] children = mChildren;
1916 for (int i = childrenCount - 1; i >= 0; i--) {
Alan Viverettea7b85e62016-01-22 10:14:02 -05001917 final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
1918 final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);
Vladislav Kaznacheev3d5cfc02017-01-05 17:50:38 -08001919 if (!canViewReceivePointerEvents(child)
1920 || !isTransformedTouchPointInView(x, y, child, null)) {
1921 continue;
1922 }
1923 final PointerIcon pointerIcon =
1924 dispatchResolvePointerIcon(event, pointerIndex, child);
1925 if (pointerIcon != null) {
1926 if (preorderedList != null) preorderedList.clear();
1927 return pointerIcon;
Jun Mukai1db53972015-09-11 18:08:31 -07001928 }
1929 }
Chris Craikfc563772016-05-04 13:34:30 -07001930 if (preorderedList != null) preorderedList.clear();
Jun Mukai1db53972015-09-11 18:08:31 -07001931 }
1932
1933 // The pointer is not a child or the child has no preferences, returning the default
1934 // implementation.
Michael Wrighte051f6f2016-05-13 17:44:16 +01001935 return super.onResolvePointerIcon(event, pointerIndex);
1936 }
1937
1938 private PointerIcon dispatchResolvePointerIcon(MotionEvent event, int pointerIndex,
1939 View child) {
1940 final PointerIcon pointerIcon;
1941 if (!child.hasIdentityMatrix()) {
1942 MotionEvent transformedEvent = getTransformedMotionEvent(event, child);
1943 pointerIcon = child.onResolvePointerIcon(transformedEvent, pointerIndex);
1944 transformedEvent.recycle();
1945 } else {
1946 final float offsetX = mScrollX - child.mLeft;
1947 final float offsetY = mScrollY - child.mTop;
1948 event.offsetLocation(offsetX, offsetY);
1949 pointerIcon = child.onResolvePointerIcon(event, pointerIndex);
1950 event.offsetLocation(-offsetX, -offsetY);
1951 }
1952 return pointerIcon;
Jun Mukai1db53972015-09-11 18:08:31 -07001953 }
1954
Alan Viverettea7b85e62016-01-22 10:14:02 -05001955 private int getAndVerifyPreorderedIndex(int childrenCount, int i, boolean customOrder) {
1956 final int childIndex;
1957 if (customOrder) {
1958 final int childIndex1 = getChildDrawingOrder(childrenCount, i);
1959 if (childIndex1 >= childrenCount) {
1960 throw new IndexOutOfBoundsException("getChildDrawingOrder() "
1961 + "returned invalid index " + childIndex1
1962 + " (child count is " + childrenCount + ")");
1963 }
1964 childIndex = childIndex1;
1965 } else {
1966 childIndex = i;
1967 }
1968 return childIndex;
1969 }
1970
Romain Guya9489272011-06-22 20:58:11 -07001971 @SuppressWarnings({"ConstantConditions"})
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001972 @Override
Jeff Browna032cc02011-03-07 16:56:21 -08001973 protected boolean dispatchHoverEvent(MotionEvent event) {
Jeff Browna032cc02011-03-07 16:56:21 -08001974 final int action = event.getAction();
Jeff Browna032cc02011-03-07 16:56:21 -08001975
Jeff Brown10b62902011-06-20 16:40:37 -07001976 // First check whether the view group wants to intercept the hover event.
1977 final boolean interceptHover = onInterceptHoverEvent(event);
1978 event.setAction(action); // restore action in case it was changed
1979
Jeff Brown87b7f802011-06-21 18:35:45 -07001980 MotionEvent eventNoHistory = event;
1981 boolean handled = false;
1982
1983 // Send events to the hovered children and build a new list of hover targets until
1984 // one is found that handles the event.
1985 HoverTarget firstOldHoverTarget = mFirstHoverTarget;
1986 mFirstHoverTarget = null;
Jeff Brown10b62902011-06-20 16:40:37 -07001987 if (!interceptHover && action != MotionEvent.ACTION_HOVER_EXIT) {
Jeff Browna032cc02011-03-07 16:56:21 -08001988 final float x = event.getX();
1989 final float y = event.getY();
Jeff Brown33bbfd22011-02-24 20:55:35 -08001990 final int childrenCount = mChildrenCount;
1991 if (childrenCount != 0) {
Chris Craikab008f02014-05-23 17:55:03 -07001992 final ArrayList<View> preorderedList = buildOrderedChildList();
1993 final boolean customOrder = preorderedList == null
1994 && isChildrenDrawingOrderEnabled();
Jeff Brown33bbfd22011-02-24 20:55:35 -08001995 final View[] children = mChildren;
Jeff Brown87b7f802011-06-21 18:35:45 -07001996 HoverTarget lastHoverTarget = null;
Jeff Brown33bbfd22011-02-24 20:55:35 -08001997 for (int i = childrenCount - 1; i >= 0; i--) {
Alan Viverettea7b85e62016-01-22 10:14:02 -05001998 final int childIndex = getAndVerifyPreorderedIndex(
1999 childrenCount, i, customOrder);
2000 final View child = getAndVerifyPreorderedView(
2001 preorderedList, children, childIndex);
Jeff Brown87b7f802011-06-21 18:35:45 -07002002 if (!canViewReceivePointerEvents(child)
2003 || !isTransformedTouchPointInView(x, y, child, null)) {
2004 continue;
2005 }
2006
2007 // Obtain a hover target for this child. Dequeue it from the
2008 // old hover target list if the child was previously hovered.
2009 HoverTarget hoverTarget = firstOldHoverTarget;
2010 final boolean wasHovered;
2011 for (HoverTarget predecessor = null; ;) {
2012 if (hoverTarget == null) {
2013 hoverTarget = HoverTarget.obtain(child);
2014 wasHovered = false;
2015 break;
2016 }
2017
2018 if (hoverTarget.child == child) {
2019 if (predecessor != null) {
2020 predecessor.next = hoverTarget.next;
2021 } else {
2022 firstOldHoverTarget = hoverTarget.next;
2023 }
2024 hoverTarget.next = null;
2025 wasHovered = true;
2026 break;
2027 }
2028
2029 predecessor = hoverTarget;
2030 hoverTarget = hoverTarget.next;
2031 }
2032
2033 // Enqueue the hover target onto the new hover target list.
2034 if (lastHoverTarget != null) {
2035 lastHoverTarget.next = hoverTarget;
2036 } else {
Jeff Brown87b7f802011-06-21 18:35:45 -07002037 mFirstHoverTarget = hoverTarget;
2038 }
Sangkyu Lee8725f362013-03-13 09:38:45 +09002039 lastHoverTarget = hoverTarget;
Jeff Brown87b7f802011-06-21 18:35:45 -07002040
2041 // Dispatch the event to the child.
2042 if (action == MotionEvent.ACTION_HOVER_ENTER) {
2043 if (!wasHovered) {
2044 // Send the enter as is.
2045 handled |= dispatchTransformedGenericPointerEvent(
2046 event, child); // enter
2047 }
2048 } else if (action == MotionEvent.ACTION_HOVER_MOVE) {
2049 if (!wasHovered) {
2050 // Synthesize an enter from a move.
2051 eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory);
2052 eventNoHistory.setAction(MotionEvent.ACTION_HOVER_ENTER);
2053 handled |= dispatchTransformedGenericPointerEvent(
2054 eventNoHistory, child); // enter
2055 eventNoHistory.setAction(action);
2056
2057 handled |= dispatchTransformedGenericPointerEvent(
2058 eventNoHistory, child); // move
2059 } else {
2060 // Send the move as is.
2061 handled |= dispatchTransformedGenericPointerEvent(event, child);
2062 }
2063 }
2064 if (handled) {
Jeff Brown10b62902011-06-20 16:40:37 -07002065 break;
Jeff Brown33bbfd22011-02-24 20:55:35 -08002066 }
Jeff Brown10b62902011-06-20 16:40:37 -07002067 }
Chris Craikab008f02014-05-23 17:55:03 -07002068 if (preorderedList != null) preorderedList.clear();
Jeff Brown10b62902011-06-20 16:40:37 -07002069 }
2070 }
Jeff Brown33bbfd22011-02-24 20:55:35 -08002071
Jeff Brown87b7f802011-06-21 18:35:45 -07002072 // Send exit events to all previously hovered children that are no longer hovered.
2073 while (firstOldHoverTarget != null) {
2074 final View child = firstOldHoverTarget.child;
Jeff Brown10b62902011-06-20 16:40:37 -07002075
Jeff Brown87b7f802011-06-21 18:35:45 -07002076 // Exit the old hovered child.
2077 if (action == MotionEvent.ACTION_HOVER_EXIT) {
2078 // Send the exit as is.
2079 handled |= dispatchTransformedGenericPointerEvent(
2080 event, child); // exit
2081 } else {
2082 // Synthesize an exit from a move or enter.
2083 // Ignore the result because hover focus has moved to a different view.
2084 if (action == MotionEvent.ACTION_HOVER_MOVE) {
Vladislav Kaznacheev5a77c372016-10-10 16:11:15 -07002085 final boolean hoverExitPending = event.isHoverExitPending();
2086 event.setHoverExitPending(true);
Jeff Brown10b62902011-06-20 16:40:37 -07002087 dispatchTransformedGenericPointerEvent(
Jeff Brown87b7f802011-06-21 18:35:45 -07002088 event, child); // move
Vladislav Kaznacheev5a77c372016-10-10 16:11:15 -07002089 event.setHoverExitPending(hoverExitPending);
Jeff Brown10b62902011-06-20 16:40:37 -07002090 }
Jeff Brown87b7f802011-06-21 18:35:45 -07002091 eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory);
2092 eventNoHistory.setAction(MotionEvent.ACTION_HOVER_EXIT);
2093 dispatchTransformedGenericPointerEvent(
2094 eventNoHistory, child); // exit
2095 eventNoHistory.setAction(action);
Jeff Brown10b62902011-06-20 16:40:37 -07002096 }
2097
Jeff Brown87b7f802011-06-21 18:35:45 -07002098 final HoverTarget nextOldHoverTarget = firstOldHoverTarget.next;
2099 firstOldHoverTarget.recycle();
2100 firstOldHoverTarget = nextOldHoverTarget;
Jeff Brown10b62902011-06-20 16:40:37 -07002101 }
2102
Vladislav Kaznacheev5a77c372016-10-10 16:11:15 -07002103 // Send events to the view group itself if no children have handled it and the view group
2104 // itself is not currently being hover-exited.
2105 boolean newHoveredSelf = !handled &&
2106 (action != MotionEvent.ACTION_HOVER_EXIT) && !event.isHoverExitPending();
Jeff Brown10b62902011-06-20 16:40:37 -07002107 if (newHoveredSelf == mHoveredSelf) {
2108 if (newHoveredSelf) {
2109 // Send event to the view group as before.
2110 handled |= super.dispatchHoverEvent(event);
2111 }
2112 } else {
2113 if (mHoveredSelf) {
2114 // Exit the view group.
2115 if (action == MotionEvent.ACTION_HOVER_EXIT) {
2116 // Send the exit as is.
2117 handled |= super.dispatchHoverEvent(event); // exit
2118 } else {
2119 // Synthesize an exit from a move or enter.
2120 // Ignore the result because hover focus is moving to a different view.
2121 if (action == MotionEvent.ACTION_HOVER_MOVE) {
2122 super.dispatchHoverEvent(event); // move
2123 }
2124 eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory);
2125 eventNoHistory.setAction(MotionEvent.ACTION_HOVER_EXIT);
2126 super.dispatchHoverEvent(eventNoHistory); // exit
2127 eventNoHistory.setAction(action);
2128 }
2129 mHoveredSelf = false;
2130 }
2131
2132 if (newHoveredSelf) {
2133 // Enter the view group.
2134 if (action == MotionEvent.ACTION_HOVER_ENTER) {
2135 // Send the enter as is.
2136 handled |= super.dispatchHoverEvent(event); // enter
2137 mHoveredSelf = true;
2138 } else if (action == MotionEvent.ACTION_HOVER_MOVE) {
2139 // Synthesize an enter from a move.
2140 eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory);
2141 eventNoHistory.setAction(MotionEvent.ACTION_HOVER_ENTER);
2142 handled |= super.dispatchHoverEvent(eventNoHistory); // enter
2143 eventNoHistory.setAction(action);
2144
2145 handled |= super.dispatchHoverEvent(eventNoHistory); // move
2146 mHoveredSelf = true;
Jeff Brown33bbfd22011-02-24 20:55:35 -08002147 }
2148 }
Jeff Brown33bbfd22011-02-24 20:55:35 -08002149 }
2150
Jeff Browna032cc02011-03-07 16:56:21 -08002151 // Recycle the copy of the event that we made.
2152 if (eventNoHistory != event) {
2153 eventNoHistory.recycle();
2154 }
2155
Jeff Browna032cc02011-03-07 16:56:21 -08002156 // Done.
2157 return handled;
2158 }
2159
Jeff Brown59a422e2012-04-19 15:19:19 -07002160 private void exitHoverTargets() {
2161 if (mHoveredSelf || mFirstHoverTarget != null) {
2162 final long now = SystemClock.uptimeMillis();
2163 MotionEvent event = MotionEvent.obtain(now, now,
2164 MotionEvent.ACTION_HOVER_EXIT, 0.0f, 0.0f, 0);
2165 event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
2166 dispatchHoverEvent(event);
2167 event.recycle();
2168 }
2169 }
2170
2171 private void cancelHoverTarget(View view) {
2172 HoverTarget predecessor = null;
2173 HoverTarget target = mFirstHoverTarget;
2174 while (target != null) {
2175 final HoverTarget next = target.next;
2176 if (target.child == view) {
2177 if (predecessor == null) {
2178 mFirstHoverTarget = next;
2179 } else {
2180 predecessor.next = next;
2181 }
2182 target.recycle();
2183
2184 final long now = SystemClock.uptimeMillis();
2185 MotionEvent event = MotionEvent.obtain(now, now,
2186 MotionEvent.ACTION_HOVER_EXIT, 0.0f, 0.0f, 0);
2187 event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
2188 view.dispatchHoverEvent(event);
2189 event.recycle();
2190 return;
2191 }
2192 predecessor = target;
2193 target = next;
2194 }
2195 }
2196
Vladislav Kaznacheevf847ee32016-11-21 14:11:00 -08002197 @Override
2198 boolean dispatchTooltipHoverEvent(MotionEvent event) {
2199 final int action = event.getAction();
2200 switch (action) {
2201 case MotionEvent.ACTION_HOVER_ENTER:
2202 break;
2203
2204 case MotionEvent.ACTION_HOVER_MOVE:
2205 View newTarget = null;
2206
2207 // Check what the child under the pointer says about the tooltip.
2208 final int childrenCount = mChildrenCount;
2209 if (childrenCount != 0) {
2210 final float x = event.getX();
2211 final float y = event.getY();
2212
2213 final ArrayList<View> preorderedList = buildOrderedChildList();
2214 final boolean customOrder = preorderedList == null
2215 && isChildrenDrawingOrderEnabled();
2216 final View[] children = mChildren;
2217 for (int i = childrenCount - 1; i >= 0; i--) {
2218 final int childIndex =
2219 getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
2220 final View child =
2221 getAndVerifyPreorderedView(preorderedList, children, childIndex);
Vladislav Kaznacheev943cf0e2017-01-06 09:52:51 -08002222 if (!canViewReceivePointerEvents(child)
2223 || !isTransformedTouchPointInView(x, y, child, null)) {
2224 continue;
2225 }
2226 if (dispatchTooltipHoverEvent(event, child)) {
2227 newTarget = child;
Vladislav Kaznacheevf847ee32016-11-21 14:11:00 -08002228 break;
2229 }
2230 }
2231 if (preorderedList != null) preorderedList.clear();
2232 }
2233
2234 if (mTooltipHoverTarget != newTarget) {
2235 if (mTooltipHoverTarget != null) {
2236 event.setAction(MotionEvent.ACTION_HOVER_EXIT);
2237 mTooltipHoverTarget.dispatchTooltipHoverEvent(event);
2238 event.setAction(action);
2239 }
2240 mTooltipHoverTarget = newTarget;
2241 }
2242
2243 if (mTooltipHoverTarget != null) {
2244 if (mTooltipHoveredSelf) {
2245 mTooltipHoveredSelf = false;
2246 event.setAction(MotionEvent.ACTION_HOVER_EXIT);
2247 super.dispatchTooltipHoverEvent(event);
2248 event.setAction(action);
2249 }
2250 return true;
2251 }
2252
2253 mTooltipHoveredSelf = super.dispatchTooltipHoverEvent(event);
2254 return mTooltipHoveredSelf;
2255
2256 case MotionEvent.ACTION_HOVER_EXIT:
2257 if (mTooltipHoverTarget != null) {
2258 mTooltipHoverTarget.dispatchTooltipHoverEvent(event);
2259 mTooltipHoverTarget = null;
2260 } else if (mTooltipHoveredSelf) {
2261 super.dispatchTooltipHoverEvent(event);
2262 mTooltipHoveredSelf = false;
2263 }
2264 break;
2265 }
2266 return false;
2267 }
2268
2269 private boolean dispatchTooltipHoverEvent(MotionEvent event, View child) {
2270 final boolean result;
2271 if (!child.hasIdentityMatrix()) {
2272 MotionEvent transformedEvent = getTransformedMotionEvent(event, child);
2273 result = child.dispatchTooltipHoverEvent(transformedEvent);
2274 transformedEvent.recycle();
2275 } else {
2276 final float offsetX = mScrollX - child.mLeft;
2277 final float offsetY = mScrollY - child.mTop;
2278 event.offsetLocation(offsetX, offsetY);
2279 result = child.dispatchTooltipHoverEvent(event);
2280 event.offsetLocation(-offsetX, -offsetY);
2281 }
2282 return result;
2283 }
2284
2285 private void exitTooltipHoverTargets() {
2286 if (mTooltipHoveredSelf || mTooltipHoverTarget != null) {
2287 final long now = SystemClock.uptimeMillis();
2288 MotionEvent event = MotionEvent.obtain(now, now,
2289 MotionEvent.ACTION_HOVER_EXIT, 0.0f, 0.0f, 0);
2290 event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
2291 dispatchTooltipHoverEvent(event);
2292 event.recycle();
2293 }
2294 }
2295
Jeff Brown87b7f802011-06-21 18:35:45 -07002296 /** @hide */
2297 @Override
2298 protected boolean hasHoveredChild() {
2299 return mFirstHoverTarget != null;
2300 }
2301
Svetoslav Ganov42138042012-03-20 11:51:39 -07002302 @Override
Adam Powellcf392d12015-06-25 14:48:45 -07002303 public void addChildrenForAccessibility(ArrayList<View> outChildren) {
Svetoslav762621c2015-06-01 17:21:59 -07002304 if (getAccessibilityNodeProvider() != null) {
2305 return;
2306 }
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07002307 ChildListForAccessibility children = ChildListForAccessibility.obtain(this, true);
2308 try {
2309 final int childrenCount = children.getChildCount();
2310 for (int i = 0; i < childrenCount; i++) {
2311 View child = children.getChildAt(i);
Svetoslav Ganovc406be92012-05-11 16:12:32 -07002312 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07002313 if (child.includeForAccessibility()) {
Adam Powellcf392d12015-06-25 14:48:45 -07002314 outChildren.add(child);
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07002315 } else {
Adam Powellcf392d12015-06-25 14:48:45 -07002316 child.addChildrenForAccessibility(outChildren);
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07002317 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07002318 }
2319 }
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07002320 } finally {
2321 children.recycle();
Svetoslav Ganov42138042012-03-20 11:51:39 -07002322 }
2323 }
2324
2325 /**
Jeff Brown10b62902011-06-20 16:40:37 -07002326 * Implement this method to intercept hover events before they are handled
2327 * by child views.
2328 * <p>
2329 * This method is called before dispatching a hover event to a child of
2330 * the view group or to the view group's own {@link #onHoverEvent} to allow
2331 * the view group a chance to intercept the hover event.
2332 * This method can also be used to watch all pointer motions that occur within
2333 * the bounds of the view group even when the pointer is hovering over
2334 * a child of the view group rather than over the view group itself.
2335 * </p><p>
2336 * The view group can prevent its children from receiving hover events by
2337 * implementing this method and returning <code>true</code> to indicate
2338 * that it would like to intercept hover events. The view group must
2339 * continuously return <code>true</code> from {@link #onInterceptHoverEvent}
2340 * for as long as it wishes to continue intercepting hover events from
2341 * its children.
2342 * </p><p>
2343 * Interception preserves the invariant that at most one view can be
2344 * hovered at a time by transferring hover focus from the currently hovered
2345 * child to the view group or vice-versa as needed.
2346 * </p><p>
2347 * If this method returns <code>true</code> and a child is already hovered, then the
2348 * child view will first receive a hover exit event and then the view group
2349 * itself will receive a hover enter event in {@link #onHoverEvent}.
2350 * Likewise, if this method had previously returned <code>true</code> to intercept hover
2351 * events and instead returns <code>false</code> while the pointer is hovering
2352 * within the bounds of one of a child, then the view group will first receive a
2353 * hover exit event in {@link #onHoverEvent} and then the hovered child will
2354 * receive a hover enter event.
2355 * </p><p>
Keisuke Kuroyanagid85bc502016-01-21 14:50:38 +09002356 * The default implementation handles mouse hover on the scroll bars.
Jeff Brown10b62902011-06-20 16:40:37 -07002357 * </p>
2358 *
2359 * @param event The motion event that describes the hover.
2360 * @return True if the view group would like to intercept the hover event
2361 * and prevent its children from receiving it.
2362 */
2363 public boolean onInterceptHoverEvent(MotionEvent event) {
Keisuke Kuroyanagid85bc502016-01-21 14:50:38 +09002364 if (event.isFromSource(InputDevice.SOURCE_MOUSE)) {
2365 final int action = event.getAction();
2366 final float x = event.getX();
2367 final float y = event.getY();
2368 if ((action == MotionEvent.ACTION_HOVER_MOVE
2369 || action == MotionEvent.ACTION_HOVER_ENTER) && isOnScrollbar(x, y)) {
2370 return true;
2371 }
2372 }
Svetoslav Ganov736c2752011-04-22 18:30:36 -07002373 return false;
2374 }
2375
Jeff Browna032cc02011-03-07 16:56:21 -08002376 private static MotionEvent obtainMotionEventNoHistoryOrSelf(MotionEvent event) {
2377 if (event.getHistorySize() == 0) {
2378 return event;
2379 }
2380 return MotionEvent.obtainNoHistory(event);
2381 }
2382
Jeff Browna032cc02011-03-07 16:56:21 -08002383 @Override
2384 protected boolean dispatchGenericPointerEvent(MotionEvent event) {
2385 // Send the event to the child under the pointer.
2386 final int childrenCount = mChildrenCount;
2387 if (childrenCount != 0) {
Jeff Browna032cc02011-03-07 16:56:21 -08002388 final float x = event.getX();
2389 final float y = event.getY();
2390
Chris Craikab008f02014-05-23 17:55:03 -07002391 final ArrayList<View> preorderedList = buildOrderedChildList();
2392 final boolean customOrder = preorderedList == null
2393 && isChildrenDrawingOrderEnabled();
2394 final View[] children = mChildren;
Jeff Browna032cc02011-03-07 16:56:21 -08002395 for (int i = childrenCount - 1; i >= 0; i--) {
Alan Viverettea7b85e62016-01-22 10:14:02 -05002396 final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
2397 final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);
Jeff Browna032cc02011-03-07 16:56:21 -08002398 if (!canViewReceivePointerEvents(child)
2399 || !isTransformedTouchPointInView(x, y, child, null)) {
2400 continue;
2401 }
2402
2403 if (dispatchTransformedGenericPointerEvent(event, child)) {
Chris Craikab008f02014-05-23 17:55:03 -07002404 if (preorderedList != null) preorderedList.clear();
Jeff Browna032cc02011-03-07 16:56:21 -08002405 return true;
2406 }
2407 }
Chris Craikab008f02014-05-23 17:55:03 -07002408 if (preorderedList != null) preorderedList.clear();
Jeff Browna032cc02011-03-07 16:56:21 -08002409 }
2410
2411 // No child handled the event. Send it to this view group.
2412 return super.dispatchGenericPointerEvent(event);
2413 }
2414
Jeff Browna032cc02011-03-07 16:56:21 -08002415 @Override
2416 protected boolean dispatchGenericFocusedEvent(MotionEvent event) {
Jeff Brown33bbfd22011-02-24 20:55:35 -08002417 // Send the event to the focused child or to this view group if it has focus.
Dianne Hackborn4702a852012-08-17 15:18:29 -07002418 if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
2419 == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
Jeff Browna032cc02011-03-07 16:56:21 -08002420 return super.dispatchGenericFocusedEvent(event);
Dianne Hackborn4702a852012-08-17 15:18:29 -07002421 } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
2422 == PFLAG_HAS_BOUNDS) {
Jeff Browncb1404e2011-01-15 18:14:15 -08002423 return mFocused.dispatchGenericMotionEvent(event);
2424 }
2425 return false;
2426 }
2427
2428 /**
Jeff Browna032cc02011-03-07 16:56:21 -08002429 * Dispatches a generic pointer event to a child, taking into account
2430 * transformations that apply to the child.
2431 *
2432 * @param event The event to send.
2433 * @param child The view to send the event to.
2434 * @return {@code true} if the child handled the event.
2435 */
2436 private boolean dispatchTransformedGenericPointerEvent(MotionEvent event, View child) {
Jeff Browna032cc02011-03-07 16:56:21 -08002437 boolean handled;
2438 if (!child.hasIdentityMatrix()) {
Michael Wrighte051f6f2016-05-13 17:44:16 +01002439 MotionEvent transformedEvent = getTransformedMotionEvent(event, child);
Jeff Browna032cc02011-03-07 16:56:21 -08002440 handled = child.dispatchGenericMotionEvent(transformedEvent);
2441 transformedEvent.recycle();
2442 } else {
Michael Wrighte051f6f2016-05-13 17:44:16 +01002443 final float offsetX = mScrollX - child.mLeft;
2444 final float offsetY = mScrollY - child.mTop;
Jeff Browna032cc02011-03-07 16:56:21 -08002445 event.offsetLocation(offsetX, offsetY);
2446 handled = child.dispatchGenericMotionEvent(event);
2447 event.offsetLocation(-offsetX, -offsetY);
2448 }
2449 return handled;
2450 }
2451
Michael Wrighte051f6f2016-05-13 17:44:16 +01002452 /**
2453 * Returns a MotionEvent that's been transformed into the child's local coordinates.
2454 *
2455 * It's the responsibility of the caller to recycle it once they're finished with it.
2456 * @param event The event to transform.
2457 * @param child The view whose coordinate space is to be used.
2458 * @return A copy of the the given MotionEvent, transformed into the given View's coordinate
2459 * space.
2460 */
2461 private MotionEvent getTransformedMotionEvent(MotionEvent event, View child) {
2462 final float offsetX = mScrollX - child.mLeft;
2463 final float offsetY = mScrollY - child.mTop;
2464 final MotionEvent transformedEvent = MotionEvent.obtain(event);
2465 transformedEvent.offsetLocation(offsetX, offsetY);
2466 if (!child.hasIdentityMatrix()) {
2467 transformedEvent.transform(child.getInverseMatrix());
2468 }
2469 return transformedEvent;
2470 }
2471
Jeff Browncb1404e2011-01-15 18:14:15 -08002472 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002473 public boolean dispatchTouchEvent(MotionEvent ev) {
Jeff Brown21bc5c92011-02-28 18:27:14 -08002474 if (mInputEventConsistencyVerifier != null) {
2475 mInputEventConsistencyVerifier.onTouchEvent(ev, 1);
2476 }
2477
Svet Ganov0a2ccee2015-02-06 10:12:32 -08002478 // If the event targets the accessibility focused view and this is it, start
2479 // normal event dispatch. Maybe a descendant is what will handle the click.
Svet Ganovf33fe1f2015-02-06 19:23:31 -08002480 if (ev.isTargetAccessibilityFocus() && isAccessibilityFocusedViewOrHost()) {
Svet Ganov0a2ccee2015-02-06 10:12:32 -08002481 ev.setTargetAccessibilityFocus(false);
2482 }
2483
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002484 boolean handled = false;
2485 if (onFilterTouchEventForSecurity(ev)) {
2486 final int action = ev.getAction();
2487 final int actionMasked = action & MotionEvent.ACTION_MASK;
Jeff Brown85a31762010-09-01 17:01:00 -07002488
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002489 // Handle an initial down.
2490 if (actionMasked == MotionEvent.ACTION_DOWN) {
2491 // Throw away all previous state when starting a new touch gesture.
2492 // The framework may have dropped the up or cancel event for the previous gesture
2493 // due to an app switch, ANR, or some other state change.
2494 cancelAndClearTouchTargets(ev);
2495 resetTouchState();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002496 }
Adam Powellb08013c2010-09-16 16:28:11 -07002497
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002498 // Check for interception.
2499 final boolean intercepted;
Svet Ganovf33fe1f2015-02-06 19:23:31 -08002500 if (actionMasked == MotionEvent.ACTION_DOWN
2501 || mFirstTouchTarget != null) {
2502 final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
2503 if (!disallowIntercept) {
2504 intercepted = onInterceptTouchEvent(ev);
2505 ev.setAction(action); // restore action in case it was changed
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002506 } else {
Svet Ganovf33fe1f2015-02-06 19:23:31 -08002507 intercepted = false;
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002508 }
2509 } else {
Svet Ganovf33fe1f2015-02-06 19:23:31 -08002510 // There are no touch targets and this action is not an initial down
2511 // so this view group continues to intercept touches.
2512 intercepted = true;
2513 }
2514
2515 // If intercepted, start normal event dispatch. Also if there is already
2516 // a view that is handling the gesture, do normal event dispatch.
2517 if (intercepted || mFirstTouchTarget != null) {
2518 ev.setTargetAccessibilityFocus(false);
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002519 }
Jeff Brown20e987b2010-08-23 12:01:02 -07002520
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002521 // Check for cancelation.
2522 final boolean canceled = resetCancelNextUpFlag(this)
2523 || actionMasked == MotionEvent.ACTION_CANCEL;
Jeff Brown20e987b2010-08-23 12:01:02 -07002524
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002525 // Update list of touch targets for pointer down, if needed.
2526 final boolean split = (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) != 0;
2527 TouchTarget newTouchTarget = null;
2528 boolean alreadyDispatchedToNewTouchTarget = false;
2529 if (!canceled && !intercepted) {
Svetoslavc73cfa02015-02-09 17:14:28 -08002530
2531 // If the event is targeting accessiiblity focus we give it to the
2532 // view that has accessibility focus and if it does not handle it
2533 // we clear the flag and dispatch the event to all children as usual.
2534 // We are looking up the accessibility focused host to avoid keeping
2535 // state since these events are very rare.
2536 View childWithAccessibilityFocus = ev.isTargetAccessibilityFocus()
2537 ? findChildWithAccessibilityFocus() : null;
2538
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002539 if (actionMasked == MotionEvent.ACTION_DOWN
2540 || (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN)
Svet Ganovf33fe1f2015-02-06 19:23:31 -08002541 || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002542 final int actionIndex = ev.getActionIndex(); // always 0 for down
2543 final int idBitsToAssign = split ? 1 << ev.getPointerId(actionIndex)
2544 : TouchTarget.ALL_POINTER_IDS;
Jeff Brown20e987b2010-08-23 12:01:02 -07002545
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002546 // Clean up earlier touch targets for this pointer id in case they
2547 // have become out of sync.
2548 removePointersFromTouchTargets(idBitsToAssign);
2549
2550 final int childrenCount = mChildrenCount;
Chet Haase9c17fe62013-03-22 17:05:55 -07002551 if (newTouchTarget == null && childrenCount != 0) {
Chet Haaseedf6f4b2013-03-26 07:55:30 -07002552 final float x = ev.getX(actionIndex);
2553 final float y = ev.getY(actionIndex);
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002554 // Find a child that can receive the event.
2555 // Scan children from front to back.
Filip Gruszczynskia33bdf32015-11-19 18:22:16 -08002556 final ArrayList<View> preorderedList = buildTouchDispatchChildList();
Chris Craikab008f02014-05-23 17:55:03 -07002557 final boolean customOrder = preorderedList == null
2558 && isChildrenDrawingOrderEnabled();
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002559 final View[] children = mChildren;
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002560 for (int i = childrenCount - 1; i >= 0; i--) {
Alan Viverettea7b85e62016-01-22 10:14:02 -05002561 final int childIndex = getAndVerifyPreorderedIndex(
2562 childrenCount, i, customOrder);
2563 final View child = getAndVerifyPreorderedView(
2564 preorderedList, children, childIndex);
Svetoslavc73cfa02015-02-09 17:14:28 -08002565
2566 // If there is a view that has accessibility focus we want it
2567 // to get the event first and if not handled we will perform a
2568 // normal dispatch. We may do a double iteration but this is
2569 // safer given the timeframe.
2570 if (childWithAccessibilityFocus != null) {
2571 if (childWithAccessibilityFocus != child) {
2572 continue;
2573 }
2574 childWithAccessibilityFocus = null;
2575 i = childrenCount - 1;
2576 }
2577
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002578 if (!canViewReceivePointerEvents(child)
2579 || !isTransformedTouchPointInView(x, y, child, null)) {
Svetoslavc73cfa02015-02-09 17:14:28 -08002580 ev.setTargetAccessibilityFocus(false);
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002581 continue;
2582 }
2583
2584 newTouchTarget = getTouchTarget(child);
2585 if (newTouchTarget != null) {
2586 // Child is already receiving touch within its bounds.
2587 // Give it the new pointer in addition to the ones it is handling.
2588 newTouchTarget.pointerIdBits |= idBitsToAssign;
2589 break;
2590 }
2591
2592 resetCancelNextUpFlag(child);
2593 if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
2594 // Child wants to receive touch within its bounds.
2595 mLastTouchDownTime = ev.getDownTime();
Chris Craikab008f02014-05-23 17:55:03 -07002596 if (preorderedList != null) {
2597 // childIndex points into presorted list, find original index
2598 for (int j = 0; j < childrenCount; j++) {
2599 if (children[childIndex] == mChildren[j]) {
2600 mLastTouchDownIndex = j;
2601 break;
2602 }
2603 }
2604 } else {
2605 mLastTouchDownIndex = childIndex;
2606 }
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002607 mLastTouchDownX = ev.getX();
2608 mLastTouchDownY = ev.getY();
2609 newTouchTarget = addTouchTarget(child, idBitsToAssign);
2610 alreadyDispatchedToNewTouchTarget = true;
2611 break;
2612 }
Svetoslavc73cfa02015-02-09 17:14:28 -08002613
2614 // The accessibility focus didn't handle the event, so clear
2615 // the flag and do a normal dispatch to all children.
2616 ev.setTargetAccessibilityFocus(false);
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002617 }
Chris Craikab008f02014-05-23 17:55:03 -07002618 if (preorderedList != null) preorderedList.clear();
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002619 }
2620
2621 if (newTouchTarget == null && mFirstTouchTarget != null) {
2622 // Did not find a child to receive the event.
2623 // Assign the pointer to the least recently added target.
2624 newTouchTarget = mFirstTouchTarget;
2625 while (newTouchTarget.next != null) {
2626 newTouchTarget = newTouchTarget.next;
2627 }
2628 newTouchTarget.pointerIdBits |= idBitsToAssign;
2629 }
2630 }
2631 }
2632
2633 // Dispatch to touch targets.
2634 if (mFirstTouchTarget == null) {
2635 // No touch targets so treat this as an ordinary view.
2636 handled = dispatchTransformedTouchEvent(ev, canceled, null,
2637 TouchTarget.ALL_POINTER_IDS);
2638 } else {
2639 // Dispatch to touch targets, excluding the new touch target if we already
2640 // dispatched to it. Cancel touch targets if necessary.
2641 TouchTarget predecessor = null;
2642 TouchTarget target = mFirstTouchTarget;
2643 while (target != null) {
2644 final TouchTarget next = target.next;
2645 if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {
2646 handled = true;
2647 } else {
2648 final boolean cancelChild = resetCancelNextUpFlag(target.child)
Chet Haase9c17fe62013-03-22 17:05:55 -07002649 || intercepted;
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002650 if (dispatchTransformedTouchEvent(ev, cancelChild,
2651 target.child, target.pointerIdBits)) {
2652 handled = true;
2653 }
2654 if (cancelChild) {
2655 if (predecessor == null) {
2656 mFirstTouchTarget = next;
2657 } else {
2658 predecessor.next = next;
2659 }
2660 target.recycle();
2661 target = next;
Jeff Brown20e987b2010-08-23 12:01:02 -07002662 continue;
2663 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002664 }
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002665 predecessor = target;
2666 target = next;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002667 }
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002668 }
Jeff Brown20e987b2010-08-23 12:01:02 -07002669
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002670 // Update list of touch targets for pointer up or cancel, if needed.
2671 if (canceled
2672 || actionMasked == MotionEvent.ACTION_UP
2673 || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
2674 resetTouchState();
2675 } else if (split && actionMasked == MotionEvent.ACTION_POINTER_UP) {
2676 final int actionIndex = ev.getActionIndex();
2677 final int idBitsToRemove = 1 << ev.getPointerId(actionIndex);
2678 removePointersFromTouchTargets(idBitsToRemove);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002679 }
2680 }
Romain Guy8506ab42009-06-11 17:35:47 -07002681
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002682 if (!handled && mInputEventConsistencyVerifier != null) {
2683 mInputEventConsistencyVerifier.onUnhandledEvent(ev, 1);
Jeff Brown20e987b2010-08-23 12:01:02 -07002684 }
Jeff Brown20e987b2010-08-23 12:01:02 -07002685 return handled;
2686 }
2687
Romain Guy469b1db2010-10-05 11:49:57 -07002688 /**
Filip Gruszczynskia33bdf32015-11-19 18:22:16 -08002689 * Provide custom ordering of views in which the touch will be dispatched.
2690 *
2691 * This is called within a tight loop, so you are not allowed to allocate objects, including
2692 * the return array. Instead, you should return a pre-allocated list that will be cleared
2693 * after the dispatch is finished.
2694 * @hide
2695 */
2696 public ArrayList<View> buildTouchDispatchChildList() {
2697 return buildOrderedChildList();
2698 }
2699
2700 /**
Svetoslavc73cfa02015-02-09 17:14:28 -08002701 * Finds the child which has accessibility focus.
2702 *
2703 * @return The child that has focus.
2704 */
2705 private View findChildWithAccessibilityFocus() {
2706 ViewRootImpl viewRoot = getViewRootImpl();
2707 if (viewRoot == null) {
2708 return null;
2709 }
2710
2711 View current = viewRoot.getAccessibilityFocusedHost();
2712 if (current == null) {
2713 return null;
2714 }
2715
2716 ViewParent parent = current.getParent();
2717 while (parent instanceof View) {
2718 if (parent == this) {
2719 return current;
2720 }
2721 current = (View) parent;
2722 parent = current.getParent();
2723 }
2724
2725 return null;
2726 }
2727
2728 /**
Romain Guy469b1db2010-10-05 11:49:57 -07002729 * Resets all touch state in preparation for a new cycle.
2730 */
2731 private void resetTouchState() {
Jeff Brown20e987b2010-08-23 12:01:02 -07002732 clearTouchTargets();
2733 resetCancelNextUpFlag(this);
2734 mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
Adam Powell10ba2772014-04-15 09:46:51 -07002735 mNestedScrollAxes = SCROLL_AXIS_NONE;
Jeff Brown20e987b2010-08-23 12:01:02 -07002736 }
2737
Romain Guy469b1db2010-10-05 11:49:57 -07002738 /**
2739 * Resets the cancel next up flag.
2740 * Returns true if the flag was previously set.
2741 */
Alan Viverettea7b85e62016-01-22 10:14:02 -05002742 private static boolean resetCancelNextUpFlag(@NonNull View view) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07002743 if ((view.mPrivateFlags & PFLAG_CANCEL_NEXT_UP_EVENT) != 0) {
2744 view.mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT;
Jeff Brown20e987b2010-08-23 12:01:02 -07002745 return true;
Adam Cohen9b073942010-08-19 16:49:52 -07002746 }
2747 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002748 }
2749
Romain Guy469b1db2010-10-05 11:49:57 -07002750 /**
2751 * Clears all touch targets.
2752 */
2753 private void clearTouchTargets() {
Jeff Brown20e987b2010-08-23 12:01:02 -07002754 TouchTarget target = mFirstTouchTarget;
2755 if (target != null) {
2756 do {
2757 TouchTarget next = target.next;
2758 target.recycle();
2759 target = next;
2760 } while (target != null);
2761 mFirstTouchTarget = null;
2762 }
2763 }
2764
Romain Guy469b1db2010-10-05 11:49:57 -07002765 /**
2766 * Cancels and clears all touch targets.
2767 */
2768 private void cancelAndClearTouchTargets(MotionEvent event) {
Jeff Brown20e987b2010-08-23 12:01:02 -07002769 if (mFirstTouchTarget != null) {
2770 boolean syntheticEvent = false;
2771 if (event == null) {
2772 final long now = SystemClock.uptimeMillis();
2773 event = MotionEvent.obtain(now, now,
2774 MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
Jeff Brown2fdbc5a2011-06-30 12:25:54 -07002775 event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
Jeff Brown20e987b2010-08-23 12:01:02 -07002776 syntheticEvent = true;
2777 }
2778
2779 for (TouchTarget target = mFirstTouchTarget; target != null; target = target.next) {
2780 resetCancelNextUpFlag(target.child);
2781 dispatchTransformedTouchEvent(event, true, target.child, target.pointerIdBits);
2782 }
2783 clearTouchTargets();
2784
2785 if (syntheticEvent) {
2786 event.recycle();
2787 }
2788 }
2789 }
2790
Romain Guy469b1db2010-10-05 11:49:57 -07002791 /**
2792 * Gets the touch target for specified child view.
2793 * Returns null if not found.
2794 */
Alan Viverettea7b85e62016-01-22 10:14:02 -05002795 private TouchTarget getTouchTarget(@NonNull View child) {
Jeff Brown20e987b2010-08-23 12:01:02 -07002796 for (TouchTarget target = mFirstTouchTarget; target != null; target = target.next) {
2797 if (target.child == child) {
2798 return target;
2799 }
2800 }
2801 return null;
2802 }
2803
Romain Guy469b1db2010-10-05 11:49:57 -07002804 /**
2805 * Adds a touch target for specified child to the beginning of the list.
2806 * Assumes the target child is not already present.
2807 */
Alan Viverettea7b85e62016-01-22 10:14:02 -05002808 private TouchTarget addTouchTarget(@NonNull View child, int pointerIdBits) {
2809 final TouchTarget target = TouchTarget.obtain(child, pointerIdBits);
Jeff Brown20e987b2010-08-23 12:01:02 -07002810 target.next = mFirstTouchTarget;
2811 mFirstTouchTarget = target;
2812 return target;
2813 }
2814
Romain Guy469b1db2010-10-05 11:49:57 -07002815 /**
2816 * Removes the pointer ids from consideration.
2817 */
2818 private void removePointersFromTouchTargets(int pointerIdBits) {
Jeff Brown20e987b2010-08-23 12:01:02 -07002819 TouchTarget predecessor = null;
2820 TouchTarget target = mFirstTouchTarget;
2821 while (target != null) {
2822 final TouchTarget next = target.next;
2823 if ((target.pointerIdBits & pointerIdBits) != 0) {
2824 target.pointerIdBits &= ~pointerIdBits;
2825 if (target.pointerIdBits == 0) {
2826 if (predecessor == null) {
2827 mFirstTouchTarget = next;
2828 } else {
2829 predecessor.next = next;
2830 }
2831 target.recycle();
2832 target = next;
2833 continue;
2834 }
2835 }
2836 predecessor = target;
2837 target = next;
2838 }
2839 }
2840
Jeff Brown59a422e2012-04-19 15:19:19 -07002841 private void cancelTouchTarget(View view) {
2842 TouchTarget predecessor = null;
2843 TouchTarget target = mFirstTouchTarget;
2844 while (target != null) {
2845 final TouchTarget next = target.next;
2846 if (target.child == view) {
2847 if (predecessor == null) {
2848 mFirstTouchTarget = next;
2849 } else {
2850 predecessor.next = next;
2851 }
2852 target.recycle();
2853
2854 final long now = SystemClock.uptimeMillis();
2855 MotionEvent event = MotionEvent.obtain(now, now,
2856 MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
2857 event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
2858 view.dispatchTouchEvent(event);
2859 event.recycle();
2860 return;
2861 }
2862 predecessor = target;
2863 target = next;
2864 }
2865 }
2866
Romain Guy469b1db2010-10-05 11:49:57 -07002867 /**
Jeff Browna032cc02011-03-07 16:56:21 -08002868 * Returns true if a child view can receive pointer events.
2869 * @hide
2870 */
Alan Viverettea7b85e62016-01-22 10:14:02 -05002871 private static boolean canViewReceivePointerEvents(@NonNull View child) {
Jeff Browna032cc02011-03-07 16:56:21 -08002872 return (child.mViewFlags & VISIBILITY_MASK) == VISIBLE
2873 || child.getAnimation() != null;
2874 }
2875
Alan Viveretteb942b6f2014-12-08 10:37:39 -08002876 private float[] getTempPoint() {
2877 if (mTempPoint == null) {
2878 mTempPoint = new float[2];
2879 }
2880 return mTempPoint;
2881 }
2882
Jeff Browna032cc02011-03-07 16:56:21 -08002883 /**
Romain Guy469b1db2010-10-05 11:49:57 -07002884 * Returns true if a child view contains the specified point when transformed
Jeff Brown20e987b2010-08-23 12:01:02 -07002885 * into its coordinate space.
Romain Guy469b1db2010-10-05 11:49:57 -07002886 * Child must not be null.
Adam Cohena32edd42010-10-26 10:35:01 -07002887 * @hide
Romain Guy469b1db2010-10-05 11:49:57 -07002888 */
Adam Cohena32edd42010-10-26 10:35:01 -07002889 protected boolean isTransformedTouchPointInView(float x, float y, View child,
Christopher Tate2c095f32010-10-04 14:13:40 -07002890 PointF outLocalPoint) {
Alan Viveretteb942b6f2014-12-08 10:37:39 -08002891 final float[] point = getTempPoint();
2892 point[0] = x;
2893 point[1] = y;
2894 transformPointToViewLocal(point, child);
2895 final boolean isInView = child.pointInView(point[0], point[1]);
Christopher Tate2c095f32010-10-04 14:13:40 -07002896 if (isInView && outLocalPoint != null) {
Alan Viveretteb942b6f2014-12-08 10:37:39 -08002897 outLocalPoint.set(point[0], point[1]);
Christopher Tate2c095f32010-10-04 14:13:40 -07002898 }
2899 return isInView;
Adam Powell2b342f02010-08-18 18:14:13 -07002900 }
2901
Romain Guy469b1db2010-10-05 11:49:57 -07002902 /**
Alan Viveretteb942b6f2014-12-08 10:37:39 -08002903 * @hide
2904 */
2905 public void transformPointToViewLocal(float[] point, View child) {
2906 point[0] += mScrollX - child.mLeft;
2907 point[1] += mScrollY - child.mTop;
2908
2909 if (!child.hasIdentityMatrix()) {
2910 child.getInverseMatrix().mapPoints(point);
2911 }
2912 }
2913
2914 /**
Romain Guy469b1db2010-10-05 11:49:57 -07002915 * Transforms a motion event into the coordinate space of a particular child view,
Jeff Brown20e987b2010-08-23 12:01:02 -07002916 * filters out irrelevant pointer ids, and overrides its action if necessary.
Romain Guy469b1db2010-10-05 11:49:57 -07002917 * If child is null, assumes the MotionEvent will be sent to this ViewGroup instead.
2918 */
2919 private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,
Jeff Brown20e987b2010-08-23 12:01:02 -07002920 View child, int desiredPointerIdBits) {
2921 final boolean handled;
Adam Powell2b342f02010-08-18 18:14:13 -07002922
Jeff Brown20e987b2010-08-23 12:01:02 -07002923 // Canceling motions is a special case. We don't need to perform any transformations
2924 // or filtering. The important part is the action, not the contents.
2925 final int oldAction = event.getAction();
2926 if (cancel || oldAction == MotionEvent.ACTION_CANCEL) {
2927 event.setAction(MotionEvent.ACTION_CANCEL);
2928 if (child == null) {
2929 handled = super.dispatchTouchEvent(event);
2930 } else {
2931 handled = child.dispatchTouchEvent(event);
2932 }
2933 event.setAction(oldAction);
2934 return handled;
2935 }
Adam Powell2b342f02010-08-18 18:14:13 -07002936
Jeff Brown20e987b2010-08-23 12:01:02 -07002937 // Calculate the number of pointers to deliver.
Jeff Brownfe9f8ab2011-05-06 18:20:01 -07002938 final int oldPointerIdBits = event.getPointerIdBits();
2939 final int newPointerIdBits = oldPointerIdBits & desiredPointerIdBits;
Adam Powell2b342f02010-08-18 18:14:13 -07002940
Jeff Brown20e987b2010-08-23 12:01:02 -07002941 // If for some reason we ended up in an inconsistent state where it looks like we
2942 // might produce a motion event with no pointers in it, then drop the event.
Jeff Brownfe9f8ab2011-05-06 18:20:01 -07002943 if (newPointerIdBits == 0) {
Jeff Brown20e987b2010-08-23 12:01:02 -07002944 return false;
2945 }
Adam Powell2b342f02010-08-18 18:14:13 -07002946
Jeff Brown20e987b2010-08-23 12:01:02 -07002947 // If the number of pointers is the same and we don't need to perform any fancy
2948 // irreversible transformations, then we can reuse the motion event for this
2949 // dispatch as long as we are careful to revert any changes we make.
Jeff Brownfe9f8ab2011-05-06 18:20:01 -07002950 // Otherwise we need to make a copy.
2951 final MotionEvent transformedEvent;
2952 if (newPointerIdBits == oldPointerIdBits) {
2953 if (child == null || child.hasIdentityMatrix()) {
2954 if (child == null) {
2955 handled = super.dispatchTouchEvent(event);
2956 } else {
2957 final float offsetX = mScrollX - child.mLeft;
2958 final float offsetY = mScrollY - child.mTop;
2959 event.offsetLocation(offsetX, offsetY);
Adam Powell2b342f02010-08-18 18:14:13 -07002960
Jeff Brownfe9f8ab2011-05-06 18:20:01 -07002961 handled = child.dispatchTouchEvent(event);
Jeff Brown20e987b2010-08-23 12:01:02 -07002962
Jeff Brownfe9f8ab2011-05-06 18:20:01 -07002963 event.offsetLocation(-offsetX, -offsetY);
2964 }
2965 return handled;
Jeff Brown20e987b2010-08-23 12:01:02 -07002966 }
Jeff Brown20e987b2010-08-23 12:01:02 -07002967 transformedEvent = MotionEvent.obtain(event);
2968 } else {
Jeff Brownfe9f8ab2011-05-06 18:20:01 -07002969 transformedEvent = event.split(newPointerIdBits);
Adam Powell2b342f02010-08-18 18:14:13 -07002970 }
2971
Jeff Brown20e987b2010-08-23 12:01:02 -07002972 // Perform any necessary transformations and dispatch.
2973 if (child == null) {
2974 handled = super.dispatchTouchEvent(transformedEvent);
2975 } else {
2976 final float offsetX = mScrollX - child.mLeft;
2977 final float offsetY = mScrollY - child.mTop;
2978 transformedEvent.offsetLocation(offsetX, offsetY);
2979 if (! child.hasIdentityMatrix()) {
2980 transformedEvent.transform(child.getInverseMatrix());
Adam Powell2b342f02010-08-18 18:14:13 -07002981 }
2982
Jeff Brown20e987b2010-08-23 12:01:02 -07002983 handled = child.dispatchTouchEvent(transformedEvent);
Adam Powell2b342f02010-08-18 18:14:13 -07002984 }
2985
Jeff Brown20e987b2010-08-23 12:01:02 -07002986 // Done.
2987 transformedEvent.recycle();
Adam Powell2b342f02010-08-18 18:14:13 -07002988 return handled;
2989 }
2990
Romain Guy469b1db2010-10-05 11:49:57 -07002991 /**
Adam Powell2b342f02010-08-18 18:14:13 -07002992 * Enable or disable the splitting of MotionEvents to multiple children during touch event
Jeff Brown995e7742010-12-22 16:59:36 -08002993 * dispatch. This behavior is enabled by default for applications that target an
2994 * SDK version of {@link Build.VERSION_CODES#HONEYCOMB} or newer.
Adam Powell2b342f02010-08-18 18:14:13 -07002995 *
2996 * <p>When this option is enabled MotionEvents may be split and dispatched to different child
2997 * views depending on where each pointer initially went down. This allows for user interactions
2998 * such as scrolling two panes of content independently, chording of buttons, and performing
2999 * independent gestures on different pieces of content.
3000 *
3001 * @param split <code>true</code> to allow MotionEvents to be split and dispatched to multiple
3002 * child views. <code>false</code> to only allow one child view to be the target of
3003 * any MotionEvent received by this ViewGroup.
Scott Main27a85082013-06-10 10:39:48 -07003004 * @attr ref android.R.styleable#ViewGroup_splitMotionEvents
Adam Powell2b342f02010-08-18 18:14:13 -07003005 */
3006 public void setMotionEventSplittingEnabled(boolean split) {
3007 // TODO Applications really shouldn't change this setting mid-touch event,
3008 // but perhaps this should handle that case and send ACTION_CANCELs to any child views
3009 // with gestures in progress when this is changed.
3010 if (split) {
Adam Powell2b342f02010-08-18 18:14:13 -07003011 mGroupFlags |= FLAG_SPLIT_MOTION_EVENTS;
3012 } else {
3013 mGroupFlags &= ~FLAG_SPLIT_MOTION_EVENTS;
Adam Powell2b342f02010-08-18 18:14:13 -07003014 }
3015 }
3016
3017 /**
Jeff Brown995e7742010-12-22 16:59:36 -08003018 * Returns true if MotionEvents dispatched to this ViewGroup can be split to multiple children.
Adam Powell2b342f02010-08-18 18:14:13 -07003019 * @return true if MotionEvents dispatched to this ViewGroup can be split to multiple children.
3020 */
3021 public boolean isMotionEventSplittingEnabled() {
3022 return (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) == FLAG_SPLIT_MOTION_EVENTS;
3023 }
3024
3025 /**
George Mount0a778ed2013-12-13 13:35:36 -08003026 * Returns true if this ViewGroup should be considered as a single entity for removal
3027 * when executing an Activity transition. If this is false, child elements will move
3028 * individually during the transition.
George Mount427c6412014-11-05 16:45:36 -08003029 *
George Mount0a778ed2013-12-13 13:35:36 -08003030 * @return True if the ViewGroup should be acted on together during an Activity transition.
George Mount427c6412014-11-05 16:45:36 -08003031 * The default value is true when there is a non-null background or if
3032 * {@link #getTransitionName()} is not null or if a
3033 * non-null {@link android.view.ViewOutlineProvider} other than
3034 * {@link android.view.ViewOutlineProvider#BACKGROUND} was given to
3035 * {@link #setOutlineProvider(ViewOutlineProvider)} and false otherwise.
George Mount0a778ed2013-12-13 13:35:36 -08003036 */
3037 public boolean isTransitionGroup() {
3038 if ((mGroupFlags & FLAG_IS_TRANSITION_GROUP_SET) != 0) {
3039 return ((mGroupFlags & FLAG_IS_TRANSITION_GROUP) != 0);
3040 } else {
George Mount427c6412014-11-05 16:45:36 -08003041 final ViewOutlineProvider outlineProvider = getOutlineProvider();
3042 return getBackground() != null || getTransitionName() != null ||
3043 (outlineProvider != null && outlineProvider != ViewOutlineProvider.BACKGROUND);
George Mount0a778ed2013-12-13 13:35:36 -08003044 }
3045 }
3046
3047 /**
3048 * Changes whether or not this ViewGroup should be treated as a single entity during
George Mount31a21722014-03-24 17:44:36 -07003049 * Activity Transitions.
George Mount0a778ed2013-12-13 13:35:36 -08003050 * @param isTransitionGroup Whether or not the ViewGroup should be treated as a unit
3051 * in Activity transitions. If false, the ViewGroup won't transition,
3052 * only its children. If true, the entire ViewGroup will transition
3053 * together.
George Mount62ab9b72014-05-02 13:51:17 -07003054 * @see android.app.ActivityOptions#makeSceneTransitionAnimation(android.app.Activity,
3055 * android.util.Pair[])
George Mount0a778ed2013-12-13 13:35:36 -08003056 */
3057 public void setTransitionGroup(boolean isTransitionGroup) {
3058 mGroupFlags |= FLAG_IS_TRANSITION_GROUP_SET;
3059 if (isTransitionGroup) {
3060 mGroupFlags |= FLAG_IS_TRANSITION_GROUP;
3061 } else {
3062 mGroupFlags &= ~FLAG_IS_TRANSITION_GROUP;
3063 }
3064 }
3065
Alan Viverettebe463f22016-01-21 10:50:10 -05003066 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003067 public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
Romain Guy8506ab42009-06-11 17:35:47 -07003068
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003069 if (disallowIntercept == ((mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0)) {
3070 // We're already in this state, assume our ancestors are too
3071 return;
3072 }
Romain Guy8506ab42009-06-11 17:35:47 -07003073
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003074 if (disallowIntercept) {
3075 mGroupFlags |= FLAG_DISALLOW_INTERCEPT;
3076 } else {
3077 mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
3078 }
Romain Guy8506ab42009-06-11 17:35:47 -07003079
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003080 // Pass it up to our parent
3081 if (mParent != null) {
3082 mParent.requestDisallowInterceptTouchEvent(disallowIntercept);
3083 }
3084 }
3085
3086 /**
3087 * Implement this method to intercept all touch screen motion events. This
3088 * allows you to watch events as they are dispatched to your children, and
3089 * take ownership of the current gesture at any point.
3090 *
3091 * <p>Using this function takes some care, as it has a fairly complicated
3092 * interaction with {@link View#onTouchEvent(MotionEvent)
3093 * View.onTouchEvent(MotionEvent)}, and using it requires implementing
3094 * that method as well as this one in the correct way. Events will be
3095 * received in the following order:
3096 *
3097 * <ol>
3098 * <li> You will receive the down event here.
3099 * <li> The down event will be handled either by a child of this view
3100 * group, or given to your own onTouchEvent() method to handle; this means
3101 * you should implement onTouchEvent() to return true, so you will
3102 * continue to see the rest of the gesture (instead of looking for
3103 * a parent view to handle it). Also, by returning true from
3104 * onTouchEvent(), you will not receive any following
3105 * events in onInterceptTouchEvent() and all touch processing must
3106 * happen in onTouchEvent() like normal.
3107 * <li> For as long as you return false from this function, each following
3108 * event (up to and including the final up) will be delivered first here
3109 * and then to the target's onTouchEvent().
3110 * <li> If you return true from here, you will not receive any
3111 * following events: the target view will receive the same event but
3112 * with the action {@link MotionEvent#ACTION_CANCEL}, and all further
3113 * events will be delivered to your onTouchEvent() method and no longer
3114 * appear here.
3115 * </ol>
3116 *
3117 * @param ev The motion event being dispatched down the hierarchy.
3118 * @return Return true to steal motion events from the children and have
3119 * them dispatched to this ViewGroup through onTouchEvent().
3120 * The current target will receive an ACTION_CANCEL event, and no further
3121 * messages will be delivered here.
3122 */
3123 public boolean onInterceptTouchEvent(MotionEvent ev) {
Keisuke Kuroyanagid85bc502016-01-21 14:50:38 +09003124 if (ev.isFromSource(InputDevice.SOURCE_MOUSE)
3125 && ev.getAction() == MotionEvent.ACTION_DOWN
3126 && ev.isButtonPressed(MotionEvent.BUTTON_PRIMARY)
3127 && isOnScrollbarThumb(ev.getX(), ev.getY())) {
3128 return true;
3129 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003130 return false;
3131 }
3132
3133 /**
3134 * {@inheritDoc}
3135 *
3136 * Looks for a view to give focus to respecting the setting specified by
3137 * {@link #getDescendantFocusability()}.
3138 *
3139 * Uses {@link #onRequestFocusInDescendants(int, android.graphics.Rect)} to
3140 * find focus within the children of this group when appropriate.
3141 *
3142 * @see #FOCUS_BEFORE_DESCENDANTS
3143 * @see #FOCUS_AFTER_DESCENDANTS
3144 * @see #FOCUS_BLOCK_DESCENDANTS
Filip Gruszczynskia33bdf32015-11-19 18:22:16 -08003145 * @see #onRequestFocusInDescendants(int, android.graphics.Rect)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003146 */
3147 @Override
3148 public boolean requestFocus(int direction, Rect previouslyFocusedRect) {
3149 if (DBG) {
3150 System.out.println(this + " ViewGroup.requestFocus direction="
3151 + direction);
3152 }
3153 int descendantFocusability = getDescendantFocusability();
3154
3155 switch (descendantFocusability) {
3156 case FOCUS_BLOCK_DESCENDANTS:
3157 return super.requestFocus(direction, previouslyFocusedRect);
3158 case FOCUS_BEFORE_DESCENDANTS: {
3159 final boolean took = super.requestFocus(direction, previouslyFocusedRect);
3160 return took ? took : onRequestFocusInDescendants(direction, previouslyFocusedRect);
3161 }
3162 case FOCUS_AFTER_DESCENDANTS: {
3163 final boolean took = onRequestFocusInDescendants(direction, previouslyFocusedRect);
3164 return took ? took : super.requestFocus(direction, previouslyFocusedRect);
3165 }
3166 default:
3167 throw new IllegalStateException("descendant focusability must be "
3168 + "one of FOCUS_BEFORE_DESCENDANTS, FOCUS_AFTER_DESCENDANTS, FOCUS_BLOCK_DESCENDANTS "
3169 + "but is " + descendantFocusability);
3170 }
3171 }
3172
3173 /**
3174 * Look for a descendant to call {@link View#requestFocus} on.
3175 * Called by {@link ViewGroup#requestFocus(int, android.graphics.Rect)}
3176 * when it wants to request focus within its children. Override this to
3177 * customize how your {@link ViewGroup} requests focus within its children.
3178 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT
3179 * @param previouslyFocusedRect The rectangle (in this View's coordinate system)
3180 * to give a finer grained hint about where focus is coming from. May be null
3181 * if there is no hint.
3182 * @return Whether focus was taken.
3183 */
3184 @SuppressWarnings({"ConstantConditions"})
3185 protected boolean onRequestFocusInDescendants(int direction,
3186 Rect previouslyFocusedRect) {
3187 int index;
3188 int increment;
3189 int end;
3190 int count = mChildrenCount;
3191 if ((direction & FOCUS_FORWARD) != 0) {
3192 index = 0;
3193 increment = 1;
3194 end = count;
3195 } else {
3196 index = count - 1;
3197 increment = -1;
3198 end = -1;
3199 }
3200 final View[] children = mChildren;
3201 for (int i = index; i != end; i += increment) {
3202 View child = children[i];
Vadim Tryshevb5ced222017-01-17 19:31:35 -08003203 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003204 if (child.requestFocus(direction, previouslyFocusedRect)) {
3205 return true;
3206 }
3207 }
3208 }
3209 return false;
3210 }
Chet Haase5c13d892010-10-08 08:37:55 -07003211
Vadim Tryshev01d8c492016-12-15 11:33:15 -08003212 @Override
Evan Rosky53fcf112017-01-26 14:37:55 -08003213 public boolean restoreDefaultFocus() {
3214 if (mDefaultFocus != null
Vadim Tryshev01d8c492016-12-15 11:33:15 -08003215 && getDescendantFocusability() != FOCUS_BLOCK_DESCENDANTS
Vadim Tryshev5ca73982017-01-04 17:24:43 -08003216 && (mDefaultFocus.mViewFlags & VISIBILITY_MASK) == VISIBLE
Evan Rosky53fcf112017-01-26 14:37:55 -08003217 && mDefaultFocus.restoreDefaultFocus()) {
Vadim Tryshev01d8c492016-12-15 11:33:15 -08003218 return true;
3219 }
Evan Rosky53fcf112017-01-26 14:37:55 -08003220 return super.restoreDefaultFocus();
3221 }
3222
3223 /**
3224 * @hide
3225 */
Evan Rosky3ac64632017-02-13 18:04:43 -08003226 @TestApi
Evan Rosky53fcf112017-01-26 14:37:55 -08003227 @Override
3228 public boolean restoreFocusInCluster(@FocusRealDirection int direction) {
Evan Rosky18b886e2017-02-15 13:26:51 -08003229 // Allow cluster-navigation to enter touchscreenBlocksFocus ViewGroups.
3230 if (isKeyboardNavigationCluster()) {
3231 final boolean blockedFocus = getTouchscreenBlocksFocus();
3232 try {
3233 setTouchscreenBlocksFocusNoRefocus(false);
3234 return restoreFocusInClusterInternal(direction);
3235 } finally {
3236 setTouchscreenBlocksFocusNoRefocus(blockedFocus);
3237 }
3238 } else {
3239 return restoreFocusInClusterInternal(direction);
3240 }
3241 }
3242
3243 private boolean restoreFocusInClusterInternal(@FocusRealDirection int direction) {
Evan Rosky0e8a6832017-04-10 12:35:15 -07003244 if (mFocusedInCluster != null && getDescendantFocusability() != FOCUS_BLOCK_DESCENDANTS
Evan Rosky53fcf112017-01-26 14:37:55 -08003245 && (mFocusedInCluster.mViewFlags & VISIBILITY_MASK) == VISIBLE
3246 && mFocusedInCluster.restoreFocusInCluster(direction)) {
3247 return true;
3248 }
3249 return super.restoreFocusInCluster(direction);
Vadim Tryshev01d8c492016-12-15 11:33:15 -08003250 }
3251
Romain Guya440b002010-02-24 15:57:54 -08003252 /**
Evan Rosky3ac64632017-02-13 18:04:43 -08003253 * @hide
3254 */
3255 @Override
3256 public boolean restoreFocusNotInCluster() {
3257 if (mFocusedInCluster != null) {
3258 // since clusters don't nest; we can assume that a non-null mFocusedInCluster
3259 // will refer to a view not-in a cluster.
3260 return restoreFocusInCluster(View.FOCUS_DOWN);
3261 }
Evan Rosky2ae1bf52017-05-11 11:18:45 -07003262 if (isKeyboardNavigationCluster() || (mViewFlags & VISIBILITY_MASK) != VISIBLE) {
Evan Rosky3ac64632017-02-13 18:04:43 -08003263 return false;
3264 }
3265 int descendentFocusability = getDescendantFocusability();
3266 if (descendentFocusability == FOCUS_BLOCK_DESCENDANTS) {
3267 return super.requestFocus(FOCUS_DOWN, null);
3268 }
3269 if (descendentFocusability == FOCUS_BEFORE_DESCENDANTS
3270 && super.requestFocus(FOCUS_DOWN, null)) {
3271 return true;
3272 }
3273 for (int i = 0; i < mChildrenCount; ++i) {
3274 View child = mChildren[i];
3275 if (!child.isKeyboardNavigationCluster()
3276 && child.restoreFocusNotInCluster()) {
3277 return true;
3278 }
3279 }
Evan Rosky2ae1bf52017-05-11 11:18:45 -07003280 if (descendentFocusability == FOCUS_AFTER_DESCENDANTS && !hasFocusableChild(false)) {
Evan Rosky3ac64632017-02-13 18:04:43 -08003281 return super.requestFocus(FOCUS_DOWN, null);
3282 }
3283 return false;
3284 }
3285
3286 /**
Romain Guya440b002010-02-24 15:57:54 -08003287 * {@inheritDoc}
Chet Haase5c13d892010-10-08 08:37:55 -07003288 *
Romain Guydcc490f2010-02-24 17:59:35 -08003289 * @hide
Romain Guya440b002010-02-24 15:57:54 -08003290 */
3291 @Override
3292 public void dispatchStartTemporaryDetach() {
3293 super.dispatchStartTemporaryDetach();
3294 final int count = mChildrenCount;
3295 final View[] children = mChildren;
3296 for (int i = 0; i < count; i++) {
3297 children[i].dispatchStartTemporaryDetach();
3298 }
3299 }
Chet Haase5c13d892010-10-08 08:37:55 -07003300
Romain Guya440b002010-02-24 15:57:54 -08003301 /**
3302 * {@inheritDoc}
Chet Haase5c13d892010-10-08 08:37:55 -07003303 *
Romain Guydcc490f2010-02-24 17:59:35 -08003304 * @hide
Romain Guya440b002010-02-24 15:57:54 -08003305 */
3306 @Override
3307 public void dispatchFinishTemporaryDetach() {
3308 super.dispatchFinishTemporaryDetach();
3309 final int count = mChildrenCount;
3310 final View[] children = mChildren;
3311 for (int i = 0; i < count; i++) {
3312 children[i].dispatchFinishTemporaryDetach();
3313 }
3314 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003315
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003316 @Override
3317 void dispatchAttachedToWindow(AttachInfo info, int visibility) {
Adam Powell4b867882011-09-16 12:59:46 -07003318 mGroupFlags |= FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003319 super.dispatchAttachedToWindow(info, visibility);
Adam Powell4b867882011-09-16 12:59:46 -07003320 mGroupFlags &= ~FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW;
3321
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003322 final int count = mChildrenCount;
3323 final View[] children = mChildren;
3324 for (int i = 0; i < count; i++) {
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07003325 final View child = children[i];
3326 child.dispatchAttachedToWindow(info,
Adam Powelleb2b0af2015-05-20 18:26:35 -07003327 combineVisibility(visibility, child.getVisibility()));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003328 }
Chet Haasec633d2f2015-04-07 10:29:39 -07003329 final int transientCount = mTransientIndices == null ? 0 : mTransientIndices.size();
3330 for (int i = 0; i < transientCount; ++i) {
3331 View view = mTransientViews.get(i);
Adam Powelleb2b0af2015-05-20 18:26:35 -07003332 view.dispatchAttachedToWindow(info,
3333 combineVisibility(visibility, view.getVisibility()));
Chet Haasec633d2f2015-04-07 10:29:39 -07003334 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003335 }
3336
svetoslavganov75986cf2009-05-14 22:28:01 -07003337 @Override
Romain Guybb9908b2012-03-08 11:14:07 -08003338 void dispatchScreenStateChanged(int screenState) {
3339 super.dispatchScreenStateChanged(screenState);
3340
3341 final int count = mChildrenCount;
3342 final View[] children = mChildren;
3343 for (int i = 0; i < count; i++) {
3344 children[i].dispatchScreenStateChanged(screenState);
3345 }
3346 }
3347
Andrii Kulianb047b8b2017-02-08 18:38:26 -08003348 @Override
Andrii Kuliane5c58ee2017-03-27 19:25:24 -07003349 void dispatchMovedToDisplay(Display display, Configuration config) {
3350 super.dispatchMovedToDisplay(display, config);
Andrii Kulianb047b8b2017-02-08 18:38:26 -08003351
3352 final int count = mChildrenCount;
3353 final View[] children = mChildren;
3354 for (int i = 0; i < count; i++) {
Andrii Kuliane5c58ee2017-03-27 19:25:24 -07003355 children[i].dispatchMovedToDisplay(display, config);
Andrii Kulianb047b8b2017-02-08 18:38:26 -08003356 }
3357 }
3358
Alan Viverettea54956a2015-01-07 16:05:02 -08003359 /** @hide */
Romain Guybb9908b2012-03-08 11:14:07 -08003360 @Override
Alan Viverettea54956a2015-01-07 16:05:02 -08003361 public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07003362 boolean handled = false;
3363 if (includeForAccessibility()) {
3364 handled = super.dispatchPopulateAccessibilityEventInternal(event);
3365 if (handled) {
3366 return handled;
3367 }
Svetoslav Ganovb84b94e2011-09-22 19:26:56 -07003368 }
Svetoslav Ganov736c2752011-04-22 18:30:36 -07003369 // Let our children have a shot in populating the event.
Svetoslav Ganov42138042012-03-20 11:51:39 -07003370 ChildListForAccessibility children = ChildListForAccessibility.obtain(this, true);
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07003371 try {
3372 final int childCount = children.getChildCount();
3373 for (int i = 0; i < childCount; i++) {
3374 View child = children.getChildAt(i);
3375 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
3376 handled = child.dispatchPopulateAccessibilityEvent(event);
3377 if (handled) {
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07003378 return handled;
3379 }
Svetoslav Ganov6179ea32011-06-28 01:12:41 -07003380 }
Svetoslav Ganov736c2752011-04-22 18:30:36 -07003381 }
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07003382 } finally {
3383 children.recycle();
svetoslavganov75986cf2009-05-14 22:28:01 -07003384 }
Svetoslav Ganov736c2752011-04-22 18:30:36 -07003385 return false;
svetoslavganov75986cf2009-05-14 22:28:01 -07003386 }
3387
Dianne Hackborn6251f0d2015-04-01 16:45:03 -07003388 /**
Felipe Leme6d553872016-12-08 17:13:25 -08003389 * Dispatch creation of {@link ViewStructure} down the hierarchy. This implementation
3390 * adds in all child views of the view group, in addition to calling the default View
3391 * implementation.
3392 */
3393 @Override
3394 public void dispatchProvideStructure(ViewStructure structure) {
3395 super.dispatchProvideStructure(structure);
Svet Ganov2f8fb1f2017-03-13 00:21:04 -07003396 if (isAssistBlocked() || structure.getChildCount() != 0) {
3397 return;
3398 }
3399 final int childrenCount = mChildrenCount;
3400 if (childrenCount <= 0) {
3401 return;
3402 }
Philip P. Moltmann083d8aa2017-08-15 15:22:37 -07003403
3404 if (!isLaidOut()) {
3405 Log.v(VIEW_LOG_TAG, "dispatchProvideStructure(): not laid out, ignoring "
3406 + childrenCount + " children of " + getAccessibilityViewId());
3407 return;
3408 }
3409
Svet Ganov2f8fb1f2017-03-13 00:21:04 -07003410 structure.setChildCount(childrenCount);
3411 ArrayList<View> preorderedList = buildOrderedChildList();
3412 boolean customOrder = preorderedList == null
3413 && isChildrenDrawingOrderEnabled();
3414 for (int i = 0; i < childrenCount; i++) {
3415 int childIndex;
3416 try {
3417 childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
3418 } catch (IndexOutOfBoundsException e) {
3419 childIndex = i;
3420 if (mContext.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.M) {
3421 Log.w(TAG, "Bad getChildDrawingOrder while collecting assist @ "
3422 + i + " of " + childrenCount, e);
3423 // At least one app is failing when we call getChildDrawingOrder
3424 // at this point, so deal semi-gracefully with it by falling back
3425 // on the basic order.
3426 customOrder = false;
3427 if (i > 0) {
3428 // If we failed at the first index, there really isn't
3429 // anything to do -- we will just proceed with the simple
3430 // sequence order.
3431 // Otherwise, we failed in the middle, so need to come up
3432 // with an order for the remaining indices and use that.
3433 // Failed at the first one, easy peasy.
3434 int[] permutation = new int[childrenCount];
3435 SparseBooleanArray usedIndices = new SparseBooleanArray();
3436 // Go back and collected the indices we have done so far.
3437 for (int j = 0; j < i; j++) {
3438 permutation[j] = getChildDrawingOrder(childrenCount, j);
3439 usedIndices.put(permutation[j], true);
3440 }
3441 // Fill in the remaining indices with indices that have not
3442 // yet been used.
3443 int nextIndex = 0;
3444 for (int j = i; j < childrenCount; j++) {
3445 while (usedIndices.get(nextIndex, false)) {
3446 nextIndex++;
3447 }
3448 permutation[j] = nextIndex;
3449 nextIndex++;
3450 }
3451 // Build the final view list.
3452 preorderedList = new ArrayList<>(childrenCount);
3453 for (int j = 0; j < childrenCount; j++) {
3454 final int index = permutation[j];
3455 final View child = mChildren[index];
3456 preorderedList.add(child);
3457 }
3458 }
3459 } else {
3460 throw e;
3461 }
3462 }
3463 final View child = getAndVerifyPreorderedView(preorderedList, mChildren,
3464 childIndex);
3465 final ViewStructure cstructure = structure.newChild(i);
3466 child.dispatchProvideStructure(cstructure);
3467 }
3468 if (preorderedList != null) {
3469 preorderedList.clear();
3470 }
Felipe Leme6d553872016-12-08 17:13:25 -08003471 }
3472
3473 /**
Felipe Leme1ca634a2016-11-28 17:21:21 -08003474 * {@inheritDoc}
3475 *
3476 * <p>This implementation adds in all child views of the view group, in addition to calling the
3477 * default {@link View} implementation.
Dianne Hackborn6251f0d2015-04-01 16:45:03 -07003478 */
Alan Viverettebe463f22016-01-21 10:50:10 -05003479 @Override
Svet Ganovfd31f852017-04-26 15:54:27 -07003480 public void dispatchProvideAutofillStructure(ViewStructure structure,
3481 @AutofillFlags int flags) {
Felipe Leme640f30a2017-03-06 15:44:06 -08003482 super.dispatchProvideAutofillStructure(structure, flags);
Svet Ganovfd31f852017-04-26 15:54:27 -07003483 if (structure.getChildCount() != 0) {
Svet Ganov2f8fb1f2017-03-13 00:21:04 -07003484 return;
3485 }
Philip P. Moltmann083d8aa2017-08-15 15:22:37 -07003486
3487 if (!isLaidOut()) {
3488 Log.v(VIEW_LOG_TAG, "dispatchProvideAutofillStructure(): not laid out, ignoring "
3489 + mChildrenCount + " children of " + getAutofillId());
3490 return;
3491 }
3492
Svet Ganovfd31f852017-04-26 15:54:27 -07003493 final ChildListForAutoFill children = getChildrenForAutofill(flags);
Svet Ganov2f8fb1f2017-03-13 00:21:04 -07003494 final int childrenCount = children.size();
3495 structure.setChildCount(childrenCount);
3496 for (int i = 0; i < childrenCount; i++) {
3497 final View child = children.get(i);
3498 final ViewStructure cstructure = structure.newChild(i);
3499 child.dispatchProvideAutofillStructure(cstructure, flags);
3500 }
3501 children.recycle();
Felipe Leme6d553872016-12-08 17:13:25 -08003502 }
Felipe Leme1ca634a2016-11-28 17:21:21 -08003503
Svet Ganov2f8fb1f2017-03-13 00:21:04 -07003504 /**
3505 * Gets the children for autofill. Children for autofill are the first
3506 * level descendants that are important for autofill. The returned
3507 * child list object is pooled and the caller must recycle it once done.
3508 * @hide */
Svet Ganovfd31f852017-04-26 15:54:27 -07003509 private @NonNull ChildListForAutoFill getChildrenForAutofill(@AutofillFlags int flags) {
Svet Ganov2f8fb1f2017-03-13 00:21:04 -07003510 final ChildListForAutoFill children = ChildListForAutoFill.obtain();
Svet Ganovfd31f852017-04-26 15:54:27 -07003511 populateChildrenForAutofill(children, flags);
Svet Ganov2f8fb1f2017-03-13 00:21:04 -07003512 return children;
Felipe Lemed04a6972017-03-02 12:56:18 -08003513 }
3514
3515 /** @hide */
Svet Ganovfd31f852017-04-26 15:54:27 -07003516 private void populateChildrenForAutofill(ArrayList<View> list, @AutofillFlags int flags) {
Svet Ganov2f8fb1f2017-03-13 00:21:04 -07003517 final int childrenCount = mChildrenCount;
3518 if (childrenCount <= 0) {
3519 return;
3520 }
3521 final ArrayList<View> preorderedList = buildOrderedChildList();
3522 final boolean customOrder = preorderedList == null
3523 && isChildrenDrawingOrderEnabled();
3524 for (int i = 0; i < childrenCount; i++) {
3525 final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
3526 final View child = (preorderedList == null)
3527 ? mChildren[childIndex] : preorderedList.get(childIndex);
Svet Ganovfd31f852017-04-26 15:54:27 -07003528 if ((flags & AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) != 0
3529 || child.isImportantForAutofill()) {
Felipe Lemed04a6972017-03-02 12:56:18 -08003530 list.add(child);
3531 } else if (child instanceof ViewGroup) {
Svet Ganovfd31f852017-04-26 15:54:27 -07003532 ((ViewGroup) child).populateChildrenForAutofill(list, flags);
Felipe Lemed04a6972017-03-02 12:56:18 -08003533 }
3534 }
3535 }
3536
Alan Viverettea7b85e62016-01-22 10:14:02 -05003537 private static View getAndVerifyPreorderedView(ArrayList<View> preorderedList, View[] children,
3538 int childIndex) {
3539 final View child;
3540 if (preorderedList != null) {
3541 child = preorderedList.get(childIndex);
3542 if (child == null) {
3543 throw new RuntimeException("Invalid preorderedList contained null child at index "
3544 + childIndex);
3545 }
3546 } else {
3547 child = children[childIndex];
3548 }
3549 return child;
3550 }
3551
Alan Viverettea54956a2015-01-07 16:05:02 -08003552 /** @hide */
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003553 @Override
Alan Viverettea54956a2015-01-07 16:05:02 -08003554 public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
Svetoslav Ganov031d9c12011-09-09 16:41:13 -07003555 super.onInitializeAccessibilityNodeInfoInternal(info);
Svet Ganov55bdb102015-02-06 12:41:17 -08003556 if (getAccessibilityNodeProvider() != null) {
3557 return;
3558 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07003559 if (mAttachInfo != null) {
Alan Viverettef0aed092013-11-06 15:33:03 -08003560 final ArrayList<View> childrenForAccessibility = mAttachInfo.mTempArrayList;
Svetoslav Ganov42138042012-03-20 11:51:39 -07003561 childrenForAccessibility.clear();
3562 addChildrenForAccessibility(childrenForAccessibility);
3563 final int childrenForAccessibilityCount = childrenForAccessibility.size();
3564 for (int i = 0; i < childrenForAccessibilityCount; i++) {
Alan Viverettef0aed092013-11-06 15:33:03 -08003565 final View child = childrenForAccessibility.get(i);
3566 info.addChildUnchecked(child);
Svetoslav Ganovea1da3d2011-06-15 17:16:02 -07003567 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07003568 childrenForAccessibility.clear();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003569 }
3570 }
3571
Svetoslav Ganov8a78fd42012-01-17 14:36:46 -08003572 @Override
Maxim Bogatovf399af32015-06-16 15:15:49 -07003573 public CharSequence getAccessibilityClassName() {
3574 return ViewGroup.class.getName();
Svetoslav Ganov8a78fd42012-01-17 14:36:46 -08003575 }
3576
Svetoslav Ganov42138042012-03-20 11:51:39 -07003577 @Override
Alan Viverette77e9a282013-09-12 17:16:09 -07003578 public void notifySubtreeAccessibilityStateChanged(View child, View source, int changeType) {
3579 // If this is a live region, we should send a subtree change event
3580 // from this view. Otherwise, we can let it propagate up.
3581 if (getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE) {
Phil Weaver10e340c2016-11-07 10:05:26 -08003582 notifyViewAccessibilityStateChangedIfNeeded(
3583 AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE);
Alan Viverette77e9a282013-09-12 17:16:09 -07003584 } else if (mParent != null) {
Adam Powell504a10f2013-07-11 15:25:59 -07003585 try {
Alan Viverette77e9a282013-09-12 17:16:09 -07003586 mParent.notifySubtreeAccessibilityStateChanged(this, source, changeType);
Adam Powell504a10f2013-07-11 15:25:59 -07003587 } catch (AbstractMethodError e) {
3588 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() +
3589 " does not fully implement ViewParent", e);
3590 }
Svetoslav6254f482013-06-04 17:22:14 -07003591 }
3592 }
3593
Phil Weaver4d3eec412016-09-01 16:28:34 -07003594 /** @hide */
3595 @Override
3596 public void notifySubtreeAccessibilityStateChangedIfNeeded() {
3597 if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) {
3598 return;
3599 }
3600 // If something important for a11y is happening in this subtree, make sure it's dispatched
3601 // from a view that is important for a11y so it doesn't get lost.
3602 if ((getImportantForAccessibility() != IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS)
3603 && !isImportantForAccessibility() && (getChildCount() > 0)) {
3604 ViewParent a11yParent = getParentForAccessibility();
3605 if (a11yParent instanceof View) {
3606 ((View) a11yParent).notifySubtreeAccessibilityStateChangedIfNeeded();
3607 return;
3608 }
3609 }
3610 super.notifySubtreeAccessibilityStateChangedIfNeeded();
3611 }
3612
Svetoslav6254f482013-06-04 17:22:14 -07003613 @Override
3614 void resetSubtreeAccessibilityStateChanged() {
3615 super.resetSubtreeAccessibilityStateChanged();
Svetoslav Ganov42138042012-03-20 11:51:39 -07003616 View[] children = mChildren;
3617 final int childCount = mChildrenCount;
3618 for (int i = 0; i < childCount; i++) {
Svetoslav6254f482013-06-04 17:22:14 -07003619 children[i].resetSubtreeAccessibilityStateChanged();
Svetoslav Ganov42138042012-03-20 11:51:39 -07003620 }
3621 }
3622
3623 /**
Phil Weaver1f222542016-01-08 11:49:32 -08003624 * Counts the number of children of this View that will be sent to an accessibility service.
3625 *
3626 * @return The number of children an {@code AccessibilityNodeInfo} rooted at this View
3627 * would have.
3628 */
3629 int getNumChildrenForAccessibility() {
3630 int numChildrenForAccessibility = 0;
3631 for (int i = 0; i < getChildCount(); i++) {
3632 View child = getChildAt(i);
3633 if (child.includeForAccessibility()) {
3634 numChildrenForAccessibility++;
3635 } else if (child instanceof ViewGroup) {
3636 numChildrenForAccessibility += ((ViewGroup) child)
3637 .getNumChildrenForAccessibility();
3638 }
3639 }
3640 return numChildrenForAccessibility;
3641 }
3642
3643 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003644 * {@inheritDoc}
Adam Powellb6ab0982015-01-07 17:00:12 -08003645 *
3646 * <p>Subclasses should always call <code>super.onNestedPrePerformAccessibilityAction</code></p>
3647 *
3648 * @param target The target view dispatching this action
3649 * @param action Action being performed; see
3650 * {@link android.view.accessibility.AccessibilityNodeInfo}
3651 * @param args Optional action arguments
3652 * @return false by default. Subclasses should return true if they handle the event.
3653 */
3654 @Override
3655 public boolean onNestedPrePerformAccessibilityAction(View target, int action, Bundle args) {
3656 return false;
3657 }
3658
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003659 @Override
3660 void dispatchDetachedFromWindow() {
Jeff Brown20e987b2010-08-23 12:01:02 -07003661 // If we still have a touch target, we are still in the process of
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003662 // dispatching motion events to a child; we need to get rid of that
3663 // child to avoid dispatching events to it after the window is torn
3664 // down. To make sure we keep the child in a consistent state, we
3665 // first send it an ACTION_CANCEL motion event.
Jeff Brown20e987b2010-08-23 12:01:02 -07003666 cancelAndClearTouchTargets(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003667
Jeff Brown59a422e2012-04-19 15:19:19 -07003668 // Similarly, set ACTION_EXIT to all hover targets and clear them.
3669 exitHoverTargets();
Vladislav Kaznacheevf847ee32016-11-21 14:11:00 -08003670 exitTooltipHoverTargets();
Jeff Brown59a422e2012-04-19 15:19:19 -07003671
Chet Haase9c087442011-01-12 16:20:16 -08003672 // In case view is detached while transition is running
Chet Haaseb9895022013-04-02 15:10:58 -07003673 mLayoutCalledWhileSuppressed = false;
Chet Haase9c087442011-01-12 16:20:16 -08003674
Christopher Tate86cab1b2011-01-13 20:28:55 -08003675 // Tear down our drag tracking
Vadim Tryshev1a68dc92015-07-20 17:01:50 -07003676 mChildrenInterestedInDrag = null;
3677 mIsInterestedInDrag = false;
3678 if (mCurrentDragStartEvent != null) {
3679 mCurrentDragStartEvent.recycle();
3680 mCurrentDragStartEvent = null;
Christopher Tate86cab1b2011-01-13 20:28:55 -08003681 }
3682
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003683 final int count = mChildrenCount;
3684 final View[] children = mChildren;
3685 for (int i = 0; i < count; i++) {
3686 children[i].dispatchDetachedFromWindow();
3687 }
John Reckca7a9da2014-03-05 16:29:07 -08003688 clearDisappearingChildren();
Chet Haasec633d2f2015-04-07 10:29:39 -07003689 final int transientCount = mTransientViews == null ? 0 : mTransientIndices.size();
3690 for (int i = 0; i < transientCount; ++i) {
3691 View view = mTransientViews.get(i);
3692 view.dispatchDetachedFromWindow();
3693 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003694 super.dispatchDetachedFromWindow();
3695 }
3696
Fabrice Di Meglio23c89fd2012-08-13 12:17:42 -07003697 /**
3698 * @hide
3699 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003700 @Override
Fabrice Di Meglio23c89fd2012-08-13 12:17:42 -07003701 protected void internalSetPadding(int left, int top, int right, int bottom) {
Romain Guy2440e672012-08-07 14:43:43 -07003702 super.internalSetPadding(left, top, right, bottom);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003703
Romain Guy13f35f32011-03-24 12:03:17 -07003704 if ((mPaddingLeft | mPaddingTop | mPaddingRight | mPaddingBottom) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003705 mGroupFlags |= FLAG_PADDING_NOT_NULL;
3706 } else {
3707 mGroupFlags &= ~FLAG_PADDING_NOT_NULL;
3708 }
3709 }
3710
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003711 @Override
3712 protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
3713 super.dispatchSaveInstanceState(container);
3714 final int count = mChildrenCount;
3715 final View[] children = mChildren;
3716 for (int i = 0; i < count; i++) {
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07003717 View c = children[i];
3718 if ((c.mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED) {
3719 c.dispatchSaveInstanceState(container);
3720 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003721 }
3722 }
3723
3724 /**
Romain Guy9fc27812011-04-27 14:21:41 -07003725 * Perform dispatching of a {@link #saveHierarchyState(android.util.SparseArray)} freeze()}
3726 * to only this view, not to its children. For use when overriding
3727 * {@link #dispatchSaveInstanceState(android.util.SparseArray)} dispatchFreeze()} to allow
3728 * subclasses to freeze their own state but not the state of their children.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003729 *
3730 * @param container the container
3731 */
3732 protected void dispatchFreezeSelfOnly(SparseArray<Parcelable> container) {
3733 super.dispatchSaveInstanceState(container);
3734 }
3735
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003736 @Override
3737 protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
3738 super.dispatchRestoreInstanceState(container);
3739 final int count = mChildrenCount;
3740 final View[] children = mChildren;
3741 for (int i = 0; i < count; i++) {
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07003742 View c = children[i];
3743 if ((c.mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED) {
3744 c.dispatchRestoreInstanceState(container);
3745 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003746 }
3747 }
3748
3749 /**
Romain Guy02739a82011-05-16 11:43:18 -07003750 * Perform dispatching of a {@link #restoreHierarchyState(android.util.SparseArray)}
3751 * to only this view, not to its children. For use when overriding
3752 * {@link #dispatchRestoreInstanceState(android.util.SparseArray)} to allow
3753 * subclasses to thaw their own state but not the state of their children.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003754 *
3755 * @param container the container
3756 */
3757 protected void dispatchThawSelfOnly(SparseArray<Parcelable> container) {
3758 super.dispatchRestoreInstanceState(container);
3759 }
3760
3761 /**
3762 * Enables or disables the drawing cache for each child of this view group.
3763 *
3764 * @param enabled true to enable the cache, false to dispose of it
3765 */
3766 protected void setChildrenDrawingCacheEnabled(boolean enabled) {
3767 if (enabled || (mPersistentDrawingCache & PERSISTENT_ALL_CACHES) != PERSISTENT_ALL_CACHES) {
3768 final View[] children = mChildren;
3769 final int count = mChildrenCount;
3770 for (int i = 0; i < count; i++) {
3771 children[i].setDrawingCacheEnabled(enabled);
3772 }
3773 }
3774 }
3775
sergeyvb37d44e2016-03-29 20:27:44 -07003776 /**
3777 * @hide
3778 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003779 @Override
sergeyvb37d44e2016-03-29 20:27:44 -07003780 public Bitmap createSnapshot(Bitmap.Config quality, int backgroundColor, boolean skipChildren) {
Romain Guy65554f22010-03-22 18:58:21 -07003781 int count = mChildrenCount;
3782 int[] visibilities = null;
3783
Romain Guy223ff5c2010-03-02 17:07:47 -08003784 if (skipChildren) {
Romain Guy65554f22010-03-22 18:58:21 -07003785 visibilities = new int[count];
3786 for (int i = 0; i < count; i++) {
3787 View child = getChildAt(i);
3788 visibilities[i] = child.getVisibility();
3789 if (visibilities[i] == View.VISIBLE) {
sergeyvb37d44e2016-03-29 20:27:44 -07003790 child.mViewFlags = (child.mViewFlags & ~View.VISIBILITY_MASK)
3791 | (View.INVISIBLE & View.VISIBILITY_MASK);
Romain Guy65554f22010-03-22 18:58:21 -07003792 }
3793 }
Romain Guy223ff5c2010-03-02 17:07:47 -08003794 }
3795
3796 Bitmap b = super.createSnapshot(quality, backgroundColor, skipChildren);
Romain Guy65554f22010-03-22 18:58:21 -07003797
3798 if (skipChildren) {
3799 for (int i = 0; i < count; i++) {
sergeyvb37d44e2016-03-29 20:27:44 -07003800 View child = getChildAt(i);
3801 child.mViewFlags = (child.mViewFlags & ~View.VISIBILITY_MASK)
3802 | (visibilities[i] & View.VISIBILITY_MASK);
Chet Haase5c13d892010-10-08 08:37:55 -07003803 }
Romain Guy65554f22010-03-22 18:58:21 -07003804 }
Romain Guy223ff5c2010-03-02 17:07:47 -08003805
3806 return b;
3807 }
3808
Philip Milne7b757812012-09-19 18:13:44 -07003809 /** Return true if this ViewGroup is laying out using optical bounds. */
3810 boolean isLayoutModeOptical() {
3811 return mLayoutMode == LAYOUT_MODE_OPTICAL_BOUNDS;
3812 }
Romain Guycbc67742012-04-27 16:12:57 -07003813
Alan Viverettebe463f22016-01-21 10:50:10 -05003814 @Override
Philip Milne7b757812012-09-19 18:13:44 -07003815 Insets computeOpticalInsets() {
3816 if (isLayoutModeOptical()) {
3817 int left = 0;
3818 int top = 0;
3819 int right = 0;
3820 int bottom = 0;
3821 for (int i = 0; i < mChildrenCount; i++) {
3822 View child = getChildAt(i);
3823 if (child.getVisibility() == VISIBLE) {
3824 Insets insets = child.getOpticalInsets();
3825 left = Math.max(left, insets.left);
3826 top = Math.max(top, insets.top);
3827 right = Math.max(right, insets.right);
3828 bottom = Math.max(bottom, insets.bottom);
3829 }
3830 }
3831 return Insets.of(left, top, right, bottom);
3832 } else {
3833 return Insets.NONE;
3834 }
3835 }
3836
3837 private static void fillRect(Canvas canvas, Paint paint, int x1, int y1, int x2, int y2) {
3838 if (x1 != x2 && y1 != y2) {
3839 if (x1 > x2) {
3840 int tmp = x1; x1 = x2; x2 = tmp;
3841 }
3842 if (y1 > y2) {
3843 int tmp = y1; y1 = y2; y2 = tmp;
3844 }
3845 canvas.drawRect(x1, y1, x2, y2, paint);
3846 }
3847 }
3848
3849 private static int sign(int x) {
3850 return (x >= 0) ? 1 : -1;
3851 }
3852
3853 private static void drawCorner(Canvas c, Paint paint, int x1, int y1, int dx, int dy, int lw) {
3854 fillRect(c, paint, x1, y1, x1 + dx, y1 + lw * sign(dy));
3855 fillRect(c, paint, x1, y1, x1 + lw * sign(dx), y1 + dy);
3856 }
3857
Romain Guy6410c0a2013-06-17 11:21:58 -07003858 private static void drawRectCorners(Canvas canvas, int x1, int y1, int x2, int y2, Paint paint,
3859 int lineLength, int lineWidth) {
Philip Milne7b757812012-09-19 18:13:44 -07003860 drawCorner(canvas, paint, x1, y1, lineLength, lineLength, lineWidth);
3861 drawCorner(canvas, paint, x1, y2, lineLength, -lineLength, lineWidth);
3862 drawCorner(canvas, paint, x2, y1, -lineLength, lineLength, lineWidth);
3863 drawCorner(canvas, paint, x2, y2, -lineLength, -lineLength, lineWidth);
3864 }
3865
3866 private static void fillDifference(Canvas canvas,
3867 int x2, int y2, int x3, int y3,
3868 int dx1, int dy1, int dx2, int dy2, Paint paint) {
3869 int x1 = x2 - dx1;
3870 int y1 = y2 - dy1;
3871
3872 int x4 = x3 + dx2;
3873 int y4 = y3 + dy2;
3874
3875 fillRect(canvas, paint, x1, y1, x4, y2);
3876 fillRect(canvas, paint, x1, y2, x2, y3);
3877 fillRect(canvas, paint, x3, y2, x4, y3);
3878 fillRect(canvas, paint, x1, y3, x4, y4);
Philip Milne10ca24a2012-04-23 15:38:27 -07003879 }
3880
3881 /**
Andrei Stingaceanu12448152017-07-12 17:39:45 +01003882 * Layout debugging code which draws rectangles around layout params.
3883 *
3884 * <p>This function is called automatically when the developer setting is enabled.<p/>
3885 *
3886 * <p>It is strongly advised to only call this function from debug builds as there is
3887 * a risk of leaking unwanted layout information.<p/>
3888 *
3889 * @param canvas the canvas on which to draw
3890 * @param paint the paint used to draw through
Philip Milne10ca24a2012-04-23 15:38:27 -07003891 */
Philip Milne7b757812012-09-19 18:13:44 -07003892 protected void onDebugDrawMargins(Canvas canvas, Paint paint) {
Philip Milne10ca24a2012-04-23 15:38:27 -07003893 for (int i = 0; i < getChildCount(); i++) {
3894 View c = getChildAt(i);
Philip Milne7b757812012-09-19 18:13:44 -07003895 c.getLayoutParams().onDebugDraw(c, canvas, paint);
Philip Milne10ca24a2012-04-23 15:38:27 -07003896 }
3897 }
3898
3899 /**
Andrei Stingaceanu12448152017-07-12 17:39:45 +01003900 * Layout debugging code which draws rectangles around:
3901 * <ul>
3902 * <li>optical bounds<li/>
3903 * <li>margins<li/>
3904 * <li>clip bounds<li/>
3905 * <ul/>
3906 *
3907 * <p>This function is called automatically when the developer setting is enabled.<p/>
3908 *
3909 * <p>It is strongly advised to only call this function from debug builds as there is
3910 * a risk of leaking unwanted layout information.<p/>
3911 *
3912 * @param canvas the canvas on which to draw
Philip Milne10ca24a2012-04-23 15:38:27 -07003913 */
3914 protected void onDebugDraw(Canvas canvas) {
Philip Milne7b757812012-09-19 18:13:44 -07003915 Paint paint = getDebugPaint();
3916
Philip Milne10ca24a2012-04-23 15:38:27 -07003917 // Draw optical bounds
Philip Milne7b757812012-09-19 18:13:44 -07003918 {
3919 paint.setColor(Color.RED);
3920 paint.setStyle(Paint.Style.STROKE);
Philip Milne7b757812012-09-19 18:13:44 -07003921
Philip Milne10ca24a2012-04-23 15:38:27 -07003922 for (int i = 0; i < getChildCount(); i++) {
3923 View c = getChildAt(i);
Chris Craika1dab8b2015-06-30 13:51:25 -07003924 if (c.getVisibility() != View.GONE) {
3925 Insets insets = c.getOpticalInsets();
Philip Milne7b757812012-09-19 18:13:44 -07003926
Chris Craika1dab8b2015-06-30 13:51:25 -07003927 drawRect(canvas, paint,
3928 c.getLeft() + insets.left,
3929 c.getTop() + insets.top,
3930 c.getRight() - insets.right - 1,
3931 c.getBottom() - insets.bottom - 1);
3932 }
Philip Milne10ca24a2012-04-23 15:38:27 -07003933 }
3934 }
3935
Philip Milne10ca24a2012-04-23 15:38:27 -07003936 // Draw margins
Philip Milne7b757812012-09-19 18:13:44 -07003937 {
3938 paint.setColor(Color.argb(63, 255, 0, 255));
3939 paint.setStyle(Paint.Style.FILL);
Philip Milne604f4402012-04-24 19:27:11 -07003940
Philip Milne7b757812012-09-19 18:13:44 -07003941 onDebugDrawMargins(canvas, paint);
3942 }
3943
3944 // Draw clip bounds
3945 {
Vadim Tryshevcdf38ba2016-10-11 18:33:10 -07003946 paint.setColor(DEBUG_CORNERS_COLOR);
Philip Milne7b757812012-09-19 18:13:44 -07003947 paint.setStyle(Paint.Style.FILL);
3948
Vadim Tryshevcdf38ba2016-10-11 18:33:10 -07003949 int lineLength = dipsToPixels(DEBUG_CORNERS_SIZE_DIP);
Philip Milne7b757812012-09-19 18:13:44 -07003950 int lineWidth = dipsToPixels(1);
3951 for (int i = 0; i < getChildCount(); i++) {
3952 View c = getChildAt(i);
Chris Craika1dab8b2015-06-30 13:51:25 -07003953 if (c.getVisibility() != View.GONE) {
3954 drawRectCorners(canvas, c.getLeft(), c.getTop(), c.getRight(), c.getBottom(),
3955 paint, lineLength, lineWidth);
3956 }
Philip Milne7b757812012-09-19 18:13:44 -07003957 }
Philip Milne604f4402012-04-24 19:27:11 -07003958 }
Philip Milne10ca24a2012-04-23 15:38:27 -07003959 }
3960
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003961 @Override
3962 protected void dispatchDraw(Canvas canvas) {
Chris Craika753f4c2014-07-24 12:39:17 -07003963 boolean usingRenderNodeProperties = canvas.isRecordingFor(mRenderNode);
Chris Craikab008f02014-05-23 17:55:03 -07003964 final int childrenCount = mChildrenCount;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003965 final View[] children = mChildren;
3966 int flags = mGroupFlags;
3967
3968 if ((flags & FLAG_RUN_ANIMATION) != 0 && canAnimate()) {
Romain Guy0d9275e2010-10-26 14:22:30 -07003969 final boolean buildCache = !isHardwareAccelerated();
Chris Craikab008f02014-05-23 17:55:03 -07003970 for (int i = 0; i < childrenCount; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003971 final View child = children[i];
3972 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
3973 final LayoutParams params = child.getLayoutParams();
Chris Craikab008f02014-05-23 17:55:03 -07003974 attachLayoutAnimationParameters(child, params, i, childrenCount);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003975 bindLayoutAnimation(child);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003976 }
3977 }
3978
3979 final LayoutAnimationController controller = mLayoutAnimationController;
3980 if (controller.willOverlap()) {
3981 mGroupFlags |= FLAG_OPTIMIZE_INVALIDATE;
3982 }
3983
3984 controller.start();
3985
3986 mGroupFlags &= ~FLAG_RUN_ANIMATION;
3987 mGroupFlags &= ~FLAG_ANIMATION_DONE;
3988
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003989 if (mAnimationListener != null) {
3990 mAnimationListener.onAnimationStart(controller.getAnimation());
3991 }
3992 }
3993
Selim Cinek19cadc22014-04-16 17:27:19 +02003994 int clipSaveCount = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003995 final boolean clipToPadding = (flags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK;
3996 if (clipToPadding) {
John Reck41f864e2016-05-12 15:07:49 -07003997 clipSaveCount = canvas.save(Canvas.CLIP_SAVE_FLAG);
Romain Guy8f2d94f2009-03-25 18:04:42 -07003998 canvas.clipRect(mScrollX + mPaddingLeft, mScrollY + mPaddingTop,
3999 mScrollX + mRight - mLeft - mPaddingRight,
4000 mScrollY + mBottom - mTop - mPaddingBottom);
Selim Cinek19cadc22014-04-16 17:27:19 +02004001 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004002
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004003 // We will draw our child's animation, let's reset the flag
Dianne Hackborn4702a852012-08-17 15:18:29 -07004004 mPrivateFlags &= ~PFLAG_DRAW_ANIMATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004005 mGroupFlags &= ~FLAG_INVALIDATE_REQUIRED;
4006
4007 boolean more = false;
4008 final long drawingTime = getDrawingTime();
4009
Chris Craik8afd0f22014-08-21 17:41:57 -07004010 if (usingRenderNodeProperties) canvas.insertReorderBarrier();
Chet Haasec633d2f2015-04-07 10:29:39 -07004011 final int transientCount = mTransientIndices == null ? 0 : mTransientIndices.size();
4012 int transientIndex = transientCount != 0 ? 0 : -1;
Chris Craikab008f02014-05-23 17:55:03 -07004013 // Only use the preordered list if not HW accelerated, since the HW pipeline will do the
4014 // draw reordering internally
Chris Craika753f4c2014-07-24 12:39:17 -07004015 final ArrayList<View> preorderedList = usingRenderNodeProperties
Chris Craikab008f02014-05-23 17:55:03 -07004016 ? null : buildOrderedChildList();
4017 final boolean customOrder = preorderedList == null
4018 && isChildrenDrawingOrderEnabled();
4019 for (int i = 0; i < childrenCount; i++) {
Chet Haasec633d2f2015-04-07 10:29:39 -07004020 while (transientIndex >= 0 && mTransientIndices.get(transientIndex) == i) {
4021 final View transientChild = mTransientViews.get(transientIndex);
4022 if ((transientChild.mViewFlags & VISIBILITY_MASK) == VISIBLE ||
4023 transientChild.getAnimation() != null) {
4024 more |= drawChild(canvas, transientChild, drawingTime);
4025 }
4026 transientIndex++;
4027 if (transientIndex >= transientCount) {
4028 transientIndex = -1;
4029 }
4030 }
Alan Viverettea7b85e62016-01-22 10:14:02 -05004031
4032 final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
4033 final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);
Chris Craikab008f02014-05-23 17:55:03 -07004034 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
4035 more |= drawChild(canvas, child, drawingTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004036 }
4037 }
Chet Haasec633d2f2015-04-07 10:29:39 -07004038 while (transientIndex >= 0) {
4039 // there may be additional transient views after the normal views
4040 final View transientChild = mTransientViews.get(transientIndex);
4041 if ((transientChild.mViewFlags & VISIBILITY_MASK) == VISIBLE ||
4042 transientChild.getAnimation() != null) {
4043 more |= drawChild(canvas, transientChild, drawingTime);
4044 }
4045 transientIndex++;
4046 if (transientIndex >= transientCount) {
4047 break;
4048 }
4049 }
Chris Craikab008f02014-05-23 17:55:03 -07004050 if (preorderedList != null) preorderedList.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004051
4052 // Draw any disappearing views that have animations
4053 if (mDisappearingChildren != null) {
4054 final ArrayList<View> disappearingChildren = mDisappearingChildren;
4055 final int disappearingCount = disappearingChildren.size() - 1;
4056 // Go backwards -- we may delete as animations finish
4057 for (int i = disappearingCount; i >= 0; i--) {
4058 final View child = disappearingChildren.get(i);
4059 more |= drawChild(canvas, child, drawingTime);
4060 }
4061 }
Chris Craik8afd0f22014-08-21 17:41:57 -07004062 if (usingRenderNodeProperties) canvas.insertInorderBarrier();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004063
Philip Milne10ca24a2012-04-23 15:38:27 -07004064 if (debugDraw()) {
4065 onDebugDraw(canvas);
4066 }
4067
Chris Craike4cf1522014-08-04 17:55:22 -07004068 if (clipToPadding) {
Selim Cinek19cadc22014-04-16 17:27:19 +02004069 canvas.restoreToCount(clipSaveCount);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004070 }
4071
4072 // mGroupFlags might have been updated by drawChild()
4073 flags = mGroupFlags;
4074
4075 if ((flags & FLAG_INVALIDATE_REQUIRED) == FLAG_INVALIDATE_REQUIRED) {
Romain Guy849d0a32011-02-01 17:20:48 -08004076 invalidate(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004077 }
4078
4079 if ((flags & FLAG_ANIMATION_DONE) == 0 && (flags & FLAG_NOTIFY_ANIMATION_LISTENER) == 0 &&
4080 mLayoutAnimationController.isDone() && !more) {
4081 // We want to erase the drawing cache and notify the listener after the
4082 // next frame is drawn because one extra invalidate() is caused by
4083 // drawChild() after the animation is over
4084 mGroupFlags |= FLAG_NOTIFY_ANIMATION_LISTENER;
4085 final Runnable end = new Runnable() {
Alan Viverettebe463f22016-01-21 10:50:10 -05004086 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004087 public void run() {
4088 notifyAnimationListener();
4089 }
4090 };
4091 post(end);
4092 }
4093 }
Romain Guy8506ab42009-06-11 17:35:47 -07004094
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004095 /**
Chet Haaseedf6f4b2013-03-26 07:55:30 -07004096 * Returns the ViewGroupOverlay for this view group, creating it if it does
4097 * not yet exist. In addition to {@link ViewOverlay}'s support for drawables,
4098 * {@link ViewGroupOverlay} allows views to be added to the overlay. These
4099 * views, like overlay drawables, are visual-only; they do not receive input
4100 * events and should not be used as anything other than a temporary
4101 * representation of a view in a parent container, such as might be used
4102 * by an animation effect.
4103 *
Chet Haase95399492013-04-08 14:30:31 -07004104 * <p>Note: Overlays do not currently work correctly with {@link
4105 * SurfaceView} or {@link TextureView}; contents in overlays for these
4106 * types of views may not display correctly.</p>
4107 *
Chet Haaseedf6f4b2013-03-26 07:55:30 -07004108 * @return The ViewGroupOverlay object for this view.
4109 * @see ViewGroupOverlay
4110 */
4111 @Override
4112 public ViewGroupOverlay getOverlay() {
4113 if (mOverlay == null) {
4114 mOverlay = new ViewGroupOverlay(mContext, this);
4115 }
4116 return (ViewGroupOverlay) mOverlay;
4117 }
4118
4119 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004120 * Returns the index of the child to draw for this iteration. Override this
4121 * if you want to change the drawing order of children. By default, it
4122 * returns i.
4123 * <p>
Romain Guy293451e2009-11-04 13:59:48 -08004124 * NOTE: In order for this method to be called, you must enable child ordering
4125 * first by calling {@link #setChildrenDrawingOrderEnabled(boolean)}.
Romain Guy8506ab42009-06-11 17:35:47 -07004126 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004127 * @param i The current iteration.
4128 * @return The index of the child to draw this iteration.
Chet Haase5c13d892010-10-08 08:37:55 -07004129 *
Romain Guy293451e2009-11-04 13:59:48 -08004130 * @see #setChildrenDrawingOrderEnabled(boolean)
4131 * @see #isChildrenDrawingOrderEnabled()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004132 */
4133 protected int getChildDrawingOrder(int childCount, int i) {
4134 return i;
4135 }
Romain Guy8506ab42009-06-11 17:35:47 -07004136
Chris Craikab008f02014-05-23 17:55:03 -07004137 private boolean hasChildWithZ() {
4138 for (int i = 0; i < mChildrenCount; i++) {
4139 if (mChildren[i].getZ() != 0) return true;
4140 }
4141 return false;
4142 }
4143
4144 /**
4145 * Populates (and returns) mPreSortedChildren with a pre-ordered list of the View's children,
Chris Craik57c79c82014-09-30 12:54:31 -07004146 * sorted first by Z, then by child drawing order (if applicable). This list must be cleared
4147 * after use to avoid leaking child Views.
Chris Craikab008f02014-05-23 17:55:03 -07004148 *
4149 * Uses a stable, insertion sort which is commonly O(n) for ViewGroups with very few elevated
4150 * children.
4151 */
George Mount81206522014-09-26 21:53:39 -07004152 ArrayList<View> buildOrderedChildList() {
Alan Viverettea7b85e62016-01-22 10:14:02 -05004153 final int childrenCount = mChildrenCount;
4154 if (childrenCount <= 1 || !hasChildWithZ()) return null;
Chris Craikab008f02014-05-23 17:55:03 -07004155
4156 if (mPreSortedChildren == null) {
Alan Viverettea7b85e62016-01-22 10:14:02 -05004157 mPreSortedChildren = new ArrayList<>(childrenCount);
Chris Craikab008f02014-05-23 17:55:03 -07004158 } else {
Chris Craikfc563772016-05-04 13:34:30 -07004159 // callers should clear, so clear shouldn't be necessary, but for safety...
4160 mPreSortedChildren.clear();
Alan Viverettea7b85e62016-01-22 10:14:02 -05004161 mPreSortedChildren.ensureCapacity(childrenCount);
Chris Craikab008f02014-05-23 17:55:03 -07004162 }
4163
Alan Viverettea7b85e62016-01-22 10:14:02 -05004164 final boolean customOrder = isChildrenDrawingOrderEnabled();
4165 for (int i = 0; i < childrenCount; i++) {
Chris Craikab008f02014-05-23 17:55:03 -07004166 // add next child (in child order) to end of list
Alan Viverettea7b85e62016-01-22 10:14:02 -05004167 final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
4168 final View nextChild = mChildren[childIndex];
4169 final float currentZ = nextChild.getZ();
Chris Craikab008f02014-05-23 17:55:03 -07004170
4171 // insert ahead of any Views with greater Z
4172 int insertIndex = i;
4173 while (insertIndex > 0 && mPreSortedChildren.get(insertIndex - 1).getZ() > currentZ) {
4174 insertIndex--;
4175 }
4176 mPreSortedChildren.add(insertIndex, nextChild);
4177 }
4178 return mPreSortedChildren;
4179 }
4180
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004181 private void notifyAnimationListener() {
4182 mGroupFlags &= ~FLAG_NOTIFY_ANIMATION_LISTENER;
4183 mGroupFlags |= FLAG_ANIMATION_DONE;
4184
4185 if (mAnimationListener != null) {
4186 final Runnable end = new Runnable() {
Alan Viverettebe463f22016-01-21 10:50:10 -05004187 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004188 public void run() {
4189 mAnimationListener.onAnimationEnd(mLayoutAnimationController.getAnimation());
4190 }
4191 };
4192 post(end);
4193 }
4194
Romain Guy849d0a32011-02-01 17:20:48 -08004195 invalidate(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004196 }
4197
4198 /**
Chet Haasedaf98e92011-01-10 14:10:36 -08004199 * This method is used to cause children of this ViewGroup to restore or recreate their
4200 * display lists. It is called by getDisplayList() when the parent ViewGroup does not need
4201 * to recreate its own display list, which would happen if it went through the normal
4202 * draw/dispatchDraw mechanisms.
4203 *
4204 * @hide
4205 */
4206 @Override
4207 protected void dispatchGetDisplayList() {
4208 final int count = mChildrenCount;
4209 final View[] children = mChildren;
4210 for (int i = 0; i < count; i++) {
4211 final View child = children[i];
John Reckc2330f52015-04-28 13:18:52 -07004212 if (((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null)) {
Chet Haase6c0665f2014-08-01 13:32:27 -07004213 recreateChildDisplayList(child);
Romain Guy2f57ba52011-02-03 18:03:29 -08004214 }
Chet Haasedaf98e92011-01-10 14:10:36 -08004215 }
Chet Haase91cedf12013-03-11 07:56:30 -07004216 if (mOverlay != null) {
Chet Haaseedf6f4b2013-03-26 07:55:30 -07004217 View overlayView = mOverlay.getOverlayView();
Chet Haase6c0665f2014-08-01 13:32:27 -07004218 recreateChildDisplayList(overlayView);
Chet Haase91cedf12013-03-11 07:56:30 -07004219 }
Chet Haase6c0665f2014-08-01 13:32:27 -07004220 if (mDisappearingChildren != null) {
4221 final ArrayList<View> disappearingChildren = mDisappearingChildren;
4222 final int disappearingCount = disappearingChildren.size();
4223 for (int i = 0; i < disappearingCount; ++i) {
4224 final View child = disappearingChildren.get(i);
4225 recreateChildDisplayList(child);
4226 }
4227 }
4228 }
4229
4230 private void recreateChildDisplayList(View child) {
Chris Craik31a2d062015-05-01 14:22:47 -07004231 child.mRecreateDisplayList = (child.mPrivateFlags & PFLAG_INVALIDATED) != 0;
Chet Haase6c0665f2014-08-01 13:32:27 -07004232 child.mPrivateFlags &= ~PFLAG_INVALIDATED;
Chris Craik31a2d062015-05-01 14:22:47 -07004233 child.updateDisplayListIfDirty();
Chet Haase6c0665f2014-08-01 13:32:27 -07004234 child.mRecreateDisplayList = false;
Chet Haasedaf98e92011-01-10 14:10:36 -08004235 }
4236
4237 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004238 * Draw one child of this View Group. This method is responsible for getting
4239 * the canvas in the right state. This includes clipping, translating so
4240 * that the child's scrolled origin is at 0, 0, and applying any animation
4241 * transformations.
4242 *
4243 * @param canvas The canvas on which to draw the child
4244 * @param child Who to draw
Chet Haasebcca79a2012-02-14 08:45:14 -08004245 * @param drawingTime The time at which draw is occurring
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004246 * @return True if an invalidate() was issued
4247 */
4248 protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
Chet Haase64a48c12012-02-13 16:33:29 -08004249 return child.draw(canvas, this, drawingTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004250 }
4251
Alan Viverette922e1c62015-05-05 17:18:27 -07004252 @Override
4253 void getScrollIndicatorBounds(@NonNull Rect out) {
4254 super.getScrollIndicatorBounds(out);
4255
4256 // If we have padding and we're supposed to clip children to that
4257 // padding, offset the scroll indicators to match our clip bounds.
4258 final boolean clipToPadding = (mGroupFlags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK;
4259 if (clipToPadding) {
4260 out.left += mPaddingLeft;
4261 out.right -= mPaddingRight;
4262 out.top += mPaddingTop;
4263 out.bottom -= mPaddingBottom;
4264 }
4265 }
4266
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004267 /**
Chris Craikd863a102013-12-19 13:31:15 -08004268 * Returns whether this group's children are clipped to their bounds before drawing.
Chet Haase430742f2013-04-12 11:18:36 -07004269 * The default value is true.
4270 * @see #setClipChildren(boolean)
4271 *
4272 * @return True if the group's children will be clipped to their bounds,
4273 * false otherwise.
4274 */
Chris Craik5c75c522014-09-05 14:08:08 -07004275 @ViewDebug.ExportedProperty(category = "drawing")
Chet Haase430742f2013-04-12 11:18:36 -07004276 public boolean getClipChildren() {
4277 return ((mGroupFlags & FLAG_CLIP_CHILDREN) != 0);
4278 }
4279
4280 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004281 * By default, children are clipped to their bounds before drawing. This
4282 * allows view groups to override this behavior for animations, etc.
4283 *
4284 * @param clipChildren true to clip children to their bounds,
4285 * false otherwise
4286 * @attr ref android.R.styleable#ViewGroup_clipChildren
4287 */
4288 public void setClipChildren(boolean clipChildren) {
Chet Haasea1cff502012-02-21 13:43:44 -08004289 boolean previousValue = (mGroupFlags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN;
4290 if (clipChildren != previousValue) {
4291 setBooleanFlag(FLAG_CLIP_CHILDREN, clipChildren);
Chet Haase1271e2c2012-04-20 09:54:27 -07004292 for (int i = 0; i < mChildrenCount; ++i) {
4293 View child = getChildAt(i);
Chris Craik64a12e12014-03-28 18:12:12 -07004294 if (child.mRenderNode != null) {
4295 child.mRenderNode.setClipToBounds(clipChildren);
Chet Haasea1cff502012-02-21 13:43:44 -08004296 }
4297 }
John Reckaae9f3b2014-07-28 09:30:36 -07004298 invalidate(true);
Chet Haasea1cff502012-02-21 13:43:44 -08004299 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004300 }
4301
4302 /**
Doris Liub134b5e2015-05-28 17:26:46 -07004303 * Sets whether this ViewGroup will clip its children to its padding and resize (but not
4304 * clip) any EdgeEffect to the padded region, if padding is present.
Chris Craikb1652962014-11-14 17:05:06 -08004305 * <p>
4306 * By default, children are clipped to the padding of their parent
Doris Liub134b5e2015-05-28 17:26:46 -07004307 * ViewGroup. This clipping behavior is only enabled if padding is non-zero.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004308 *
Doris Liub134b5e2015-05-28 17:26:46 -07004309 * @param clipToPadding true to clip children to the padding of the group, and resize (but
4310 * not clip) any EdgeEffect to the padded region. False otherwise.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004311 * @attr ref android.R.styleable#ViewGroup_clipToPadding
4312 */
4313 public void setClipToPadding(boolean clipToPadding) {
John Reck9fa3a242014-06-27 15:57:19 -07004314 if (hasBooleanFlag(FLAG_CLIP_TO_PADDING) != clipToPadding) {
4315 setBooleanFlag(FLAG_CLIP_TO_PADDING, clipToPadding);
John Reckaae9f3b2014-07-28 09:30:36 -07004316 invalidate(true);
John Reck9fa3a242014-06-27 15:57:19 -07004317 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004318 }
4319
4320 /**
Doris Liub134b5e2015-05-28 17:26:46 -07004321 * Returns whether this ViewGroup will clip its children to its padding, and resize (but
4322 * not clip) any EdgeEffect to the padded region, if padding is present.
Chris Craikb1652962014-11-14 17:05:06 -08004323 * <p>
4324 * By default, children are clipped to the padding of their parent
4325 * Viewgroup. This clipping behavior is only enabled if padding is non-zero.
Adam Powell1c35b082014-07-11 15:37:15 -07004326 *
Doris Liub134b5e2015-05-28 17:26:46 -07004327 * @return true if this ViewGroup clips children to its padding and resizes (but doesn't
4328 * clip) any EdgeEffect to the padded region, false otherwise.
Adam Powell1c35b082014-07-11 15:37:15 -07004329 *
4330 * @attr ref android.R.styleable#ViewGroup_clipToPadding
4331 */
Chris Craik5c75c522014-09-05 14:08:08 -07004332 @ViewDebug.ExportedProperty(category = "drawing")
Adam Powell1c35b082014-07-11 15:37:15 -07004333 public boolean getClipToPadding() {
4334 return hasBooleanFlag(FLAG_CLIP_TO_PADDING);
4335 }
4336
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004337 @Override
4338 public void dispatchSetSelected(boolean selected) {
4339 final View[] children = mChildren;
4340 final int count = mChildrenCount;
4341 for (int i = 0; i < count; i++) {
4342 children[i].setSelected(selected);
4343 }
4344 }
Romain Guy8506ab42009-06-11 17:35:47 -07004345
Dianne Hackbornd0fa3712010-09-14 18:57:14 -07004346 @Override
4347 public void dispatchSetActivated(boolean activated) {
4348 final View[] children = mChildren;
4349 final int count = mChildrenCount;
4350 for (int i = 0; i < count; i++) {
Dianne Hackbornd0fa3712010-09-14 18:57:14 -07004351 children[i].setActivated(activated);
4352 }
4353 }
4354
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004355 @Override
4356 protected void dispatchSetPressed(boolean pressed) {
4357 final View[] children = mChildren;
4358 final int count = mChildrenCount;
4359 for (int i = 0; i < count; i++) {
Adam Powell035a1fc2012-02-27 15:23:50 -08004360 final View child = children[i];
4361 // Children that are clickable on their own should not
4362 // show a pressed state when their parent view does.
4363 // Clearing a pressed state always propagates.
4364 if (!pressed || (!child.isClickable() && !child.isLongClickable())) {
4365 child.setPressed(pressed);
4366 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004367 }
4368 }
4369
Alan Viveretteb942b6f2014-12-08 10:37:39 -08004370 /**
4371 * Dispatches drawable hotspot changes to child views that meet at least
4372 * one of the following criteria:
4373 * <ul>
4374 * <li>Returns {@code false} from both {@link View#isClickable()} and
4375 * {@link View#isLongClickable()}</li>
4376 * <li>Requests duplication of parent state via
4377 * {@link View#setDuplicateParentStateEnabled(boolean)}</li>
4378 * </ul>
4379 *
4380 * @param x hotspot x coordinate
4381 * @param y hotspot y coordinate
4382 * @see #drawableHotspotChanged(float, float)
4383 */
4384 @Override
4385 public void dispatchDrawableHotspotChanged(float x, float y) {
4386 final int count = mChildrenCount;
4387 if (count == 0) {
4388 return;
4389 }
4390
4391 final View[] children = mChildren;
4392 for (int i = 0; i < count; i++) {
4393 final View child = children[i];
4394 // Children that are clickable on their own should not
4395 // receive hotspots when their parent view does.
4396 final boolean nonActionable = !child.isClickable() && !child.isLongClickable();
4397 final boolean duplicatesState = (child.mViewFlags & DUPLICATE_PARENT_STATE) != 0;
4398 if (nonActionable || duplicatesState) {
4399 final float[] point = getTempPoint();
4400 point[0] = x;
4401 point[1] = y;
4402 transformPointToViewLocal(point, child);
4403 child.drawableHotspotChanged(point[0], point[1]);
4404 }
4405 }
4406 }
4407
Adam Powell14874662013-07-18 19:42:41 -07004408 @Override
4409 void dispatchCancelPendingInputEvents() {
4410 super.dispatchCancelPendingInputEvents();
4411
4412 final View[] children = mChildren;
4413 final int count = mChildrenCount;
4414 for (int i = 0; i < count; i++) {
4415 children[i].dispatchCancelPendingInputEvents();
4416 }
4417 }
4418
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004419 /**
4420 * When this property is set to true, this ViewGroup supports static transformations on
4421 * children; this causes
4422 * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} to be
4423 * invoked when a child is drawn.
4424 *
4425 * Any subclass overriding
4426 * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} should
4427 * set this property to true.
4428 *
4429 * @param enabled True to enable static transformations on children, false otherwise.
4430 *
Chet Haase599913d2012-07-23 16:22:05 -07004431 * @see #getChildStaticTransformation(View, android.view.animation.Transformation)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004432 */
4433 protected void setStaticTransformationsEnabled(boolean enabled) {
4434 setBooleanFlag(FLAG_SUPPORT_STATIC_TRANSFORMATIONS, enabled);
4435 }
4436
4437 /**
Chet Haase2d46fcc2011-12-19 18:01:05 -08004438 * Sets <code>t</code> to be the static transformation of the child, if set, returning a
4439 * boolean to indicate whether a static transform was set. The default implementation
4440 * simply returns <code>false</code>; subclasses may override this method for different
Chet Haase599913d2012-07-23 16:22:05 -07004441 * behavior. {@link #setStaticTransformationsEnabled(boolean)} must be set to true
4442 * for this method to be called.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004443 *
Chet Haase2d46fcc2011-12-19 18:01:05 -08004444 * @param child The child view whose static transform is being requested
4445 * @param t The Transformation which will hold the result
4446 * @return true if the transformation was set, false otherwise
Romain Guy8506ab42009-06-11 17:35:47 -07004447 * @see #setStaticTransformationsEnabled(boolean)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004448 */
4449 protected boolean getChildStaticTransformation(View child, Transformation t) {
4450 return false;
4451 }
4452
Romain Guyf6991302013-06-05 17:19:01 -07004453 Transformation getChildTransformation() {
4454 if (mChildTransformation == null) {
4455 mChildTransformation = new Transformation();
4456 }
4457 return mChildTransformation;
4458 }
4459
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004460 /**
4461 * {@hide}
4462 */
4463 @Override
Alan Viverette8e1a7292017-02-27 10:57:58 -05004464 protected <T extends View> T findViewTraversal(@IdRes int id) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004465 if (id == mID) {
Alan Viverette8e1a7292017-02-27 10:57:58 -05004466 return (T) this;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004467 }
4468
4469 final View[] where = mChildren;
4470 final int len = mChildrenCount;
4471
4472 for (int i = 0; i < len; i++) {
4473 View v = where[i];
4474
Dianne Hackborn4702a852012-08-17 15:18:29 -07004475 if ((v.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004476 v = v.findViewById(id);
4477
4478 if (v != null) {
Alan Viverette8e1a7292017-02-27 10:57:58 -05004479 return (T) v;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004480 }
4481 }
4482 }
4483
4484 return null;
4485 }
4486
4487 /**
4488 * {@hide}
4489 */
4490 @Override
Alan Viverette8e1a7292017-02-27 10:57:58 -05004491 protected <T extends View> T findViewWithTagTraversal(Object tag) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004492 if (tag != null && tag.equals(mTag)) {
Alan Viverette8e1a7292017-02-27 10:57:58 -05004493 return (T) this;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004494 }
4495
4496 final View[] where = mChildren;
4497 final int len = mChildrenCount;
4498
4499 for (int i = 0; i < len; i++) {
4500 View v = where[i];
4501
Dianne Hackborn4702a852012-08-17 15:18:29 -07004502 if ((v.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004503 v = v.findViewWithTag(tag);
4504
4505 if (v != null) {
Alan Viverette8e1a7292017-02-27 10:57:58 -05004506 return (T) v;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004507 }
4508 }
4509 }
4510
4511 return null;
4512 }
4513
4514 /**
Jeff Brown4e6319b2010-12-13 10:36:51 -08004515 * {@hide}
4516 */
4517 @Override
Alan Viverette8e1a7292017-02-27 10:57:58 -05004518 protected <T extends View> T findViewByPredicateTraversal(Predicate<View> predicate,
4519 View childToSkip) {
Paul Duffinca4964c2017-02-07 15:04:10 +00004520 if (predicate.test(this)) {
Alan Viverette8e1a7292017-02-27 10:57:58 -05004521 return (T) this;
Jeff Brown4e6319b2010-12-13 10:36:51 -08004522 }
4523
4524 final View[] where = mChildren;
4525 final int len = mChildrenCount;
4526
4527 for (int i = 0; i < len; i++) {
4528 View v = where[i];
4529
Dianne Hackborn4702a852012-08-17 15:18:29 -07004530 if (v != childToSkip && (v.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
Jeff Brown4e6319b2010-12-13 10:36:51 -08004531 v = v.findViewByPredicate(predicate);
4532
4533 if (v != null) {
Alan Viverette8e1a7292017-02-27 10:57:58 -05004534 return (T) v;
Jeff Brown4e6319b2010-12-13 10:36:51 -08004535 }
4536 }
4537 }
4538
4539 return null;
4540 }
4541
4542 /**
Chet Haasec633d2f2015-04-07 10:29:39 -07004543 * This method adds a view to this container at the specified index purely for the
4544 * purposes of allowing that view to draw even though it is not a normal child of
4545 * the container. That is, the view does not participate in layout, focus, accessibility,
4546 * input, or other normal view operations; it is purely an item to be drawn during the normal
4547 * rendering operation of this container. The index that it is added at is the order
4548 * in which it will be drawn, with respect to the other views in the container.
4549 * For example, a transient view added at index 0 will be drawn before all other views
4550 * in the container because it will be drawn first (including before any real view
4551 * at index 0). There can be more than one transient view at any particular index;
4552 * these views will be drawn in the order in which they were added to the list of
4553 * transient views. The index of transient views can also be greater than the number
4554 * of normal views in the container; that just means that they will be drawn after all
4555 * other views are drawn.
4556 *
4557 * <p>Note that since transient views do not participate in layout, they must be sized
4558 * manually or, more typically, they should just use the size that they had before they
4559 * were removed from their container.</p>
4560 *
4561 * <p>Transient views are useful for handling animations of views that have been removed
4562 * from the container, but which should be animated out after the removal. Adding these
4563 * views as transient views allows them to participate in drawing without side-effecting
4564 * the layout of the container.</p>
4565 *
4566 * <p>Transient views must always be explicitly {@link #removeTransientView(View) removed}
4567 * from the container when they are no longer needed. For example, a transient view
4568 * which is added in order to fade it out in its old location should be removed
4569 * once the animation is complete.</p>
4570 *
4571 * @param view The view to be added
4572 * @param index The index at which this view should be drawn, must be >= 0.
4573 * This value is relative to the {@link #getChildAt(int) index} values in the normal
4574 * child list of this container, where any transient view at a particular index will
4575 * be drawn before any normal child at that same index.
Chris Craik66b41392015-04-17 10:08:10 -07004576 *
4577 * @hide
Chet Haasec633d2f2015-04-07 10:29:39 -07004578 */
4579 public void addTransientView(View view, int index) {
4580 if (index < 0) {
4581 return;
4582 }
4583 if (mTransientIndices == null) {
4584 mTransientIndices = new ArrayList<Integer>();
4585 mTransientViews = new ArrayList<View>();
4586 }
4587 final int oldSize = mTransientIndices.size();
4588 if (oldSize > 0) {
4589 int insertionIndex;
4590 for (insertionIndex = 0; insertionIndex < oldSize; ++insertionIndex) {
4591 if (index < mTransientIndices.get(insertionIndex)) {
4592 break;
4593 }
4594 }
4595 mTransientIndices.add(insertionIndex, index);
4596 mTransientViews.add(insertionIndex, view);
4597 } else {
4598 mTransientIndices.add(index);
4599 mTransientViews.add(view);
4600 }
4601 view.mParent = this;
4602 view.dispatchAttachedToWindow(mAttachInfo, (mViewFlags&VISIBILITY_MASK));
4603 invalidate(true);
4604 }
4605
4606 /**
4607 * Removes a view from the list of transient views in this container. If there is no
4608 * such transient view, this method does nothing.
4609 *
4610 * @param view The transient view to be removed
Chris Craik66b41392015-04-17 10:08:10 -07004611 *
4612 * @hide
Chet Haasec633d2f2015-04-07 10:29:39 -07004613 */
4614 public void removeTransientView(View view) {
4615 if (mTransientViews == null) {
4616 return;
4617 }
4618 final int size = mTransientViews.size();
4619 for (int i = 0; i < size; ++i) {
4620 if (view == mTransientViews.get(i)) {
4621 mTransientViews.remove(i);
4622 mTransientIndices.remove(i);
4623 view.mParent = null;
4624 view.dispatchDetachedFromWindow();
4625 invalidate(true);
4626 return;
4627 }
4628 }
4629 }
4630
4631 /**
4632 * Returns the number of transient views in this container. Specific transient
4633 * views and the index at which they were added can be retrieved via
4634 * {@link #getTransientView(int)} and {@link #getTransientViewIndex(int)}.
4635 *
4636 * @see #addTransientView(View, int)
4637 * @return The number of transient views in this container
Chris Craik66b41392015-04-17 10:08:10 -07004638 *
4639 * @hide
Chet Haasec633d2f2015-04-07 10:29:39 -07004640 */
4641 public int getTransientViewCount() {
4642 return mTransientIndices == null ? 0 : mTransientIndices.size();
4643 }
4644
4645 /**
4646 * Given a valid position within the list of transient views, returns the index of
4647 * the transient view at that position.
4648 *
4649 * @param position The position of the index being queried. Must be at least 0
4650 * and less than the value returned by {@link #getTransientViewCount()}.
4651 * @return The index of the transient view stored in the given position if the
4652 * position is valid, otherwise -1
Chris Craik66b41392015-04-17 10:08:10 -07004653 *
4654 * @hide
Chet Haasec633d2f2015-04-07 10:29:39 -07004655 */
4656 public int getTransientViewIndex(int position) {
4657 if (position < 0 || mTransientIndices == null || position >= mTransientIndices.size()) {
4658 return -1;
4659 }
4660 return mTransientIndices.get(position);
4661 }
4662
4663 /**
4664 * Given a valid position within the list of transient views, returns the
4665 * transient view at that position.
4666 *
4667 * @param position The position of the view being queried. Must be at least 0
4668 * and less than the value returned by {@link #getTransientViewCount()}.
4669 * @return The transient view stored in the given position if the
4670 * position is valid, otherwise null
Chris Craik66b41392015-04-17 10:08:10 -07004671 *
4672 * @hide
Chet Haasec633d2f2015-04-07 10:29:39 -07004673 */
4674 public View getTransientView(int position) {
4675 if (mTransientViews == null || position >= mTransientViews.size()) {
4676 return null;
4677 }
4678 return mTransientViews.get(position);
4679 }
4680
4681 /**
Romain Guy393a52c2012-05-22 20:21:08 -07004682 * <p>Adds a child view. If no layout parameters are already set on the child, the
4683 * default parameters for this ViewGroup are set on the child.</p>
Filip Gruszczynskia33bdf32015-11-19 18:22:16 -08004684 *
Romain Guy393a52c2012-05-22 20:21:08 -07004685 * <p><strong>Note:</strong> do not invoke this method from
4686 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
4687 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004688 *
4689 * @param child the child view to add
4690 *
4691 * @see #generateDefaultLayoutParams()
4692 */
4693 public void addView(View child) {
4694 addView(child, -1);
4695 }
4696
4697 /**
4698 * Adds a child view. If no layout parameters are already set on the child, the
4699 * default parameters for this ViewGroup are set on the child.
Filip Gruszczynskia33bdf32015-11-19 18:22:16 -08004700 *
Romain Guy393a52c2012-05-22 20:21:08 -07004701 * <p><strong>Note:</strong> do not invoke this method from
4702 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
4703 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004704 *
4705 * @param child the child view to add
4706 * @param index the position at which to add the child
4707 *
4708 * @see #generateDefaultLayoutParams()
4709 */
4710 public void addView(View child, int index) {
Adam Powell45a9da52014-10-09 09:44:18 -07004711 if (child == null) {
4712 throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup");
4713 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004714 LayoutParams params = child.getLayoutParams();
4715 if (params == null) {
4716 params = generateDefaultLayoutParams();
4717 if (params == null) {
4718 throw new IllegalArgumentException("generateDefaultLayoutParams() cannot return null");
4719 }
4720 }
4721 addView(child, index, params);
4722 }
4723
4724 /**
4725 * Adds a child view with this ViewGroup's default layout parameters and the
4726 * specified width and height.
4727 *
Romain Guy393a52c2012-05-22 20:21:08 -07004728 * <p><strong>Note:</strong> do not invoke this method from
4729 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
4730 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
4731 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004732 * @param child the child view to add
4733 */
4734 public void addView(View child, int width, int height) {
4735 final LayoutParams params = generateDefaultLayoutParams();
4736 params.width = width;
4737 params.height = height;
4738 addView(child, -1, params);
4739 }
4740
4741 /**
4742 * Adds a child view with the specified layout parameters.
4743 *
Romain Guy393a52c2012-05-22 20:21:08 -07004744 * <p><strong>Note:</strong> do not invoke this method from
4745 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
4746 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
4747 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004748 * @param child the child view to add
4749 * @param params the layout parameters to set on the child
4750 */
Alan Viverettebe463f22016-01-21 10:50:10 -05004751 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004752 public void addView(View child, LayoutParams params) {
4753 addView(child, -1, params);
4754 }
4755
4756 /**
4757 * Adds a child view with the specified layout parameters.
4758 *
Romain Guy393a52c2012-05-22 20:21:08 -07004759 * <p><strong>Note:</strong> do not invoke this method from
4760 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
4761 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
4762 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004763 * @param child the child view to add
Alan Viverette77bb6f12015-02-11 17:24:33 -08004764 * @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 -08004765 * @param params the layout parameters to set on the child
4766 */
4767 public void addView(View child, int index, LayoutParams params) {
4768 if (DBG) {
4769 System.out.println(this + " addView");
4770 }
4771
Adam Powell45a9da52014-10-09 09:44:18 -07004772 if (child == null) {
4773 throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup");
4774 }
4775
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004776 // addViewInner() will call child.requestLayout() when setting the new LayoutParams
4777 // therefore, we call requestLayout() on ourselves before, so that the child's request
4778 // will be blocked at our level
4779 requestLayout();
Romain Guy849d0a32011-02-01 17:20:48 -08004780 invalidate(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004781 addViewInner(child, index, params, false);
4782 }
4783
Alan Viverettebe463f22016-01-21 10:50:10 -05004784 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004785 public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
4786 if (!checkLayoutParams(params)) {
4787 throw new IllegalArgumentException("Invalid LayoutParams supplied to " + this);
4788 }
4789 if (view.mParent != this) {
4790 throw new IllegalArgumentException("Given view not a child of " + this);
4791 }
4792 view.setLayoutParams(params);
4793 }
4794
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004795 protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
4796 return p != null;
4797 }
4798
4799 /**
4800 * Interface definition for a callback to be invoked when the hierarchy
4801 * within this view changed. The hierarchy changes whenever a child is added
4802 * to or removed from this view.
4803 */
4804 public interface OnHierarchyChangeListener {
4805 /**
4806 * Called when a new child is added to a parent view.
4807 *
4808 * @param parent the view in which a child was added
4809 * @param child the new child view added in the hierarchy
4810 */
4811 void onChildViewAdded(View parent, View child);
4812
4813 /**
4814 * Called when a child is removed from a parent view.
4815 *
4816 * @param parent the view from which the child was removed
4817 * @param child the child removed from the hierarchy
4818 */
4819 void onChildViewRemoved(View parent, View child);
4820 }
4821
4822 /**
4823 * Register a callback to be invoked when a child is added to or removed
4824 * from this view.
4825 *
4826 * @param listener the callback to invoke on hierarchy change
4827 */
4828 public void setOnHierarchyChangeListener(OnHierarchyChangeListener listener) {
4829 mOnHierarchyChangeListener = listener;
4830 }
4831
Adam Powell6690d012015-06-17 16:41:56 -07004832 void dispatchViewAdded(View child) {
4833 onViewAdded(child);
Philip Milnef51d91c2011-07-18 16:12:19 -07004834 if (mOnHierarchyChangeListener != null) {
4835 mOnHierarchyChangeListener.onChildViewAdded(this, child);
4836 }
4837 }
4838
4839 /**
Adam Powell6690d012015-06-17 16:41:56 -07004840 * Called when a new child is added to this ViewGroup. Overrides should always
4841 * call super.onViewAdded.
4842 *
4843 * @param child the added child view
Philip Milnef51d91c2011-07-18 16:12:19 -07004844 */
Adam Powell6690d012015-06-17 16:41:56 -07004845 public void onViewAdded(View child) {
4846 }
4847
4848 void dispatchViewRemoved(View child) {
4849 onViewRemoved(child);
Philip Milnef51d91c2011-07-18 16:12:19 -07004850 if (mOnHierarchyChangeListener != null) {
4851 mOnHierarchyChangeListener.onChildViewRemoved(this, child);
4852 }
4853 }
4854
Adam Powell6690d012015-06-17 16:41:56 -07004855 /**
4856 * Called when a child view is removed from this ViewGroup. Overrides should always
4857 * call super.onViewRemoved.
4858 *
4859 * @param child the removed child view
4860 */
4861 public void onViewRemoved(View child) {
4862 }
4863
Philip Milnecfb631b2012-10-26 10:51:46 -07004864 private void clearCachedLayoutMode() {
Svetoslav6254f482013-06-04 17:22:14 -07004865 if (!hasBooleanFlag(FLAG_LAYOUT_MODE_WAS_EXPLICITLY_SET)) {
Philip Milnecfb631b2012-10-26 10:51:46 -07004866 mLayoutMode = LAYOUT_MODE_UNDEFINED;
4867 }
4868 }
4869
4870 @Override
4871 protected void onAttachedToWindow() {
4872 super.onAttachedToWindow();
4873 clearCachedLayoutMode();
4874 }
4875
4876 @Override
4877 protected void onDetachedFromWindow() {
4878 super.onDetachedFromWindow();
4879 clearCachedLayoutMode();
4880 }
4881
John Reck2de950d2017-01-25 10:58:30 -08004882 /** @hide */
4883 @Override
4884 protected void destroyHardwareResources() {
4885 super.destroyHardwareResources();
4886 int count = getChildCount();
4887 for (int i = 0; i < count; i++) {
4888 getChildAt(i).destroyHardwareResources();
4889 }
4890 }
4891
Philip Milnef51d91c2011-07-18 16:12:19 -07004892 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004893 * Adds a view during layout. This is useful if in your onLayout() method,
4894 * you need to add more views (as does the list view for example).
4895 *
4896 * If index is negative, it means put it at the end of the list.
4897 *
4898 * @param child the view to add to the group
Alan Viverette77bb6f12015-02-11 17:24:33 -08004899 * @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 -08004900 * @param params the layout parameters to associate with the child
4901 * @return true if the child was added, false otherwise
4902 */
4903 protected boolean addViewInLayout(View child, int index, LayoutParams params) {
4904 return addViewInLayout(child, index, params, false);
4905 }
4906
4907 /**
4908 * Adds a view during layout. This is useful if in your onLayout() method,
4909 * you need to add more views (as does the list view for example).
4910 *
4911 * If index is negative, it means put it at the end of the list.
4912 *
4913 * @param child the view to add to the group
Alan Viverette77bb6f12015-02-11 17:24:33 -08004914 * @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 -08004915 * @param params the layout parameters to associate with the child
4916 * @param preventRequestLayout if true, calling this method will not trigger a
4917 * layout request on child
4918 * @return true if the child was added, false otherwise
4919 */
4920 protected boolean addViewInLayout(View child, int index, LayoutParams params,
4921 boolean preventRequestLayout) {
Adam Powell45a9da52014-10-09 09:44:18 -07004922 if (child == null) {
4923 throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup");
4924 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004925 child.mParent = null;
4926 addViewInner(child, index, params, preventRequestLayout);
Dianne Hackborn4702a852012-08-17 15:18:29 -07004927 child.mPrivateFlags = (child.mPrivateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004928 return true;
4929 }
4930
4931 /**
4932 * Prevents the specified child to be laid out during the next layout pass.
4933 *
4934 * @param child the child on which to perform the cleanup
4935 */
4936 protected void cleanupLayoutState(View child) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07004937 child.mPrivateFlags &= ~View.PFLAG_FORCE_LAYOUT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004938 }
4939
4940 private void addViewInner(View child, int index, LayoutParams params,
4941 boolean preventRequestLayout) {
4942
Chet Haasee8e45d32011-03-02 17:07:35 -08004943 if (mTransition != null) {
4944 // Don't prevent other add transitions from completing, but cancel remove
4945 // transitions to let them complete the process before we add to the container
4946 mTransition.cancel(LayoutTransition.DISAPPEARING);
Chet Haaseadd65772011-02-09 16:47:29 -08004947 }
4948
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004949 if (child.getParent() != null) {
4950 throw new IllegalStateException("The specified child already has a parent. " +
4951 "You must call removeView() on the child's parent first.");
4952 }
4953
Chet Haase21cd1382010-09-01 17:42:29 -07004954 if (mTransition != null) {
Chet Haase5e25c2c2010-09-16 11:15:56 -07004955 mTransition.addChild(this, child);
Chet Haase21cd1382010-09-01 17:42:29 -07004956 }
4957
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004958 if (!checkLayoutParams(params)) {
4959 params = generateLayoutParams(params);
4960 }
4961
4962 if (preventRequestLayout) {
4963 child.mLayoutParams = params;
4964 } else {
4965 child.setLayoutParams(params);
4966 }
4967
4968 if (index < 0) {
4969 index = mChildrenCount;
4970 }
4971
4972 addInArray(child, index);
4973
4974 // tell our children
4975 if (preventRequestLayout) {
4976 child.assignParent(this);
4977 } else {
4978 child.mParent = this;
4979 }
4980
Evan Rosky2ae1bf52017-05-11 11:18:45 -07004981 final boolean childHasFocus = child.hasFocus();
4982 if (childHasFocus) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004983 requestChildFocus(child, child.findFocus());
4984 }
Romain Guy8506ab42009-06-11 17:35:47 -07004985
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004986 AttachInfo ai = mAttachInfo;
Adam Powell4b867882011-09-16 12:59:46 -07004987 if (ai != null && (mGroupFlags & FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW) == 0) {
Romain Guy8506ab42009-06-11 17:35:47 -07004988 boolean lastKeepOn = ai.mKeepScreenOn;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004989 ai.mKeepScreenOn = false;
4990 child.dispatchAttachedToWindow(mAttachInfo, (mViewFlags&VISIBILITY_MASK));
4991 if (ai.mKeepScreenOn) {
4992 needGlobalAttributesUpdate(true);
4993 }
4994 ai.mKeepScreenOn = lastKeepOn;
4995 }
4996
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07004997 if (child.isLayoutDirectionInherited()) {
Fabrice Di Meglioa7e0bcd2012-10-16 19:55:01 -07004998 child.resetRtlProperties();
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07004999 }
5000
Adam Powell6690d012015-06-17 16:41:56 -07005001 dispatchViewAdded(child);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005002
5003 if ((child.mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE) {
5004 mGroupFlags |= FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE;
5005 }
Adam Powell539ee872012-02-03 19:00:49 -08005006
5007 if (child.hasTransientState()) {
5008 childHasTransientStateChanged(child, true);
5009 }
Svetoslav6254f482013-06-04 17:22:14 -07005010
Svetoslav8e3feb12014-02-24 13:46:47 -08005011 if (child.getVisibility() != View.GONE) {
Svetoslav00dbe812013-06-10 12:51:09 -07005012 notifySubtreeAccessibilityStateChangedIfNeeded();
Svetoslav6254f482013-06-04 17:22:14 -07005013 }
Chet Haasec633d2f2015-04-07 10:29:39 -07005014
5015 if (mTransientIndices != null) {
5016 final int transientCount = mTransientIndices.size();
5017 for (int i = 0; i < transientCount; ++i) {
5018 final int oldIndex = mTransientIndices.get(i);
5019 if (index <= oldIndex) {
5020 mTransientIndices.set(i, oldIndex + 1);
5021 }
5022 }
5023 }
Vadim Tryshev02ed4a02015-10-23 17:39:33 -07005024
5025 if (mCurrentDragStartEvent != null && child.getVisibility() == VISIBLE) {
5026 notifyChildOfDragStart(child);
5027 }
Vadim Tryshev5ca73982017-01-04 17:24:43 -08005028
5029 if (child.hasDefaultFocus()) {
5030 // When adding a child that contains default focus, either during inflation or while
5031 // manually assembling the hierarchy, update the ancestor default-focus chain.
5032 setDefaultFocus(child);
5033 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005034 }
5035
5036 private void addInArray(View child, int index) {
5037 View[] children = mChildren;
5038 final int count = mChildrenCount;
5039 final int size = children.length;
5040 if (index == count) {
5041 if (size == count) {
5042 mChildren = new View[size + ARRAY_CAPACITY_INCREMENT];
5043 System.arraycopy(children, 0, mChildren, 0, size);
5044 children = mChildren;
5045 }
5046 children[mChildrenCount++] = child;
5047 } else if (index < count) {
5048 if (size == count) {
5049 mChildren = new View[size + ARRAY_CAPACITY_INCREMENT];
5050 System.arraycopy(children, 0, mChildren, 0, index);
5051 System.arraycopy(children, index, mChildren, index + 1, count - index);
5052 children = mChildren;
5053 } else {
5054 System.arraycopy(children, index, children, index + 1, count - index);
5055 }
5056 children[index] = child;
5057 mChildrenCount++;
Joe Onorato03ab0c72011-01-06 15:46:27 -08005058 if (mLastTouchDownIndex >= index) {
5059 mLastTouchDownIndex++;
5060 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005061 } else {
5062 throw new IndexOutOfBoundsException("index=" + index + " count=" + count);
5063 }
5064 }
5065
5066 // This method also sets the child's mParent to null
5067 private void removeFromArray(int index) {
5068 final View[] children = mChildren;
Chet Haase21cd1382010-09-01 17:42:29 -07005069 if (!(mTransitioningViews != null && mTransitioningViews.contains(children[index]))) {
5070 children[index].mParent = null;
5071 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005072 final int count = mChildrenCount;
5073 if (index == count - 1) {
5074 children[--mChildrenCount] = null;
5075 } else if (index >= 0 && index < count) {
5076 System.arraycopy(children, index + 1, children, index, count - index - 1);
5077 children[--mChildrenCount] = null;
5078 } else {
5079 throw new IndexOutOfBoundsException();
5080 }
Joe Onorato03ab0c72011-01-06 15:46:27 -08005081 if (mLastTouchDownIndex == index) {
5082 mLastTouchDownTime = 0;
5083 mLastTouchDownIndex = -1;
5084 } else if (mLastTouchDownIndex > index) {
5085 mLastTouchDownIndex--;
5086 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005087 }
5088
5089 // This method also sets the children's mParent to null
5090 private void removeFromArray(int start, int count) {
5091 final View[] children = mChildren;
5092 final int childrenCount = mChildrenCount;
5093
5094 start = Math.max(0, start);
5095 final int end = Math.min(childrenCount, start + count);
5096
5097 if (start == end) {
5098 return;
5099 }
5100
5101 if (end == childrenCount) {
5102 for (int i = start; i < end; i++) {
5103 children[i].mParent = null;
5104 children[i] = null;
5105 }
5106 } else {
5107 for (int i = start; i < end; i++) {
5108 children[i].mParent = null;
5109 }
5110
5111 // Since we're looping above, we might as well do the copy, but is arraycopy()
5112 // faster than the extra 2 bounds checks we would do in the loop?
5113 System.arraycopy(children, end, children, start, childrenCount - end);
5114
5115 for (int i = childrenCount - (end - start); i < childrenCount; i++) {
5116 children[i] = null;
5117 }
5118 }
5119
5120 mChildrenCount -= (end - start);
5121 }
5122
5123 private void bindLayoutAnimation(View child) {
5124 Animation a = mLayoutAnimationController.getAnimationForView(child);
5125 child.setAnimation(a);
5126 }
5127
5128 /**
5129 * Subclasses should override this method to set layout animation
5130 * parameters on the supplied child.
5131 *
5132 * @param child the child to associate with animation parameters
5133 * @param params the child's layout parameters which hold the animation
5134 * parameters
5135 * @param index the index of the child in the view group
5136 * @param count the number of children in the view group
5137 */
5138 protected void attachLayoutAnimationParameters(View child,
5139 LayoutParams params, int index, int count) {
5140 LayoutAnimationController.AnimationParameters animationParams =
5141 params.layoutAnimationParameters;
5142 if (animationParams == null) {
5143 animationParams = new LayoutAnimationController.AnimationParameters();
5144 params.layoutAnimationParameters = animationParams;
5145 }
5146
5147 animationParams.count = count;
5148 animationParams.index = index;
5149 }
5150
5151 /**
5152 * {@inheritDoc}
Filip Gruszczynskia33bdf32015-11-19 18:22:16 -08005153 *
Romain Guy393a52c2012-05-22 20:21:08 -07005154 * <p><strong>Note:</strong> do not invoke this method from
5155 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
5156 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005157 */
Alan Viverettebe463f22016-01-21 10:50:10 -05005158 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005159 public void removeView(View view) {
Alan Viverette177ec4602014-10-17 13:34:50 -07005160 if (removeViewInternal(view)) {
5161 requestLayout();
5162 invalidate(true);
5163 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005164 }
5165
5166 /**
5167 * Removes a view during layout. This is useful if in your onLayout() method,
5168 * you need to remove more views.
5169 *
Romain Guy393a52c2012-05-22 20:21:08 -07005170 * <p><strong>Note:</strong> do not invoke this method from
5171 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
5172 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
Filip Gruszczynskia33bdf32015-11-19 18:22:16 -08005173 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005174 * @param view the view to remove from the group
5175 */
5176 public void removeViewInLayout(View view) {
5177 removeViewInternal(view);
5178 }
5179
5180 /**
5181 * Removes a range of views during layout. This is useful if in your onLayout() method,
5182 * you need to remove more views.
5183 *
Romain Guy393a52c2012-05-22 20:21:08 -07005184 * <p><strong>Note:</strong> do not invoke this method from
5185 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
5186 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
5187 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005188 * @param start the index of the first view to remove from the group
5189 * @param count the number of views to remove from the group
5190 */
5191 public void removeViewsInLayout(int start, int count) {
5192 removeViewsInternal(start, count);
5193 }
5194
5195 /**
5196 * Removes the view at the specified position in the group.
5197 *
Romain Guy393a52c2012-05-22 20:21:08 -07005198 * <p><strong>Note:</strong> do not invoke this method from
5199 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
5200 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
Filip Gruszczynskia33bdf32015-11-19 18:22:16 -08005201 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005202 * @param index the position in the group of the view to remove
5203 */
5204 public void removeViewAt(int index) {
5205 removeViewInternal(index, getChildAt(index));
5206 requestLayout();
Romain Guy849d0a32011-02-01 17:20:48 -08005207 invalidate(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005208 }
5209
5210 /**
5211 * Removes the specified range of views from the group.
5212 *
Romain Guy393a52c2012-05-22 20:21:08 -07005213 * <p><strong>Note:</strong> do not invoke this method from
5214 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
5215 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
5216 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005217 * @param start the first position in the group of the range of views to remove
5218 * @param count the number of views to remove
5219 */
5220 public void removeViews(int start, int count) {
5221 removeViewsInternal(start, count);
5222 requestLayout();
Romain Guy849d0a32011-02-01 17:20:48 -08005223 invalidate(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005224 }
5225
Alan Viverette177ec4602014-10-17 13:34:50 -07005226 private boolean removeViewInternal(View view) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005227 final int index = indexOfChild(view);
5228 if (index >= 0) {
5229 removeViewInternal(index, view);
Alan Viverette177ec4602014-10-17 13:34:50 -07005230 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005231 }
Alan Viverette177ec4602014-10-17 13:34:50 -07005232 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005233 }
5234
5235 private void removeViewInternal(int index, View view) {
Chet Haase21cd1382010-09-01 17:42:29 -07005236 if (mTransition != null) {
Chet Haase5e25c2c2010-09-16 11:15:56 -07005237 mTransition.removeChild(this, view);
Chet Haase21cd1382010-09-01 17:42:29 -07005238 }
5239
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005240 boolean clearChildFocus = false;
5241 if (view == mFocused) {
Alan Viverette223622a2013-12-17 13:29:02 -08005242 view.unFocus(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005243 clearChildFocus = true;
5244 }
Evan Rosky53fcf112017-01-26 14:37:55 -08005245 if (view == mFocusedInCluster) {
Evan Rosky0e8a6832017-04-10 12:35:15 -07005246 clearFocusedInCluster(view);
Vadim Tryshev01d8c492016-12-15 11:33:15 -08005247 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005248
Alan Viverette632af842014-10-28 13:45:11 -07005249 view.clearAccessibilityFocus();
Svetoslav Ganov961bf0e2012-05-08 09:40:03 -07005250
Jeff Brown59a422e2012-04-19 15:19:19 -07005251 cancelTouchTarget(view);
5252 cancelHoverTarget(view);
5253
Chet Haase21cd1382010-09-01 17:42:29 -07005254 if (view.getAnimation() != null ||
5255 (mTransitioningViews != null && mTransitioningViews.contains(view))) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005256 addDisappearingView(view);
5257 } else if (view.mAttachInfo != null) {
5258 view.dispatchDetachedFromWindow();
5259 }
5260
Adam Powell539ee872012-02-03 19:00:49 -08005261 if (view.hasTransientState()) {
5262 childHasTransientStateChanged(view, false);
5263 }
5264
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005265 needGlobalAttributesUpdate(false);
Romain Guy8506ab42009-06-11 17:35:47 -07005266
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005267 removeFromArray(index);
5268
Evan Rosky53fcf112017-01-26 14:37:55 -08005269 if (view == mDefaultFocus) {
5270 clearDefaultFocus(view);
5271 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005272 if (clearChildFocus) {
5273 clearChildFocus(view);
Svetoslav Ganov149567f2013-01-08 15:23:34 -08005274 if (!rootViewRequestFocus()) {
5275 notifyGlobalFocusCleared(this);
5276 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07005277 }
Romain Guy6fb05632012-11-29 10:50:33 -08005278
Adam Powell6690d012015-06-17 16:41:56 -07005279 dispatchViewRemoved(view);
Svetoslav6254f482013-06-04 17:22:14 -07005280
Svetoslav8e3feb12014-02-24 13:46:47 -08005281 if (view.getVisibility() != View.GONE) {
Svetoslav00dbe812013-06-10 12:51:09 -07005282 notifySubtreeAccessibilityStateChangedIfNeeded();
Svetoslav6254f482013-06-04 17:22:14 -07005283 }
Chet Haasec633d2f2015-04-07 10:29:39 -07005284
5285 int transientCount = mTransientIndices == null ? 0 : mTransientIndices.size();
5286 for (int i = 0; i < transientCount; ++i) {
5287 final int oldIndex = mTransientIndices.get(i);
5288 if (index < oldIndex) {
5289 mTransientIndices.set(i, oldIndex - 1);
5290 }
5291 }
Vadim Tryshev02ed4a02015-10-23 17:39:33 -07005292
5293 if (mCurrentDragStartEvent != null) {
5294 mChildrenInterestedInDrag.remove(view);
5295 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005296 }
5297
Chet Haase21cd1382010-09-01 17:42:29 -07005298 /**
5299 * Sets the LayoutTransition object for this ViewGroup. If the LayoutTransition object is
5300 * not null, changes in layout which occur because of children being added to or removed from
5301 * the ViewGroup will be animated according to the animations defined in that LayoutTransition
5302 * object. By default, the transition object is null (so layout changes are not animated).
5303 *
Chet Haaseef3cbfd2013-08-21 14:01:02 -07005304 * <p>Replacing a non-null transition will cause that previous transition to be
5305 * canceled, if it is currently running, to restore this container to
5306 * its correct post-transition state.</p>
5307 *
Chet Haase21cd1382010-09-01 17:42:29 -07005308 * @param transition The LayoutTransition object that will animated changes in layout. A value
5309 * of <code>null</code> means no transition will run on layout changes.
Chet Haase13cc1202010-09-03 15:39:20 -07005310 * @attr ref android.R.styleable#ViewGroup_animateLayoutChanges
Chet Haase21cd1382010-09-01 17:42:29 -07005311 */
5312 public void setLayoutTransition(LayoutTransition transition) {
Chet Haaseb20db3e2010-09-10 13:07:30 -07005313 if (mTransition != null) {
Chet Haasefee6f2b2013-08-27 12:22:29 -07005314 LayoutTransition previousTransition = mTransition;
5315 previousTransition.cancel();
5316 previousTransition.removeTransitionListener(mLayoutTransitionListener);
Chet Haaseb20db3e2010-09-10 13:07:30 -07005317 }
Chet Haase21cd1382010-09-01 17:42:29 -07005318 mTransition = transition;
Chet Haase13cc1202010-09-03 15:39:20 -07005319 if (mTransition != null) {
5320 mTransition.addTransitionListener(mLayoutTransitionListener);
5321 }
5322 }
5323
5324 /**
5325 * Gets the LayoutTransition object for this ViewGroup. If the LayoutTransition object is
5326 * not null, changes in layout which occur because of children being added to or removed from
5327 * the ViewGroup will be animated according to the animations defined in that LayoutTransition
5328 * object. By default, the transition object is null (so layout changes are not animated).
5329 *
5330 * @return LayoutTranstion The LayoutTransition object that will animated changes in layout.
5331 * A value of <code>null</code> means no transition will run on layout changes.
5332 */
5333 public LayoutTransition getLayoutTransition() {
5334 return mTransition;
Chet Haase21cd1382010-09-01 17:42:29 -07005335 }
5336
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005337 private void removeViewsInternal(int start, int count) {
Chris Craik18a759d2015-10-14 14:16:33 -07005338 final int end = start + count;
5339
5340 if (start < 0 || count < 0 || end > mChildrenCount) {
5341 throw new IndexOutOfBoundsException();
5342 }
5343
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005344 final View focused = mFocused;
5345 final boolean detach = mAttachInfo != null;
Svetoslav Ganov149567f2013-01-08 15:23:34 -08005346 boolean clearChildFocus = false;
Evan Rosky53fcf112017-01-26 14:37:55 -08005347 View clearDefaultFocus = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005348
5349 final View[] children = mChildren;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005350
5351 for (int i = start; i < end; i++) {
5352 final View view = children[i];
5353
Chet Haase21cd1382010-09-01 17:42:29 -07005354 if (mTransition != null) {
Chet Haase5e25c2c2010-09-16 11:15:56 -07005355 mTransition.removeChild(this, view);
Chet Haase21cd1382010-09-01 17:42:29 -07005356 }
5357
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005358 if (view == focused) {
Alan Viverette223622a2013-12-17 13:29:02 -08005359 view.unFocus(null);
Svetoslav Ganov149567f2013-01-08 15:23:34 -08005360 clearChildFocus = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005361 }
Vadim Tryshev5ca73982017-01-04 17:24:43 -08005362 if (view == mDefaultFocus) {
Evan Rosky53fcf112017-01-26 14:37:55 -08005363 clearDefaultFocus = view;
5364 }
5365 if (view == mFocusedInCluster) {
Evan Rosky0e8a6832017-04-10 12:35:15 -07005366 clearFocusedInCluster(view);
Vadim Tryshev01d8c492016-12-15 11:33:15 -08005367 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005368
Alan Viverette632af842014-10-28 13:45:11 -07005369 view.clearAccessibilityFocus();
Svetoslav Ganov961bf0e2012-05-08 09:40:03 -07005370
Jeff Brown59a422e2012-04-19 15:19:19 -07005371 cancelTouchTarget(view);
5372 cancelHoverTarget(view);
5373
Chet Haase21cd1382010-09-01 17:42:29 -07005374 if (view.getAnimation() != null ||
5375 (mTransitioningViews != null && mTransitioningViews.contains(view))) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005376 addDisappearingView(view);
5377 } else if (detach) {
5378 view.dispatchDetachedFromWindow();
5379 }
5380
Adam Powell539ee872012-02-03 19:00:49 -08005381 if (view.hasTransientState()) {
5382 childHasTransientStateChanged(view, false);
5383 }
5384
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005385 needGlobalAttributesUpdate(false);
Romain Guy8506ab42009-06-11 17:35:47 -07005386
Adam Powell6690d012015-06-17 16:41:56 -07005387 dispatchViewRemoved(view);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005388 }
5389
5390 removeFromArray(start, count);
5391
Evan Rosky53fcf112017-01-26 14:37:55 -08005392 if (clearDefaultFocus != null) {
5393 clearDefaultFocus(clearDefaultFocus);
5394 }
Svetoslav Ganov149567f2013-01-08 15:23:34 -08005395 if (clearChildFocus) {
5396 clearChildFocus(focused);
5397 if (!rootViewRequestFocus()) {
5398 notifyGlobalFocusCleared(focused);
5399 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005400 }
5401 }
5402
5403 /**
5404 * Call this method to remove all child views from the
5405 * ViewGroup.
Filip Gruszczynskia33bdf32015-11-19 18:22:16 -08005406 *
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>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005410 */
5411 public void removeAllViews() {
5412 removeAllViewsInLayout();
5413 requestLayout();
Romain Guy849d0a32011-02-01 17:20:48 -08005414 invalidate(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005415 }
5416
5417 /**
5418 * Called by a ViewGroup subclass to remove child views from itself,
5419 * when it must first know its size on screen before it can calculate how many
5420 * child views it will render. An example is a Gallery or a ListView, which
5421 * may "have" 50 children, but actually only render the number of children
5422 * that can currently fit inside the object on screen. Do not call
5423 * this method unless you are extending ViewGroup and understand the
5424 * view measuring and layout pipeline.
Romain Guy393a52c2012-05-22 20:21:08 -07005425 *
5426 * <p><strong>Note:</strong> do not invoke this method from
5427 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
5428 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005429 */
5430 public void removeAllViewsInLayout() {
5431 final int count = mChildrenCount;
5432 if (count <= 0) {
5433 return;
5434 }
5435
5436 final View[] children = mChildren;
5437 mChildrenCount = 0;
5438
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005439 final View focused = mFocused;
5440 final boolean detach = mAttachInfo != null;
Svetoslav Ganov149567f2013-01-08 15:23:34 -08005441 boolean clearChildFocus = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005442
5443 needGlobalAttributesUpdate(false);
Romain Guy8506ab42009-06-11 17:35:47 -07005444
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005445 for (int i = count - 1; i >= 0; i--) {
5446 final View view = children[i];
5447
Chet Haase21cd1382010-09-01 17:42:29 -07005448 if (mTransition != null) {
Chet Haase5e25c2c2010-09-16 11:15:56 -07005449 mTransition.removeChild(this, view);
Chet Haase21cd1382010-09-01 17:42:29 -07005450 }
5451
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005452 if (view == focused) {
Alan Viverette223622a2013-12-17 13:29:02 -08005453 view.unFocus(null);
Svetoslav Ganov149567f2013-01-08 15:23:34 -08005454 clearChildFocus = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005455 }
5456
Alan Viverette632af842014-10-28 13:45:11 -07005457 view.clearAccessibilityFocus();
Svetoslav Ganov961bf0e2012-05-08 09:40:03 -07005458
Jeff Brown59a422e2012-04-19 15:19:19 -07005459 cancelTouchTarget(view);
5460 cancelHoverTarget(view);
5461
Chet Haase21cd1382010-09-01 17:42:29 -07005462 if (view.getAnimation() != null ||
5463 (mTransitioningViews != null && mTransitioningViews.contains(view))) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005464 addDisappearingView(view);
5465 } else if (detach) {
5466 view.dispatchDetachedFromWindow();
5467 }
5468
Adam Powell539ee872012-02-03 19:00:49 -08005469 if (view.hasTransientState()) {
5470 childHasTransientStateChanged(view, false);
5471 }
5472
Adam Powell6690d012015-06-17 16:41:56 -07005473 dispatchViewRemoved(view);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005474
5475 view.mParent = null;
5476 children[i] = null;
5477 }
5478
Evan Rosky53fcf112017-01-26 14:37:55 -08005479 if (mDefaultFocus != null) {
5480 clearDefaultFocus(mDefaultFocus);
5481 }
Evan Rosky776fa5f2017-04-26 16:47:54 -07005482 if (mFocusedInCluster != null) {
5483 clearFocusedInCluster(mFocusedInCluster);
5484 }
Svetoslav Ganov149567f2013-01-08 15:23:34 -08005485 if (clearChildFocus) {
5486 clearChildFocus(focused);
5487 if (!rootViewRequestFocus()) {
5488 notifyGlobalFocusCleared(focused);
5489 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005490 }
5491 }
5492
5493 /**
5494 * Finishes the removal of a detached view. This method will dispatch the detached from
5495 * window event and notify the hierarchy change listener.
Chet Haaseca479d42012-08-30 17:20:08 -07005496 * <p>
5497 * This method is intended to be lightweight and makes no assumptions about whether the
5498 * parent or child should be redrawn. Proper use of this method will include also making
5499 * any appropriate {@link #requestLayout()} or {@link #invalidate()} calls.
5500 * For example, callers can {@link #post(Runnable) post} a {@link Runnable}
5501 * which performs a {@link #requestLayout()} on the next frame, after all detach/remove
5502 * calls are finished, causing layout to be run prior to redrawing the view hierarchy.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005503 *
5504 * @param child the child to be definitely removed from the view hierarchy
5505 * @param animate if true and the view has an animation, the view is placed in the
5506 * disappearing views list, otherwise, it is detached from the window
5507 *
5508 * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
5509 * @see #detachAllViewsFromParent()
5510 * @see #detachViewFromParent(View)
5511 * @see #detachViewFromParent(int)
5512 */
5513 protected void removeDetachedView(View child, boolean animate) {
Chet Haase21cd1382010-09-01 17:42:29 -07005514 if (mTransition != null) {
Chet Haase5e25c2c2010-09-16 11:15:56 -07005515 mTransition.removeChild(this, child);
Chet Haase21cd1382010-09-01 17:42:29 -07005516 }
5517
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005518 if (child == mFocused) {
5519 child.clearFocus();
5520 }
Vadim Tryshev5ca73982017-01-04 17:24:43 -08005521 if (child == mDefaultFocus) {
Evan Rosky53fcf112017-01-26 14:37:55 -08005522 clearDefaultFocus(child);
5523 }
5524 if (child == mFocusedInCluster) {
Evan Rosky0e8a6832017-04-10 12:35:15 -07005525 clearFocusedInCluster(child);
Vadim Tryshev01d8c492016-12-15 11:33:15 -08005526 }
Romain Guy8506ab42009-06-11 17:35:47 -07005527
Svetoslav Ganov961bf0e2012-05-08 09:40:03 -07005528 child.clearAccessibilityFocus();
5529
Jeff Brown59a422e2012-04-19 15:19:19 -07005530 cancelTouchTarget(child);
5531 cancelHoverTarget(child);
5532
Chet Haase21cd1382010-09-01 17:42:29 -07005533 if ((animate && child.getAnimation() != null) ||
5534 (mTransitioningViews != null && mTransitioningViews.contains(child))) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005535 addDisappearingView(child);
5536 } else if (child.mAttachInfo != null) {
5537 child.dispatchDetachedFromWindow();
5538 }
5539
Adam Powell539ee872012-02-03 19:00:49 -08005540 if (child.hasTransientState()) {
5541 childHasTransientStateChanged(child, false);
5542 }
5543
Adam Powell6690d012015-06-17 16:41:56 -07005544 dispatchViewRemoved(child);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005545 }
5546
5547 /**
5548 * Attaches a view to this view group. Attaching a view assigns this group as the parent,
Chet Haaseca479d42012-08-30 17:20:08 -07005549 * sets the layout parameters and puts the view in the list of children so that
5550 * it can be retrieved by calling {@link #getChildAt(int)}.
5551 * <p>
5552 * This method is intended to be lightweight and makes no assumptions about whether the
5553 * parent or child should be redrawn. Proper use of this method will include also making
5554 * any appropriate {@link #requestLayout()} or {@link #invalidate()} calls.
5555 * For example, callers can {@link #post(Runnable) post} a {@link Runnable}
5556 * which performs a {@link #requestLayout()} on the next frame, after all detach/attach
5557 * calls are finished, causing layout to be run prior to redrawing the view hierarchy.
5558 * <p>
5559 * This method should be called only for views which were detached from their parent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005560 *
5561 * @param child the child to attach
5562 * @param index the index at which the child should be attached
5563 * @param params the layout parameters of the child
5564 *
5565 * @see #removeDetachedView(View, boolean)
5566 * @see #detachAllViewsFromParent()
5567 * @see #detachViewFromParent(View)
5568 * @see #detachViewFromParent(int)
5569 */
5570 protected void attachViewToParent(View child, int index, LayoutParams params) {
5571 child.mLayoutParams = params;
5572
5573 if (index < 0) {
5574 index = mChildrenCount;
5575 }
5576
5577 addInArray(child, index);
5578
5579 child.mParent = this;
Dianne Hackborn4702a852012-08-17 15:18:29 -07005580 child.mPrivateFlags = (child.mPrivateFlags & ~PFLAG_DIRTY_MASK
5581 & ~PFLAG_DRAWING_CACHE_VALID)
5582 | PFLAG_DRAWN | PFLAG_INVALIDATED;
5583 this.mPrivateFlags |= PFLAG_INVALIDATED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005584
5585 if (child.hasFocus()) {
5586 requestChildFocus(child, child.findFocus());
5587 }
Adam Powellc5874092016-03-17 16:27:24 -07005588 dispatchVisibilityAggregated(isAttachedToWindow() && getWindowVisibility() == VISIBLE
5589 && isShown());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005590 }
5591
5592 /**
Chet Haaseca479d42012-08-30 17:20:08 -07005593 * Detaches a view from its parent. Detaching a view should be followed
5594 * either by a call to
5595 * {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
5596 * or a call to {@link #removeDetachedView(View, boolean)}. Detachment should only be
5597 * temporary; reattachment or removal should happen within the same drawing cycle as
5598 * detachment. When a view is detached, its parent is null and cannot be retrieved by a
5599 * call to {@link #getChildAt(int)}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005600 *
5601 * @param child the child to detach
5602 *
5603 * @see #detachViewFromParent(int)
5604 * @see #detachViewsFromParent(int, int)
5605 * @see #detachAllViewsFromParent()
5606 * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
5607 * @see #removeDetachedView(View, boolean)
5608 */
5609 protected void detachViewFromParent(View child) {
5610 removeFromArray(indexOfChild(child));
5611 }
5612
5613 /**
Chet Haaseca479d42012-08-30 17:20:08 -07005614 * Detaches a view from its parent. Detaching a view should be followed
5615 * either by a call to
5616 * {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
5617 * or a call to {@link #removeDetachedView(View, boolean)}. Detachment should only be
5618 * temporary; reattachment or removal should happen within the same drawing cycle as
5619 * detachment. When a view is detached, its parent is null and cannot be retrieved by a
5620 * call to {@link #getChildAt(int)}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005621 *
5622 * @param index the index of the child to detach
5623 *
5624 * @see #detachViewFromParent(View)
5625 * @see #detachAllViewsFromParent()
5626 * @see #detachViewsFromParent(int, int)
5627 * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
5628 * @see #removeDetachedView(View, boolean)
5629 */
5630 protected void detachViewFromParent(int index) {
5631 removeFromArray(index);
5632 }
5633
5634 /**
Chet Haaseca479d42012-08-30 17:20:08 -07005635 * Detaches a range of views from their parents. Detaching a view should be followed
5636 * either by a call to
5637 * {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
5638 * or a call to {@link #removeDetachedView(View, boolean)}. Detachment should only be
5639 * temporary; reattachment or removal should happen within the same drawing cycle as
5640 * detachment. When a view is detached, its parent is null and cannot be retrieved by a
5641 * call to {@link #getChildAt(int)}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005642 *
5643 * @param start the first index of the childrend range to detach
5644 * @param count the number of children to detach
5645 *
5646 * @see #detachViewFromParent(View)
5647 * @see #detachViewFromParent(int)
5648 * @see #detachAllViewsFromParent()
5649 * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
5650 * @see #removeDetachedView(View, boolean)
5651 */
5652 protected void detachViewsFromParent(int start, int count) {
5653 removeFromArray(start, count);
5654 }
5655
5656 /**
Chet Haaseca479d42012-08-30 17:20:08 -07005657 * Detaches all views from the parent. Detaching a view should be followed
5658 * either by a call to
5659 * {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
5660 * or a call to {@link #removeDetachedView(View, boolean)}. Detachment should only be
5661 * temporary; reattachment or removal should happen within the same drawing cycle as
5662 * detachment. When a view is detached, its parent is null and cannot be retrieved by a
5663 * call to {@link #getChildAt(int)}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005664 *
5665 * @see #detachViewFromParent(View)
5666 * @see #detachViewFromParent(int)
5667 * @see #detachViewsFromParent(int, int)
5668 * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
5669 * @see #removeDetachedView(View, boolean)
5670 */
5671 protected void detachAllViewsFromParent() {
5672 final int count = mChildrenCount;
5673 if (count <= 0) {
5674 return;
5675 }
5676
5677 final View[] children = mChildren;
5678 mChildrenCount = 0;
5679
5680 for (int i = count - 1; i >= 0; i--) {
5681 children[i].mParent = null;
5682 children[i] = null;
5683 }
5684 }
5685
Chris Craik9de95db2017-01-18 17:59:23 -08005686 @Override
5687 @CallSuper
5688 public void onDescendantInvalidated(@NonNull View child, @NonNull View target) {
5689 /*
5690 * HW-only, Rect-ignoring damage codepath
5691 *
5692 * We don't deal with rectangles here, since RenderThread native code computes damage for
5693 * everything drawn by HWUI (and SW layer / drawing cache doesn't keep track of damage area)
5694 */
5695
5696 // if set, combine the animation flag into the parent
5697 mPrivateFlags |= (target.mPrivateFlags & PFLAG_DRAW_ANIMATION);
5698
5699 if ((target.mPrivateFlags & ~PFLAG_DIRTY_MASK) != 0) {
5700 // We lazily use PFLAG_DIRTY, since computing opaque isn't worth the potential
5701 // optimization in provides in a DisplayList world.
5702 mPrivateFlags = (mPrivateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DIRTY;
5703
5704 // simplified invalidateChildInParent behavior: clear cache validity to be safe...
5705 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
Chris Craik3f06c6d2017-01-09 18:19:48 +00005706 }
5707
Chris Craik9de95db2017-01-18 17:59:23 -08005708 // ... and mark inval if in software layer that needs to repaint (hw handled in native)
5709 if (mLayerType == LAYER_TYPE_SOFTWARE) {
5710 // Layered parents should be invalidated. Escalate to a full invalidate (and note that
5711 // we do this after consuming any relevant flags from the originating descendant)
5712 mPrivateFlags |= PFLAG_INVALIDATED | PFLAG_DIRTY;
5713 target = this;
Chris Craik3f06c6d2017-01-09 18:19:48 +00005714 }
5715
Chris Craik9de95db2017-01-18 17:59:23 -08005716 if (mParent != null) {
5717 mParent.onDescendantInvalidated(this, target);
Chris Craik3f06c6d2017-01-09 18:19:48 +00005718 }
Chris Craik3f06c6d2017-01-09 18:19:48 +00005719 }
5720
5721
5722 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005723 * Don't call or override this method. It is used for the implementation of
5724 * the view hierarchy.
Chris Craik9de95db2017-01-18 17:59:23 -08005725 *
5726 * @deprecated Use {@link #onDescendantInvalidated(View, View)} instead to observe updates to
5727 * draw state in descendants.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005728 */
Chris Craik9de95db2017-01-18 17:59:23 -08005729 @Deprecated
Alan Viverettebe463f22016-01-21 10:50:10 -05005730 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005731 public final void invalidateChild(View child, final Rect dirty) {
Chris Craik9de95db2017-01-18 17:59:23 -08005732 final AttachInfo attachInfo = mAttachInfo;
5733 if (attachInfo != null && attachInfo.mHardwareAccelerated) {
5734 // HW accelerated fast path
5735 onDescendantInvalidated(child, child);
Chris Craik3f06c6d2017-01-09 18:19:48 +00005736 return;
5737 }
5738
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005739 ViewParent parent = this;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005740 if (attachInfo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005741 // If the child is drawing an animation, we want to copy this flag onto
5742 // ourselves and the parent to make sure the invalidate request goes
5743 // through
Chris Craik3f06c6d2017-01-09 18:19:48 +00005744 final boolean drawAnimation = (child.mPrivateFlags & PFLAG_DRAW_ANIMATION) != 0;
Romain Guy24443ea2009-05-11 11:56:30 -07005745
Romain Guyfe455af2012-02-15 16:40:20 -08005746 // Check whether the child that requests the invalidate is fully opaque
5747 // Views being animated or transformed are not considered opaque because we may
5748 // be invalidating their old position and need the parent to paint behind them.
5749 Matrix childMatrix = child.getMatrix();
5750 final boolean isOpaque = child.isOpaque() && !drawAnimation &&
5751 child.getAnimation() == null && childMatrix.isIdentity();
5752 // Mark the child as dirty, using the appropriate flag
5753 // Make sure we do not set both flags at the same time
Dianne Hackborn4702a852012-08-17 15:18:29 -07005754 int opaqueFlag = isOpaque ? PFLAG_DIRTY_OPAQUE : PFLAG_DIRTY;
Romain Guyfe455af2012-02-15 16:40:20 -08005755
John Reck96bb8ad2014-06-19 10:53:03 -07005756 if (child.mLayerType != LAYER_TYPE_NONE) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07005757 mPrivateFlags |= PFLAG_INVALIDATED;
5758 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
Romain Guyfe455af2012-02-15 16:40:20 -08005759 }
5760
5761 final int[] location = attachInfo.mInvalidateChildLocation;
5762 location[CHILD_LEFT_INDEX] = child.mLeft;
5763 location[CHILD_TOP_INDEX] = child.mTop;
Chet Haase599913d2012-07-23 16:22:05 -07005764 if (!childMatrix.isIdentity() ||
5765 (mGroupFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) {
Romain Guyfe455af2012-02-15 16:40:20 -08005766 RectF boundingRect = attachInfo.mTmpTransformRect;
5767 boundingRect.set(dirty);
Chet Haase599913d2012-07-23 16:22:05 -07005768 Matrix transformMatrix;
5769 if ((mGroupFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) {
5770 Transformation t = attachInfo.mTmpTransformation;
5771 boolean transformed = getChildStaticTransformation(child, t);
5772 if (transformed) {
5773 transformMatrix = attachInfo.mTmpMatrix;
5774 transformMatrix.set(t.getMatrix());
5775 if (!childMatrix.isIdentity()) {
5776 transformMatrix.preConcat(childMatrix);
5777 }
5778 } else {
5779 transformMatrix = childMatrix;
5780 }
5781 } else {
5782 transformMatrix = childMatrix;
5783 }
5784 transformMatrix.mapRect(boundingRect);
Alan Viverettec45b1d42015-11-16 15:38:59 -05005785 dirty.set((int) Math.floor(boundingRect.left),
5786 (int) Math.floor(boundingRect.top),
5787 (int) Math.ceil(boundingRect.right),
5788 (int) Math.ceil(boundingRect.bottom));
Romain Guyfe455af2012-02-15 16:40:20 -08005789 }
5790
5791 do {
5792 View view = null;
5793 if (parent instanceof View) {
5794 view = (View) parent;
Romain Guyfe455af2012-02-15 16:40:20 -08005795 }
5796
5797 if (drawAnimation) {
5798 if (view != null) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07005799 view.mPrivateFlags |= PFLAG_DRAW_ANIMATION;
Romain Guyfe455af2012-02-15 16:40:20 -08005800 } else if (parent instanceof ViewRootImpl) {
5801 ((ViewRootImpl) parent).mIsAnimating = true;
5802 }
5803 }
5804
5805 // If the parent is dirty opaque or not dirty, mark it dirty with the opaque
5806 // flag coming from the child that initiated the invalidate
5807 if (view != null) {
5808 if ((view.mViewFlags & FADING_EDGE_MASK) != 0 &&
5809 view.getSolidColor() == 0) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07005810 opaqueFlag = PFLAG_DIRTY;
Romain Guyfe455af2012-02-15 16:40:20 -08005811 }
Dianne Hackborn4702a852012-08-17 15:18:29 -07005812 if ((view.mPrivateFlags & PFLAG_DIRTY_MASK) != PFLAG_DIRTY) {
5813 view.mPrivateFlags = (view.mPrivateFlags & ~PFLAG_DIRTY_MASK) | opaqueFlag;
Romain Guyfe455af2012-02-15 16:40:20 -08005814 }
5815 }
5816
5817 parent = parent.invalidateChildInParent(location, dirty);
5818 if (view != null) {
5819 // Account for transform on current parent
5820 Matrix m = view.getMatrix();
5821 if (!m.isIdentity()) {
5822 RectF boundingRect = attachInfo.mTmpTransformRect;
5823 boundingRect.set(dirty);
5824 m.mapRect(boundingRect);
Alan Viverettec45b1d42015-11-16 15:38:59 -05005825 dirty.set((int) Math.floor(boundingRect.left),
5826 (int) Math.floor(boundingRect.top),
5827 (int) Math.ceil(boundingRect.right),
5828 (int) Math.ceil(boundingRect.bottom));
Romain Guyfe455af2012-02-15 16:40:20 -08005829 }
5830 }
5831 } while (parent != null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005832 }
5833 }
5834
5835 /**
5836 * Don't call or override this method. It is used for the implementation of
5837 * the view hierarchy.
5838 *
5839 * This implementation returns null if this ViewGroup does not have a parent,
5840 * if this ViewGroup is already fully invalidated or if the dirty rectangle
5841 * does not intersect with this ViewGroup's bounds.
Chris Craik9de95db2017-01-18 17:59:23 -08005842 *
5843 * @deprecated Use {@link #onDescendantInvalidated(View, View)} instead to observe updates to
5844 * draw state in descendants.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005845 */
Chris Craik9de95db2017-01-18 17:59:23 -08005846 @Deprecated
Alan Viverettebe463f22016-01-21 10:50:10 -05005847 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005848 public ViewParent invalidateChildInParent(final int[] location, final Rect dirty) {
Chris Craik3f06c6d2017-01-09 18:19:48 +00005849 if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID)) != 0) {
5850 // either DRAWN, or DRAWING_CACHE_VALID
5851 if ((mGroupFlags & (FLAG_OPTIMIZE_INVALIDATE | FLAG_ANIMATION_DONE))
5852 != FLAG_OPTIMIZE_INVALIDATE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005853 dirty.offset(location[CHILD_LEFT_INDEX] - mScrollX,
5854 location[CHILD_TOP_INDEX] - mScrollY);
Chet Haasea4f14eb2013-04-22 11:11:39 -07005855 if ((mGroupFlags & FLAG_CLIP_CHILDREN) == 0) {
5856 dirty.union(0, 0, mRight - mLeft, mBottom - mTop);
5857 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005858
5859 final int left = mLeft;
5860 final int top = mTop;
5861
Chet Haase05e91ed2012-07-03 14:17:57 -07005862 if ((mGroupFlags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN) {
5863 if (!dirty.intersect(0, 0, mRight - left, mBottom - top)) {
5864 dirty.setEmpty();
Romain Guy3a3133d2011-02-01 22:59:58 -08005865 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005866 }
Chet Haase05e91ed2012-07-03 14:17:57 -07005867
5868 location[CHILD_LEFT_INDEX] = left;
5869 location[CHILD_TOP_INDEX] = top;
Selim Cinek1cb8b082016-12-21 15:34:30 +00005870 } else {
Selim Cinek1cb8b082016-12-21 15:34:30 +00005871
Chet Haasea3db8662011-07-19 10:36:05 -07005872 if ((mGroupFlags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN) {
5873 dirty.set(0, 0, mRight - mLeft, mBottom - mTop);
5874 } else {
5875 // in case the dirty rect extends outside the bounds of this container
5876 dirty.union(0, 0, mRight - mLeft, mBottom - mTop);
5877 }
Chris Craik3f06c6d2017-01-09 18:19:48 +00005878 location[CHILD_LEFT_INDEX] = mLeft;
5879 location[CHILD_TOP_INDEX] = mTop;
Romain Guy3a3133d2011-02-01 22:59:58 -08005880
Chris Craik3f06c6d2017-01-09 18:19:48 +00005881 mPrivateFlags &= ~PFLAG_DRAWN;
Selim Cinek1cb8b082016-12-21 15:34:30 +00005882 }
Chris Craik3f06c6d2017-01-09 18:19:48 +00005883 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
5884 if (mLayerType != LAYER_TYPE_NONE) {
5885 mPrivateFlags |= PFLAG_INVALIDATED;
5886 }
5887
5888 return mParent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005889 }
5890
5891 return null;
5892 }
5893
5894 /**
5895 * Offset a rectangle that is in a descendant's coordinate
5896 * space into our coordinate space.
5897 * @param descendant A descendant of this view
5898 * @param rect A rectangle defined in descendant's coordinate space.
5899 */
5900 public final void offsetDescendantRectToMyCoords(View descendant, Rect rect) {
5901 offsetRectBetweenParentAndChild(descendant, rect, true, false);
5902 }
5903
5904 /**
5905 * Offset a rectangle that is in our coordinate space into an ancestor's
5906 * coordinate space.
5907 * @param descendant A descendant of this view
5908 * @param rect A rectangle defined in descendant's coordinate space.
5909 */
5910 public final void offsetRectIntoDescendantCoords(View descendant, Rect rect) {
5911 offsetRectBetweenParentAndChild(descendant, rect, false, false);
5912 }
5913
5914 /**
5915 * Helper method that offsets a rect either from parent to descendant or
5916 * descendant to parent.
5917 */
5918 void offsetRectBetweenParentAndChild(View descendant, Rect rect,
5919 boolean offsetFromChildToParent, boolean clipToBounds) {
5920
5921 // already in the same coord system :)
5922 if (descendant == this) {
5923 return;
5924 }
5925
5926 ViewParent theParent = descendant.mParent;
5927
5928 // search and offset up to the parent
5929 while ((theParent != null)
5930 && (theParent instanceof View)
5931 && (theParent != this)) {
5932
5933 if (offsetFromChildToParent) {
Hyunyoung Song4eb1a4e2016-03-09 22:51:02 +00005934 rect.offset(descendant.mLeft - descendant.mScrollX,
5935 descendant.mTop - descendant.mScrollY);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005936 if (clipToBounds) {
5937 View p = (View) theParent;
Doris Liu9607fbe2015-05-28 17:17:28 -07005938 boolean intersected = rect.intersect(0, 0, p.mRight - p.mLeft,
5939 p.mBottom - p.mTop);
5940 if (!intersected) {
5941 rect.setEmpty();
5942 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005943 }
5944 } else {
5945 if (clipToBounds) {
5946 View p = (View) theParent;
Doris Liu9607fbe2015-05-28 17:17:28 -07005947 boolean intersected = rect.intersect(0, 0, p.mRight - p.mLeft,
5948 p.mBottom - p.mTop);
5949 if (!intersected) {
5950 rect.setEmpty();
5951 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005952 }
Hyunyoung Song4eb1a4e2016-03-09 22:51:02 +00005953 rect.offset(descendant.mScrollX - descendant.mLeft,
5954 descendant.mScrollY - descendant.mTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005955 }
5956
5957 descendant = (View) theParent;
5958 theParent = descendant.mParent;
5959 }
5960
5961 // now that we are up to this view, need to offset one more time
5962 // to get into our coordinate space
5963 if (theParent == this) {
5964 if (offsetFromChildToParent) {
Hyunyoung Song4eb1a4e2016-03-09 22:51:02 +00005965 rect.offset(descendant.mLeft - descendant.mScrollX,
5966 descendant.mTop - descendant.mScrollY);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005967 } else {
Hyunyoung Song4eb1a4e2016-03-09 22:51:02 +00005968 rect.offset(descendant.mScrollX - descendant.mLeft,
5969 descendant.mScrollY - descendant.mTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005970 }
5971 } else {
5972 throw new IllegalArgumentException("parameter must be a descendant of this view");
5973 }
5974 }
5975
5976 /**
5977 * Offset the vertical location of all children of this view by the specified number of pixels.
5978 *
5979 * @param offset the number of pixels to offset
5980 *
5981 * @hide
5982 */
5983 public void offsetChildrenTopAndBottom(int offset) {
5984 final int count = mChildrenCount;
5985 final View[] children = mChildren;
Romain Guy5549cb52013-05-06 18:42:08 -07005986 boolean invalidate = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005987
5988 for (int i = 0; i < count; i++) {
5989 final View v = children[i];
5990 v.mTop += offset;
5991 v.mBottom += offset;
Chris Craik64a12e12014-03-28 18:12:12 -07005992 if (v.mRenderNode != null) {
Romain Guy5549cb52013-05-06 18:42:08 -07005993 invalidate = true;
Chris Craik64a12e12014-03-28 18:12:12 -07005994 v.mRenderNode.offsetTopAndBottom(offset);
Chet Haasea1cff502012-02-21 13:43:44 -08005995 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005996 }
Romain Guy5549cb52013-05-06 18:42:08 -07005997
5998 if (invalidate) {
5999 invalidateViewProperty(false, false);
6000 }
Guang Zhu84e25092014-05-01 21:12:55 -07006001 notifySubtreeAccessibilityStateChangedIfNeeded();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006002 }
6003
Alan Viverettebe463f22016-01-21 10:50:10 -05006004 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006005 public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) {
Abodunrinwa Toki4e7a1202016-05-03 18:23:12 +01006006 return getChildVisibleRect(child, r, offset, false);
6007 }
6008
6009 /**
Abodunrinwa Tokicb664062016-05-13 19:26:03 +01006010 * @param forceParentCheck true to guarantee that this call will propagate to all ancestors,
6011 * false otherwise
6012 *
Abodunrinwa Toki4e7a1202016-05-03 18:23:12 +01006013 * @hide
6014 */
6015 public boolean getChildVisibleRect(
6016 View child, Rect r, android.graphics.Point offset, boolean forceParentCheck) {
Adam Powellf93bb6d2011-12-12 15:21:57 -08006017 // It doesn't make a whole lot of sense to call this on a view that isn't attached,
6018 // but for some simple tests it can be useful. If we don't have attach info this
6019 // will allocate memory.
6020 final RectF rect = mAttachInfo != null ? mAttachInfo.mTmpTransformRect : new RectF();
Gilles Debunnecea45132011-11-24 02:19:27 +01006021 rect.set(r);
6022
6023 if (!child.hasIdentityMatrix()) {
George Mount002d43d2014-11-11 12:54:43 -08006024 child.getMatrix().mapRect(rect);
Gilles Debunnecea45132011-11-24 02:19:27 +01006025 }
6026
Alan Viveretteab2cf6d2014-11-26 14:34:36 -08006027 final int dx = child.mLeft - mScrollX;
6028 final int dy = child.mTop - mScrollY;
Gilles Debunnecea45132011-11-24 02:19:27 +01006029
6030 rect.offset(dx, dy);
6031
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006032 if (offset != null) {
Gilles Debunnecea45132011-11-24 02:19:27 +01006033 if (!child.hasIdentityMatrix()) {
Adam Powellf93bb6d2011-12-12 15:21:57 -08006034 float[] position = mAttachInfo != null ? mAttachInfo.mTmpTransformLocation
6035 : new float[2];
Gilles Debunnecea45132011-11-24 02:19:27 +01006036 position[0] = offset.x;
6037 position[1] = offset.y;
6038 child.getMatrix().mapPoints(position);
Alan Viverettec45b1d42015-11-16 15:38:59 -05006039 offset.x = Math.round(position[0]);
6040 offset.y = Math.round(position[1]);
Gilles Debunnecea45132011-11-24 02:19:27 +01006041 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006042 offset.x += dx;
6043 offset.y += dy;
6044 }
Gilles Debunnecea45132011-11-24 02:19:27 +01006045
Alan Viveretteab2cf6d2014-11-26 14:34:36 -08006046 final int width = mRight - mLeft;
6047 final int height = mBottom - mTop;
6048
George Mount002d43d2014-11-11 12:54:43 -08006049 boolean rectIsVisible = true;
Adam Powell35da41e2014-12-10 18:59:34 -08006050 if (mParent == null ||
6051 (mParent instanceof ViewGroup && ((ViewGroup) mParent).getClipChildren())) {
Alan Viveretteab2cf6d2014-11-26 14:34:36 -08006052 // Clip to bounds.
6053 rectIsVisible = rect.intersect(0, 0, width, height);
Gilles Debunnecea45132011-11-24 02:19:27 +01006054 }
6055
Abodunrinwa Toki4e7a1202016-05-03 18:23:12 +01006056 if ((forceParentCheck || rectIsVisible)
6057 && (mGroupFlags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK) {
Alan Viveretteab2cf6d2014-11-26 14:34:36 -08006058 // Clip to padding.
George Mount002d43d2014-11-11 12:54:43 -08006059 rectIsVisible = rect.intersect(mPaddingLeft, mPaddingTop,
Alan Viveretteab2cf6d2014-11-26 14:34:36 -08006060 width - mPaddingRight, height - mPaddingBottom);
George Mount002d43d2014-11-11 12:54:43 -08006061 }
6062
Abodunrinwa Toki4e7a1202016-05-03 18:23:12 +01006063 if ((forceParentCheck || rectIsVisible) && mClipBounds != null) {
Alan Viveretteab2cf6d2014-11-26 14:34:36 -08006064 // Clip to clipBounds.
George Mount002d43d2014-11-11 12:54:43 -08006065 rectIsVisible = rect.intersect(mClipBounds.left, mClipBounds.top, mClipBounds.right,
6066 mClipBounds.bottom);
6067 }
Alan Viverettec45b1d42015-11-16 15:38:59 -05006068 r.set((int) Math.floor(rect.left), (int) Math.floor(rect.top),
6069 (int) Math.ceil(rect.right), (int) Math.ceil(rect.bottom));
Abodunrinwa Toki4e7a1202016-05-03 18:23:12 +01006070
6071 if ((forceParentCheck || rectIsVisible) && mParent != null) {
Abodunrinwa Tokicb664062016-05-13 19:26:03 +01006072 if (mParent instanceof ViewGroup) {
6073 rectIsVisible = ((ViewGroup) mParent)
6074 .getChildVisibleRect(this, r, offset, forceParentCheck);
6075 } else {
6076 rectIsVisible = mParent.getChildVisibleRect(this, r, offset);
6077 }
George Mount002d43d2014-11-11 12:54:43 -08006078 }
6079 return rectIsVisible;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006080 }
6081
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006082 @Override
Chet Haase9c087442011-01-12 16:20:16 -08006083 public final void layout(int l, int t, int r, int b) {
Chet Haase430742f2013-04-12 11:18:36 -07006084 if (!mSuppressLayout && (mTransition == null || !mTransition.isChangingLayout())) {
Chet Haase7dd4a532012-04-16 13:35:09 -07006085 if (mTransition != null) {
6086 mTransition.layoutChange(this);
6087 }
Chet Haase9c087442011-01-12 16:20:16 -08006088 super.layout(l, t, r, b);
6089 } else {
6090 // record the fact that we noop'd it; request layout when transition finishes
Chet Haaseb9895022013-04-02 15:10:58 -07006091 mLayoutCalledWhileSuppressed = true;
Chet Haase9c087442011-01-12 16:20:16 -08006092 }
6093 }
6094
Chet Haase9c087442011-01-12 16:20:16 -08006095 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006096 protected abstract void onLayout(boolean changed,
6097 int l, int t, int r, int b);
6098
6099 /**
6100 * Indicates whether the view group has the ability to animate its children
6101 * after the first layout.
6102 *
6103 * @return true if the children can be animated, false otherwise
6104 */
6105 protected boolean canAnimate() {
6106 return mLayoutAnimationController != null;
6107 }
6108
6109 /**
6110 * Runs the layout animation. Calling this method triggers a relayout of
6111 * this view group.
6112 */
6113 public void startLayoutAnimation() {
6114 if (mLayoutAnimationController != null) {
6115 mGroupFlags |= FLAG_RUN_ANIMATION;
6116 requestLayout();
6117 }
6118 }
6119
6120 /**
6121 * Schedules the layout animation to be played after the next layout pass
6122 * of this view group. This can be used to restart the layout animation
6123 * when the content of the view group changes or when the activity is
6124 * paused and resumed.
6125 */
6126 public void scheduleLayoutAnimation() {
6127 mGroupFlags |= FLAG_RUN_ANIMATION;
6128 }
6129
6130 /**
6131 * Sets the layout animation controller used to animate the group's
6132 * children after the first layout.
6133 *
6134 * @param controller the animation controller
6135 */
6136 public void setLayoutAnimation(LayoutAnimationController controller) {
6137 mLayoutAnimationController = controller;
6138 if (mLayoutAnimationController != null) {
6139 mGroupFlags |= FLAG_RUN_ANIMATION;
6140 }
6141 }
6142
6143 /**
6144 * Returns the layout animation controller used to animate the group's
6145 * children.
6146 *
6147 * @return the current animation controller
6148 */
6149 public LayoutAnimationController getLayoutAnimation() {
6150 return mLayoutAnimationController;
6151 }
6152
6153 /**
6154 * Indicates whether the children's drawing cache is used during a layout
6155 * animation. By default, the drawing cache is enabled but this will prevent
6156 * nested layout animations from working. To nest animations, you must disable
6157 * the cache.
6158 *
6159 * @return true if the animation cache is enabled, false otherwise
6160 *
6161 * @see #setAnimationCacheEnabled(boolean)
6162 * @see View#setDrawingCacheEnabled(boolean)
Chris Craik5a6bbae2015-04-10 17:41:34 -07006163 *
Dianne Hackborn0e3de6c2015-07-29 15:20:21 -07006164 * @deprecated As of {@link android.os.Build.VERSION_CODES#M}, this property is ignored.
Chris Craik5a6bbae2015-04-10 17:41:34 -07006165 * Caching behavior of children may be controlled through {@link View#setLayerType(int, Paint)}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006166 */
Aurimas Liutikas514c5ef2016-05-24 15:22:55 -07006167 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006168 public boolean isAnimationCacheEnabled() {
6169 return (mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE;
6170 }
6171
6172 /**
6173 * Enables or disables the children's drawing cache during a layout animation.
6174 * By default, the drawing cache is enabled but this will prevent nested
6175 * layout animations from working. To nest animations, you must disable the
6176 * cache.
6177 *
6178 * @param enabled true to enable the animation cache, false otherwise
6179 *
6180 * @see #isAnimationCacheEnabled()
6181 * @see View#setDrawingCacheEnabled(boolean)
Chris Craik5a6bbae2015-04-10 17:41:34 -07006182 *
Dianne Hackborn0e3de6c2015-07-29 15:20:21 -07006183 * @deprecated As of {@link android.os.Build.VERSION_CODES#M}, this property is ignored.
Chris Craik5a6bbae2015-04-10 17:41:34 -07006184 * Caching behavior of children may be controlled through {@link View#setLayerType(int, Paint)}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006185 */
Aurimas Liutikas514c5ef2016-05-24 15:22:55 -07006186 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006187 public void setAnimationCacheEnabled(boolean enabled) {
6188 setBooleanFlag(FLAG_ANIMATION_CACHE, enabled);
6189 }
6190
6191 /**
6192 * Indicates whether this ViewGroup will always try to draw its children using their
6193 * drawing cache. By default this property is enabled.
6194 *
6195 * @return true if the animation cache is enabled, false otherwise
6196 *
6197 * @see #setAlwaysDrawnWithCacheEnabled(boolean)
6198 * @see #setChildrenDrawnWithCacheEnabled(boolean)
6199 * @see View#setDrawingCacheEnabled(boolean)
Chris Craik5a6bbae2015-04-10 17:41:34 -07006200 *
Dianne Hackborn0e3de6c2015-07-29 15:20:21 -07006201 * @deprecated As of {@link android.os.Build.VERSION_CODES#M}, this property is ignored.
Chris Craik5a6bbae2015-04-10 17:41:34 -07006202 * Child views may no longer have their caching behavior disabled by parents.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006203 */
Aurimas Liutikas514c5ef2016-05-24 15:22:55 -07006204 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006205 public boolean isAlwaysDrawnWithCacheEnabled() {
6206 return (mGroupFlags & FLAG_ALWAYS_DRAWN_WITH_CACHE) == FLAG_ALWAYS_DRAWN_WITH_CACHE;
6207 }
6208
6209 /**
6210 * Indicates whether this ViewGroup will always try to draw its children using their
6211 * drawing cache. This property can be set to true when the cache rendering is
6212 * slightly different from the children's normal rendering. Renderings can be different,
6213 * for instance, when the cache's quality is set to low.
6214 *
6215 * When this property is disabled, the ViewGroup will use the drawing cache of its
6216 * children only when asked to. It's usually the task of subclasses to tell ViewGroup
6217 * when to start using the drawing cache and when to stop using it.
6218 *
6219 * @param always true to always draw with the drawing cache, false otherwise
6220 *
6221 * @see #isAlwaysDrawnWithCacheEnabled()
6222 * @see #setChildrenDrawnWithCacheEnabled(boolean)
6223 * @see View#setDrawingCacheEnabled(boolean)
6224 * @see View#setDrawingCacheQuality(int)
Chris Craik5a6bbae2015-04-10 17:41:34 -07006225 *
Dianne Hackborn0e3de6c2015-07-29 15:20:21 -07006226 * @deprecated As of {@link android.os.Build.VERSION_CODES#M}, this property is ignored.
Chris Craik5a6bbae2015-04-10 17:41:34 -07006227 * Child views may no longer have their caching behavior disabled by parents.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006228 */
Aurimas Liutikas514c5ef2016-05-24 15:22:55 -07006229 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006230 public void setAlwaysDrawnWithCacheEnabled(boolean always) {
6231 setBooleanFlag(FLAG_ALWAYS_DRAWN_WITH_CACHE, always);
6232 }
6233
6234 /**
6235 * Indicates whether the ViewGroup is currently drawing its children using
6236 * their drawing cache.
6237 *
6238 * @return true if children should be drawn with their cache, false otherwise
6239 *
6240 * @see #setAlwaysDrawnWithCacheEnabled(boolean)
6241 * @see #setChildrenDrawnWithCacheEnabled(boolean)
Chris Craik5a6bbae2015-04-10 17:41:34 -07006242 *
Dianne Hackborn0e3de6c2015-07-29 15:20:21 -07006243 * @deprecated As of {@link android.os.Build.VERSION_CODES#M}, this property is ignored.
Chris Craik5a6bbae2015-04-10 17:41:34 -07006244 * Child views may no longer be forced to cache their rendering state by their parents.
6245 * Use {@link View#setLayerType(int, Paint)} on individual Views instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006246 */
Aurimas Liutikas514c5ef2016-05-24 15:22:55 -07006247 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006248 protected boolean isChildrenDrawnWithCacheEnabled() {
6249 return (mGroupFlags & FLAG_CHILDREN_DRAWN_WITH_CACHE) == FLAG_CHILDREN_DRAWN_WITH_CACHE;
6250 }
6251
6252 /**
6253 * Tells the ViewGroup to draw its children using their drawing cache. This property
6254 * is ignored when {@link #isAlwaysDrawnWithCacheEnabled()} is true. A child's drawing cache
6255 * will be used only if it has been enabled.
6256 *
6257 * Subclasses should call this method to start and stop using the drawing cache when
6258 * they perform performance sensitive operations, like scrolling or animating.
6259 *
6260 * @param enabled true if children should be drawn with their cache, false otherwise
6261 *
6262 * @see #setAlwaysDrawnWithCacheEnabled(boolean)
6263 * @see #isChildrenDrawnWithCacheEnabled()
Chris Craik5a6bbae2015-04-10 17:41:34 -07006264 *
Dianne Hackborn0e3de6c2015-07-29 15:20:21 -07006265 * @deprecated As of {@link android.os.Build.VERSION_CODES#M}, this property is ignored.
Chris Craik5a6bbae2015-04-10 17:41:34 -07006266 * Child views may no longer be forced to cache their rendering state by their parents.
6267 * Use {@link View#setLayerType(int, Paint)} on individual Views instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006268 */
Aurimas Liutikas514c5ef2016-05-24 15:22:55 -07006269 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006270 protected void setChildrenDrawnWithCacheEnabled(boolean enabled) {
6271 setBooleanFlag(FLAG_CHILDREN_DRAWN_WITH_CACHE, enabled);
6272 }
6273
Romain Guy293451e2009-11-04 13:59:48 -08006274 /**
6275 * Indicates whether the ViewGroup is drawing its children in the order defined by
6276 * {@link #getChildDrawingOrder(int, int)}.
6277 *
6278 * @return true if children drawing order is defined by {@link #getChildDrawingOrder(int, int)},
6279 * false otherwise
6280 *
6281 * @see #setChildrenDrawingOrderEnabled(boolean)
6282 * @see #getChildDrawingOrder(int, int)
6283 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07006284 @ViewDebug.ExportedProperty(category = "drawing")
Romain Guy293451e2009-11-04 13:59:48 -08006285 protected boolean isChildrenDrawingOrderEnabled() {
6286 return (mGroupFlags & FLAG_USE_CHILD_DRAWING_ORDER) == FLAG_USE_CHILD_DRAWING_ORDER;
6287 }
6288
6289 /**
6290 * Tells the ViewGroup whether to draw its children in the order defined by the method
6291 * {@link #getChildDrawingOrder(int, int)}.
Chris Craike83cbd42014-09-03 17:52:24 -07006292 * <p>
6293 * Note that {@link View#getZ() Z} reordering, done by {@link #dispatchDraw(Canvas)},
6294 * will override custom child ordering done via this method.
Romain Guy293451e2009-11-04 13:59:48 -08006295 *
6296 * @param enabled true if the order of the children when drawing is determined by
6297 * {@link #getChildDrawingOrder(int, int)}, false otherwise
6298 *
6299 * @see #isChildrenDrawingOrderEnabled()
6300 * @see #getChildDrawingOrder(int, int)
6301 */
6302 protected void setChildrenDrawingOrderEnabled(boolean enabled) {
6303 setBooleanFlag(FLAG_USE_CHILD_DRAWING_ORDER, enabled);
6304 }
6305
Svetoslav6254f482013-06-04 17:22:14 -07006306 private boolean hasBooleanFlag(int flag) {
Philip Milnef091b662013-02-27 11:15:21 -08006307 return (mGroupFlags & flag) == flag;
6308 }
6309
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006310 private void setBooleanFlag(int flag, boolean value) {
6311 if (value) {
6312 mGroupFlags |= flag;
6313 } else {
6314 mGroupFlags &= ~flag;
6315 }
6316 }
6317
6318 /**
6319 * Returns an integer indicating what types of drawing caches are kept in memory.
6320 *
6321 * @see #setPersistentDrawingCache(int)
6322 * @see #setAnimationCacheEnabled(boolean)
6323 *
6324 * @return one or a combination of {@link #PERSISTENT_NO_CACHE},
6325 * {@link #PERSISTENT_ANIMATION_CACHE}, {@link #PERSISTENT_SCROLLING_CACHE}
6326 * and {@link #PERSISTENT_ALL_CACHES}
6327 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07006328 @ViewDebug.ExportedProperty(category = "drawing", mapping = {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006329 @ViewDebug.IntToString(from = PERSISTENT_NO_CACHE, to = "NONE"),
Romain Guy203688c2010-05-12 15:41:32 -07006330 @ViewDebug.IntToString(from = PERSISTENT_ANIMATION_CACHE, to = "ANIMATION"),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006331 @ViewDebug.IntToString(from = PERSISTENT_SCROLLING_CACHE, to = "SCROLLING"),
6332 @ViewDebug.IntToString(from = PERSISTENT_ALL_CACHES, to = "ALL")
6333 })
6334 public int getPersistentDrawingCache() {
6335 return mPersistentDrawingCache;
6336 }
6337
6338 /**
6339 * Indicates what types of drawing caches should be kept in memory after
6340 * they have been created.
6341 *
6342 * @see #getPersistentDrawingCache()
6343 * @see #setAnimationCacheEnabled(boolean)
6344 *
6345 * @param drawingCacheToKeep one or a combination of {@link #PERSISTENT_NO_CACHE},
6346 * {@link #PERSISTENT_ANIMATION_CACHE}, {@link #PERSISTENT_SCROLLING_CACHE}
6347 * and {@link #PERSISTENT_ALL_CACHES}
6348 */
6349 public void setPersistentDrawingCache(int drawingCacheToKeep) {
6350 mPersistentDrawingCache = drawingCacheToKeep & PERSISTENT_ALL_CACHES;
6351 }
6352
Philip Milnef091b662013-02-27 11:15:21 -08006353 private void setLayoutMode(int layoutMode, boolean explicitly) {
6354 mLayoutMode = layoutMode;
6355 setBooleanFlag(FLAG_LAYOUT_MODE_WAS_EXPLICITLY_SET, explicitly);
6356 }
6357
6358 /**
6359 * Recursively traverse the view hierarchy, resetting the layoutMode of any
6360 * descendants that had inherited a different layoutMode from a previous parent.
6361 * Recursion terminates when a descendant's mode is:
6362 * <ul>
6363 * <li>Undefined</li>
6364 * <li>The same as the root node's</li>
6365 * <li>A mode that had been explicitly set</li>
6366 * <ul/>
6367 * The first two clauses are optimizations.
6368 * @param layoutModeOfRoot
6369 */
6370 @Override
6371 void invalidateInheritedLayoutMode(int layoutModeOfRoot) {
6372 if (mLayoutMode == LAYOUT_MODE_UNDEFINED ||
6373 mLayoutMode == layoutModeOfRoot ||
Svetoslav6254f482013-06-04 17:22:14 -07006374 hasBooleanFlag(FLAG_LAYOUT_MODE_WAS_EXPLICITLY_SET)) {
Philip Milnef091b662013-02-27 11:15:21 -08006375 return;
6376 }
6377 setLayoutMode(LAYOUT_MODE_UNDEFINED, false);
6378
6379 // apply recursively
6380 for (int i = 0, N = getChildCount(); i < N; i++) {
6381 getChildAt(i).invalidateInheritedLayoutMode(layoutModeOfRoot);
6382 }
6383 }
6384
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006385 /**
Philip Milnecfb631b2012-10-26 10:51:46 -07006386 * Returns the basis of alignment during layout operations on this ViewGroup:
Philip Milne7b757812012-09-19 18:13:44 -07006387 * either {@link #LAYOUT_MODE_CLIP_BOUNDS} or {@link #LAYOUT_MODE_OPTICAL_BOUNDS}.
Philip Milnecfb631b2012-10-26 10:51:46 -07006388 * <p>
6389 * If no layoutMode was explicitly set, either programmatically or in an XML resource,
6390 * the method returns the layoutMode of the view's parent ViewGroup if such a parent exists,
6391 * otherwise the method returns a default value of {@link #LAYOUT_MODE_CLIP_BOUNDS}.
Philip Milne1557fd72012-04-04 23:41:34 -07006392 *
Philip Milnefcc6a0f2012-04-16 16:12:19 -07006393 * @return the layout mode to use during layout operations
Philip Milne1557fd72012-04-04 23:41:34 -07006394 *
6395 * @see #setLayoutMode(int)
6396 */
6397 public int getLayoutMode() {
Philip Milnecfb631b2012-10-26 10:51:46 -07006398 if (mLayoutMode == LAYOUT_MODE_UNDEFINED) {
Philip Milnef091b662013-02-27 11:15:21 -08006399 int inheritedLayoutMode = (mParent instanceof ViewGroup) ?
6400 ((ViewGroup) mParent).getLayoutMode() : LAYOUT_MODE_DEFAULT;
6401 setLayoutMode(inheritedLayoutMode, false);
Philip Milnecfb631b2012-10-26 10:51:46 -07006402 }
Philip Milne1557fd72012-04-04 23:41:34 -07006403 return mLayoutMode;
6404 }
6405
6406 /**
Philip Milnecfb631b2012-10-26 10:51:46 -07006407 * Sets the basis of alignment during the layout of this ViewGroup.
Philip Milne7b757812012-09-19 18:13:44 -07006408 * Valid values are either {@link #LAYOUT_MODE_CLIP_BOUNDS} or
6409 * {@link #LAYOUT_MODE_OPTICAL_BOUNDS}.
Philip Milne1557fd72012-04-04 23:41:34 -07006410 *
Philip Milnefcc6a0f2012-04-16 16:12:19 -07006411 * @param layoutMode the layout mode to use during layout operations
Philip Milne1557fd72012-04-04 23:41:34 -07006412 *
6413 * @see #getLayoutMode()
Scott Main27a85082013-06-10 10:39:48 -07006414 * @attr ref android.R.styleable#ViewGroup_layoutMode
Philip Milne1557fd72012-04-04 23:41:34 -07006415 */
6416 public void setLayoutMode(int layoutMode) {
6417 if (mLayoutMode != layoutMode) {
Philip Milnef091b662013-02-27 11:15:21 -08006418 invalidateInheritedLayoutMode(layoutMode);
6419 setLayoutMode(layoutMode, layoutMode != LAYOUT_MODE_UNDEFINED);
Philip Milne1557fd72012-04-04 23:41:34 -07006420 requestLayout();
6421 }
6422 }
6423
6424 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006425 * Returns a new set of layout parameters based on the supplied attributes set.
6426 *
6427 * @param attrs the attributes to build the layout parameters from
6428 *
6429 * @return an instance of {@link android.view.ViewGroup.LayoutParams} or one
6430 * of its descendants
6431 */
6432 public LayoutParams generateLayoutParams(AttributeSet attrs) {
6433 return new LayoutParams(getContext(), attrs);
6434 }
6435
6436 /**
6437 * Returns a safe set of layout parameters based on the supplied layout params.
6438 * When a ViewGroup is passed a View whose layout params do not pass the test of
6439 * {@link #checkLayoutParams(android.view.ViewGroup.LayoutParams)}, this method
6440 * is invoked. This method should return a new set of layout params suitable for
6441 * this ViewGroup, possibly by copying the appropriate attributes from the
6442 * specified set of layout params.
6443 *
6444 * @param p The layout parameters to convert into a suitable set of layout parameters
6445 * for this ViewGroup.
6446 *
6447 * @return an instance of {@link android.view.ViewGroup.LayoutParams} or one
6448 * of its descendants
6449 */
6450 protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
Chet Haase4610eef2015-12-03 07:38:11 -08006451 return p;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006452 }
6453
6454 /**
6455 * Returns a set of default layout parameters. These parameters are requested
6456 * when the View passed to {@link #addView(View)} has no layout parameters
6457 * already set. If null is returned, an exception is thrown from addView.
6458 *
6459 * @return a set of default layout parameters or null
6460 */
6461 protected LayoutParams generateDefaultLayoutParams() {
6462 return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
6463 }
6464
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006465 @Override
6466 protected void debug(int depth) {
6467 super.debug(depth);
6468 String output;
6469
6470 if (mFocused != null) {
6471 output = debugIndent(depth);
6472 output += "mFocused";
6473 Log.d(VIEW_LOG_TAG, output);
Vadim Tryshev01d8c492016-12-15 11:33:15 -08006474 mFocused.debug(depth + 1);
6475 }
Vadim Tryshev5ca73982017-01-04 17:24:43 -08006476 if (mDefaultFocus != null) {
Vadim Tryshev01d8c492016-12-15 11:33:15 -08006477 output = debugIndent(depth);
Vadim Tryshev5ca73982017-01-04 17:24:43 -08006478 output += "mDefaultFocus";
Vadim Tryshev01d8c492016-12-15 11:33:15 -08006479 Log.d(VIEW_LOG_TAG, output);
Vadim Tryshev5ca73982017-01-04 17:24:43 -08006480 mDefaultFocus.debug(depth + 1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006481 }
Evan Rosky53fcf112017-01-26 14:37:55 -08006482 if (mFocusedInCluster != null) {
6483 output = debugIndent(depth);
6484 output += "mFocusedInCluster";
6485 Log.d(VIEW_LOG_TAG, output);
6486 mFocusedInCluster.debug(depth + 1);
6487 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006488 if (mChildrenCount != 0) {
6489 output = debugIndent(depth);
6490 output += "{";
6491 Log.d(VIEW_LOG_TAG, output);
6492 }
6493 int count = mChildrenCount;
6494 for (int i = 0; i < count; i++) {
6495 View child = mChildren[i];
6496 child.debug(depth + 1);
6497 }
6498
6499 if (mChildrenCount != 0) {
6500 output = debugIndent(depth);
6501 output += "}";
6502 Log.d(VIEW_LOG_TAG, output);
6503 }
6504 }
6505
6506 /**
6507 * Returns the position in the group of the specified child view.
6508 *
6509 * @param child the view for which to get the position
6510 * @return a positive integer representing the position of the view in the
6511 * group, or -1 if the view does not exist in the group
6512 */
6513 public int indexOfChild(View child) {
6514 final int count = mChildrenCount;
6515 final View[] children = mChildren;
6516 for (int i = 0; i < count; i++) {
6517 if (children[i] == child) {
6518 return i;
6519 }
6520 }
6521 return -1;
6522 }
6523
6524 /**
6525 * Returns the number of children in the group.
6526 *
6527 * @return a positive integer representing the number of children in
6528 * the group
6529 */
6530 public int getChildCount() {
6531 return mChildrenCount;
6532 }
6533
6534 /**
6535 * Returns the view at the specified position in the group.
6536 *
6537 * @param index the position at which to get the view from
6538 * @return the view at the specified position or null if the position
6539 * does not exist within the group
6540 */
6541 public View getChildAt(int index) {
Adam Powell3ba8f5d62011-03-07 15:36:33 -08006542 if (index < 0 || index >= mChildrenCount) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006543 return null;
6544 }
Adam Powell3ba8f5d62011-03-07 15:36:33 -08006545 return mChildren[index];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006546 }
6547
6548 /**
6549 * Ask all of the children of this view to measure themselves, taking into
6550 * account both the MeasureSpec requirements for this view and its padding.
6551 * We skip children that are in the GONE state The heavy lifting is done in
6552 * getChildMeasureSpec.
6553 *
6554 * @param widthMeasureSpec The width requirements for this view
6555 * @param heightMeasureSpec The height requirements for this view
6556 */
6557 protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec) {
6558 final int size = mChildrenCount;
6559 final View[] children = mChildren;
6560 for (int i = 0; i < size; ++i) {
6561 final View child = children[i];
6562 if ((child.mViewFlags & VISIBILITY_MASK) != GONE) {
6563 measureChild(child, widthMeasureSpec, heightMeasureSpec);
6564 }
6565 }
6566 }
6567
6568 /**
6569 * Ask one of the children of this view to measure itself, taking into
6570 * account both the MeasureSpec requirements for this view and its padding.
6571 * The heavy lifting is done in getChildMeasureSpec.
6572 *
6573 * @param child The child to measure
6574 * @param parentWidthMeasureSpec The width requirements for this view
6575 * @param parentHeightMeasureSpec The height requirements for this view
6576 */
6577 protected void measureChild(View child, int parentWidthMeasureSpec,
6578 int parentHeightMeasureSpec) {
6579 final LayoutParams lp = child.getLayoutParams();
6580
6581 final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
6582 mPaddingLeft + mPaddingRight, lp.width);
6583 final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
6584 mPaddingTop + mPaddingBottom, lp.height);
6585
6586 child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
6587 }
6588
6589 /**
6590 * Ask one of the children of this view to measure itself, taking into
6591 * account both the MeasureSpec requirements for this view and its padding
6592 * and margins. The child must have MarginLayoutParams The heavy lifting is
6593 * done in getChildMeasureSpec.
6594 *
6595 * @param child The child to measure
6596 * @param parentWidthMeasureSpec The width requirements for this view
6597 * @param widthUsed Extra space that has been used up by the parent
6598 * horizontally (possibly by other children of the parent)
6599 * @param parentHeightMeasureSpec The height requirements for this view
6600 * @param heightUsed Extra space that has been used up by the parent
6601 * vertically (possibly by other children of the parent)
6602 */
6603 protected void measureChildWithMargins(View child,
6604 int parentWidthMeasureSpec, int widthUsed,
6605 int parentHeightMeasureSpec, int heightUsed) {
6606 final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
6607
6608 final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
6609 mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin
6610 + widthUsed, lp.width);
6611 final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
6612 mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin
6613 + heightUsed, lp.height);
6614
6615 child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
6616 }
6617
6618 /**
6619 * Does the hard part of measureChildren: figuring out the MeasureSpec to
6620 * pass to a particular child. This method figures out the right MeasureSpec
6621 * for one dimension (height or width) of one child view.
6622 *
6623 * The goal is to combine information from our MeasureSpec with the
6624 * LayoutParams of the child to get the best possible results. For example,
6625 * if the this view knows its size (because its MeasureSpec has a mode of
6626 * EXACTLY), and the child has indicated in its LayoutParams that it wants
6627 * to be the same size as the parent, the parent should ask the child to
6628 * layout given an exact size.
6629 *
6630 * @param spec The requirements for this view
6631 * @param padding The padding of this view for the current dimension and
6632 * margins, if applicable
6633 * @param childDimension How big the child wants to be in the current
6634 * dimension
6635 * @return a MeasureSpec integer for the child
6636 */
6637 public static int getChildMeasureSpec(int spec, int padding, int childDimension) {
6638 int specMode = MeasureSpec.getMode(spec);
6639 int specSize = MeasureSpec.getSize(spec);
6640
6641 int size = Math.max(0, specSize - padding);
6642
6643 int resultSize = 0;
6644 int resultMode = 0;
6645
6646 switch (specMode) {
6647 // Parent has imposed an exact size on us
6648 case MeasureSpec.EXACTLY:
6649 if (childDimension >= 0) {
6650 resultSize = childDimension;
6651 resultMode = MeasureSpec.EXACTLY;
Romain Guy980a9382010-01-08 15:06:28 -08006652 } else if (childDimension == LayoutParams.MATCH_PARENT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006653 // Child wants to be our size. So be it.
6654 resultSize = size;
6655 resultMode = MeasureSpec.EXACTLY;
6656 } else if (childDimension == LayoutParams.WRAP_CONTENT) {
6657 // Child wants to determine its own size. It can't be
6658 // bigger than us.
6659 resultSize = size;
6660 resultMode = MeasureSpec.AT_MOST;
6661 }
6662 break;
6663
6664 // Parent has imposed a maximum size on us
6665 case MeasureSpec.AT_MOST:
6666 if (childDimension >= 0) {
6667 // Child wants a specific size... so be it
6668 resultSize = childDimension;
6669 resultMode = MeasureSpec.EXACTLY;
Romain Guy980a9382010-01-08 15:06:28 -08006670 } else if (childDimension == LayoutParams.MATCH_PARENT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006671 // Child wants to be our size, but our size is not fixed.
6672 // Constrain child to not be bigger than us.
6673 resultSize = size;
6674 resultMode = MeasureSpec.AT_MOST;
6675 } else if (childDimension == LayoutParams.WRAP_CONTENT) {
6676 // Child wants to determine its own size. It can't be
6677 // bigger than us.
6678 resultSize = size;
6679 resultMode = MeasureSpec.AT_MOST;
6680 }
6681 break;
6682
6683 // Parent asked to see how big we want to be
6684 case MeasureSpec.UNSPECIFIED:
6685 if (childDimension >= 0) {
6686 // Child wants a specific size... let him have it
6687 resultSize = childDimension;
6688 resultMode = MeasureSpec.EXACTLY;
Romain Guy980a9382010-01-08 15:06:28 -08006689 } else if (childDimension == LayoutParams.MATCH_PARENT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006690 // Child wants to be our size... find out how big it should
6691 // be
Adam Powelld5dbf4b2015-06-11 13:19:24 -07006692 resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006693 resultMode = MeasureSpec.UNSPECIFIED;
6694 } else if (childDimension == LayoutParams.WRAP_CONTENT) {
6695 // Child wants to determine its own size.... find out how
6696 // big it should be
Adam Powelld5dbf4b2015-06-11 13:19:24 -07006697 resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006698 resultMode = MeasureSpec.UNSPECIFIED;
6699 }
6700 break;
6701 }
Tor Norbye67568642015-03-31 07:47:23 -07006702 //noinspection ResourceType
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006703 return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
6704 }
6705
6706
6707 /**
6708 * Removes any pending animations for views that have been removed. Call
6709 * this if you don't want animations for exiting views to stack up.
6710 */
6711 public void clearDisappearingChildren() {
John Reckca7a9da2014-03-05 16:29:07 -08006712 final ArrayList<View> disappearingChildren = mDisappearingChildren;
6713 if (disappearingChildren != null) {
6714 final int count = disappearingChildren.size();
6715 for (int i = 0; i < count; i++) {
6716 final View view = disappearingChildren.get(i);
6717 if (view.mAttachInfo != null) {
6718 view.dispatchDetachedFromWindow();
6719 }
6720 view.clearAnimation();
6721 }
6722 disappearingChildren.clear();
Chet Haaseb85967b2012-03-26 14:37:51 -07006723 invalidate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006724 }
6725 }
6726
6727 /**
6728 * Add a view which is removed from mChildren but still needs animation
6729 *
6730 * @param v View to add
6731 */
6732 private void addDisappearingView(View v) {
6733 ArrayList<View> disappearingChildren = mDisappearingChildren;
6734
6735 if (disappearingChildren == null) {
6736 disappearingChildren = mDisappearingChildren = new ArrayList<View>();
6737 }
6738
6739 disappearingChildren.add(v);
6740 }
6741
6742 /**
6743 * Cleanup a view when its animation is done. This may mean removing it from
6744 * the list of disappearing views.
6745 *
6746 * @param view The view whose animation has finished
6747 * @param animation The animation, cannot be null
6748 */
Chet Haase64a48c12012-02-13 16:33:29 -08006749 void finishAnimatingView(final View view, Animation animation) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006750 final ArrayList<View> disappearingChildren = mDisappearingChildren;
6751 if (disappearingChildren != null) {
6752 if (disappearingChildren.contains(view)) {
6753 disappearingChildren.remove(view);
6754
6755 if (view.mAttachInfo != null) {
6756 view.dispatchDetachedFromWindow();
6757 }
6758
6759 view.clearAnimation();
6760 mGroupFlags |= FLAG_INVALIDATE_REQUIRED;
6761 }
6762 }
6763
6764 if (animation != null && !animation.getFillAfter()) {
6765 view.clearAnimation();
6766 }
6767
Dianne Hackborn4702a852012-08-17 15:18:29 -07006768 if ((view.mPrivateFlags & PFLAG_ANIMATION_STARTED) == PFLAG_ANIMATION_STARTED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006769 view.onAnimationEnd();
6770 // Should be performed by onAnimationEnd() but this avoid an infinite loop,
6771 // so we'd rather be safe than sorry
Dianne Hackborn4702a852012-08-17 15:18:29 -07006772 view.mPrivateFlags &= ~PFLAG_ANIMATION_STARTED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006773 // Draw one more frame after the animation is done
6774 mGroupFlags |= FLAG_INVALIDATE_REQUIRED;
6775 }
6776 }
6777
Chet Haaseb20db3e2010-09-10 13:07:30 -07006778 /**
Chet Haaseaceafe62011-08-26 15:44:33 -07006779 * Utility function called by View during invalidation to determine whether a view that
6780 * is invisible or gone should still be invalidated because it is being transitioned (and
6781 * therefore still needs to be drawn).
6782 */
6783 boolean isViewTransitioning(View view) {
6784 return (mTransitioningViews != null && mTransitioningViews.contains(view));
6785 }
6786
6787 /**
Chet Haaseb20db3e2010-09-10 13:07:30 -07006788 * This method tells the ViewGroup that the given View object, which should have this
6789 * ViewGroup as its parent,
6790 * should be kept around (re-displayed when the ViewGroup draws its children) even if it
6791 * is removed from its parent. This allows animations, such as those used by
6792 * {@link android.app.Fragment} and {@link android.animation.LayoutTransition} to animate
6793 * the removal of views. A call to this method should always be accompanied by a later call
6794 * to {@link #endViewTransition(View)}, such as after an animation on the View has finished,
6795 * so that the View finally gets removed.
6796 *
6797 * @param view The View object to be kept visible even if it gets removed from its parent.
6798 */
6799 public void startViewTransition(View view) {
6800 if (view.mParent == this) {
6801 if (mTransitioningViews == null) {
6802 mTransitioningViews = new ArrayList<View>();
6803 }
6804 mTransitioningViews.add(view);
6805 }
6806 }
6807
6808 /**
6809 * This method should always be called following an earlier call to
6810 * {@link #startViewTransition(View)}. The given View is finally removed from its parent
6811 * and will no longer be displayed. Note that this method does not perform the functionality
6812 * of removing a view from its parent; it just discontinues the display of a View that
6813 * has previously been removed.
6814 *
6815 * @return view The View object that has been removed but is being kept around in the visible
6816 * hierarchy by an earlier call to {@link #startViewTransition(View)}.
6817 */
6818 public void endViewTransition(View view) {
6819 if (mTransitioningViews != null) {
6820 mTransitioningViews.remove(view);
6821 final ArrayList<View> disappearingChildren = mDisappearingChildren;
6822 if (disappearingChildren != null && disappearingChildren.contains(view)) {
6823 disappearingChildren.remove(view);
Chet Haase5e25c2c2010-09-16 11:15:56 -07006824 if (mVisibilityChangingChildren != null &&
6825 mVisibilityChangingChildren.contains(view)) {
6826 mVisibilityChangingChildren.remove(view);
6827 } else {
6828 if (view.mAttachInfo != null) {
6829 view.dispatchDetachedFromWindow();
6830 }
6831 if (view.mParent != null) {
6832 view.mParent = null;
6833 }
Chet Haaseb20db3e2010-09-10 13:07:30 -07006834 }
Chet Haaseb85967b2012-03-26 14:37:51 -07006835 invalidate();
Chet Haaseb20db3e2010-09-10 13:07:30 -07006836 }
6837 }
6838 }
6839
Chet Haase21cd1382010-09-01 17:42:29 -07006840 private LayoutTransition.TransitionListener mLayoutTransitionListener =
6841 new LayoutTransition.TransitionListener() {
6842 @Override
6843 public void startTransition(LayoutTransition transition, ViewGroup container,
6844 View view, int transitionType) {
6845 // We only care about disappearing items, since we need special logic to keep
6846 // those items visible after they've been 'removed'
6847 if (transitionType == LayoutTransition.DISAPPEARING) {
Chet Haaseb20db3e2010-09-10 13:07:30 -07006848 startViewTransition(view);
Chet Haase21cd1382010-09-01 17:42:29 -07006849 }
6850 }
6851
6852 @Override
6853 public void endTransition(LayoutTransition transition, ViewGroup container,
6854 View view, int transitionType) {
Chet Haaseb9895022013-04-02 15:10:58 -07006855 if (mLayoutCalledWhileSuppressed && !transition.isChangingLayout()) {
Chet Haase9c087442011-01-12 16:20:16 -08006856 requestLayout();
Chet Haaseb9895022013-04-02 15:10:58 -07006857 mLayoutCalledWhileSuppressed = false;
Chet Haase9c087442011-01-12 16:20:16 -08006858 }
Chet Haase21cd1382010-09-01 17:42:29 -07006859 if (transitionType == LayoutTransition.DISAPPEARING && mTransitioningViews != null) {
Chet Haaseb20db3e2010-09-10 13:07:30 -07006860 endViewTransition(view);
Chet Haase21cd1382010-09-01 17:42:29 -07006861 }
6862 }
6863 };
6864
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006865 /**
Chet Haaseb9895022013-04-02 15:10:58 -07006866 * Tells this ViewGroup to suppress all layout() calls until layout
6867 * suppression is disabled with a later call to suppressLayout(false).
6868 * When layout suppression is disabled, a requestLayout() call is sent
6869 * if layout() was attempted while layout was being suppressed.
6870 *
6871 * @hide
6872 */
6873 public void suppressLayout(boolean suppress) {
6874 mSuppressLayout = suppress;
6875 if (!suppress) {
6876 if (mLayoutCalledWhileSuppressed) {
6877 requestLayout();
6878 mLayoutCalledWhileSuppressed = false;
6879 }
6880 }
6881 }
6882
6883 /**
Chet Haase199acdf2013-07-24 18:40:55 -07006884 * Returns whether layout calls on this container are currently being
6885 * suppressed, due to an earlier call to {@link #suppressLayout(boolean)}.
6886 *
6887 * @return true if layout calls are currently suppressed, false otherwise.
6888 *
6889 * @hide
6890 */
6891 public boolean isLayoutSuppressed() {
6892 return mSuppressLayout;
6893 }
6894
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006895 @Override
6896 public boolean gatherTransparentRegion(Region region) {
6897 // If no transparent regions requested, we are always opaque.
Dianne Hackborn4702a852012-08-17 15:18:29 -07006898 final boolean meOpaque = (mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) == 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006899 if (meOpaque && region == null) {
6900 // The caller doesn't care about the region, so stop now.
6901 return true;
6902 }
6903 super.gatherTransparentRegion(region);
Teng-Hui Zhuf8da30d2016-08-15 10:28:20 -07006904 // Instead of naively traversing the view tree, we have to traverse according to the Z
6905 // order here. We need to go with the same order as dispatchDraw().
6906 // One example is that after surfaceView punch a hole, we will still allow other views drawn
6907 // on top of that hole. In this case, those other views should be able to cut the
6908 // transparent region into smaller area.
6909 final int childrenCount = mChildrenCount;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006910 boolean noneOfTheChildrenAreTransparent = true;
Teng-Hui Zhuf8da30d2016-08-15 10:28:20 -07006911 if (childrenCount > 0) {
6912 final ArrayList<View> preorderedList = buildOrderedChildList();
6913 final boolean customOrder = preorderedList == null
6914 && isChildrenDrawingOrderEnabled();
6915 final View[] children = mChildren;
6916 for (int i = 0; i < childrenCount; i++) {
6917 final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
6918 final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);
6919 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
6920 if (!child.gatherTransparentRegion(region)) {
6921 noneOfTheChildrenAreTransparent = false;
6922 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006923 }
6924 }
Teng-Hui Zhuf8da30d2016-08-15 10:28:20 -07006925 if (preorderedList != null) preorderedList.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006926 }
6927 return meOpaque || noneOfTheChildrenAreTransparent;
6928 }
6929
Alan Viverettebe463f22016-01-21 10:50:10 -05006930 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006931 public void requestTransparentRegion(View child) {
6932 if (child != null) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07006933 child.mPrivateFlags |= View.PFLAG_REQUEST_TRANSPARENT_REGIONS;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006934 if (mParent != null) {
6935 mParent.requestTransparentRegion(this);
6936 }
6937 }
6938 }
Romain Guy8506ab42009-06-11 17:35:47 -07006939
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006940 @Override
Adam Powell46e38fd2014-02-03 10:16:49 -08006941 public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) {
6942 insets = super.dispatchApplyWindowInsets(insets);
Adam Powell0d9fdba2014-06-11 15:33:08 -07006943 if (!insets.isConsumed()) {
Adam Powell46e38fd2014-02-03 10:16:49 -08006944 final int count = getChildCount();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006945 for (int i = 0; i < count; i++) {
Adam Powell46e38fd2014-02-03 10:16:49 -08006946 insets = getChildAt(i).dispatchApplyWindowInsets(insets);
Adam Powell0d9fdba2014-06-11 15:33:08 -07006947 if (insets.isConsumed()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006948 break;
6949 }
6950 }
6951 }
Adam Powell46e38fd2014-02-03 10:16:49 -08006952 return insets;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006953 }
6954
6955 /**
6956 * Returns the animation listener to which layout animation events are
6957 * sent.
6958 *
6959 * @return an {@link android.view.animation.Animation.AnimationListener}
6960 */
6961 public Animation.AnimationListener getLayoutAnimationListener() {
6962 return mAnimationListener;
6963 }
6964
6965 @Override
6966 protected void drawableStateChanged() {
6967 super.drawableStateChanged();
6968
6969 if ((mGroupFlags & FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE) != 0) {
6970 if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0) {
6971 throw new IllegalStateException("addStateFromChildren cannot be enabled if a"
6972 + " child has duplicateParentState set to true");
6973 }
6974
6975 final View[] children = mChildren;
6976 final int count = mChildrenCount;
6977
6978 for (int i = 0; i < count; i++) {
6979 final View child = children[i];
6980 if ((child.mViewFlags & DUPLICATE_PARENT_STATE) != 0) {
6981 child.refreshDrawableState();
6982 }
6983 }
6984 }
6985 }
6986
6987 @Override
Dianne Hackborne2136772010-11-04 15:08:59 -07006988 public void jumpDrawablesToCurrentState() {
6989 super.jumpDrawablesToCurrentState();
6990 final View[] children = mChildren;
6991 final int count = mChildrenCount;
6992 for (int i = 0; i < count; i++) {
6993 children[i].jumpDrawablesToCurrentState();
6994 }
6995 }
6996
6997 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006998 protected int[] onCreateDrawableState(int extraSpace) {
6999 if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) == 0) {
7000 return super.onCreateDrawableState(extraSpace);
7001 }
7002
7003 int need = 0;
7004 int n = getChildCount();
7005 for (int i = 0; i < n; i++) {
7006 int[] childState = getChildAt(i).getDrawableState();
7007
7008 if (childState != null) {
7009 need += childState.length;
7010 }
7011 }
7012
7013 int[] state = super.onCreateDrawableState(extraSpace + need);
7014
7015 for (int i = 0; i < n; i++) {
7016 int[] childState = getChildAt(i).getDrawableState();
7017
7018 if (childState != null) {
7019 state = mergeDrawableStates(state, childState);
7020 }
7021 }
7022
7023 return state;
7024 }
7025
7026 /**
7027 * Sets whether this ViewGroup's drawable states also include
7028 * its children's drawable states. This is used, for example, to
7029 * make a group appear to be focused when its child EditText or button
7030 * is focused.
7031 */
7032 public void setAddStatesFromChildren(boolean addsStates) {
7033 if (addsStates) {
7034 mGroupFlags |= FLAG_ADD_STATES_FROM_CHILDREN;
7035 } else {
7036 mGroupFlags &= ~FLAG_ADD_STATES_FROM_CHILDREN;
7037 }
7038
7039 refreshDrawableState();
7040 }
7041
7042 /**
7043 * Returns whether this ViewGroup's drawable states also include
7044 * its children's drawable states. This is used, for example, to
7045 * make a group appear to be focused when its child EditText or button
7046 * is focused.
7047 */
7048 public boolean addStatesFromChildren() {
7049 return (mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0;
7050 }
7051
7052 /**
Jeff Smitha45746e2012-07-19 14:19:24 -05007053 * If {@link #addStatesFromChildren} is true, refreshes this group's
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007054 * drawable state (to include the states from its children).
7055 */
Alan Viverettebe463f22016-01-21 10:50:10 -05007056 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007057 public void childDrawableStateChanged(View child) {
7058 if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0) {
7059 refreshDrawableState();
7060 }
7061 }
7062
7063 /**
7064 * Specifies the animation listener to which layout animation events must
7065 * be sent. Only
7066 * {@link android.view.animation.Animation.AnimationListener#onAnimationStart(Animation)}
7067 * and
7068 * {@link android.view.animation.Animation.AnimationListener#onAnimationEnd(Animation)}
7069 * are invoked.
7070 *
7071 * @param animationListener the layout animation listener
7072 */
7073 public void setLayoutAnimationListener(Animation.AnimationListener animationListener) {
7074 mAnimationListener = animationListener;
7075 }
7076
7077 /**
Chet Haasecca2c982011-05-20 14:34:18 -07007078 * This method is called by LayoutTransition when there are 'changing' animations that need
7079 * to start after the layout/setup phase. The request is forwarded to the ViewAncestor, who
7080 * starts all pending transitions prior to the drawing phase in the current traversal.
7081 *
7082 * @param transition The LayoutTransition to be started on the next traversal.
7083 *
7084 * @hide
7085 */
7086 public void requestTransitionStart(LayoutTransition transition) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07007087 ViewRootImpl viewAncestor = getViewRootImpl();
Chet Haase1abf7fa2011-08-17 18:31:56 -07007088 if (viewAncestor != null) {
7089 viewAncestor.requestTransitionStart(transition);
7090 }
Chet Haasecca2c982011-05-20 14:34:18 -07007091 }
7092
Fabrice Di Meglio4457e852012-09-18 19:23:12 -07007093 /**
7094 * @hide
7095 */
Fabrice Di Meglio80dc53d2011-06-21 18:36:33 -07007096 @Override
Fabrice Di Meglio09ecb252013-05-03 16:51:55 -07007097 public boolean resolveRtlPropertiesIfNeeded() {
7098 final boolean result = super.resolveRtlPropertiesIfNeeded();
7099 // We dont need to resolve the children RTL properties if nothing has changed for the parent
7100 if (result) {
7101 int count = getChildCount();
7102 for (int i = 0; i < count; i++) {
7103 final View child = getChildAt(i);
7104 if (child.isLayoutDirectionInherited()) {
7105 child.resolveRtlPropertiesIfNeeded();
7106 }
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07007107 }
7108 }
Fabrice Di Meglio09ecb252013-05-03 16:51:55 -07007109 return result;
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07007110 }
7111
7112 /**
7113 * @hide
7114 */
7115 @Override
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07007116 public boolean resolveLayoutDirection() {
7117 final boolean result = super.resolveLayoutDirection();
7118 if (result) {
7119 int count = getChildCount();
7120 for (int i = 0; i < count; i++) {
7121 final View child = getChildAt(i);
7122 if (child.isLayoutDirectionInherited()) {
7123 child.resolveLayoutDirection();
7124 }
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07007125 }
7126 }
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07007127 return result;
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07007128 }
7129
7130 /**
7131 * @hide
7132 */
7133 @Override
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07007134 public boolean resolveTextDirection() {
7135 final boolean result = super.resolveTextDirection();
7136 if (result) {
7137 int count = getChildCount();
7138 for (int i = 0; i < count; i++) {
7139 final View child = getChildAt(i);
7140 if (child.isTextDirectionInherited()) {
7141 child.resolveTextDirection();
7142 }
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07007143 }
7144 }
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07007145 return result;
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07007146 }
7147
7148 /**
7149 * @hide
7150 */
7151 @Override
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07007152 public boolean resolveTextAlignment() {
7153 final boolean result = super.resolveTextAlignment();
7154 if (result) {
7155 int count = getChildCount();
7156 for (int i = 0; i < count; i++) {
7157 final View child = getChildAt(i);
7158 if (child.isTextAlignmentInherited()) {
7159 child.resolveTextAlignment();
7160 }
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07007161 }
7162 }
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07007163 return result;
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07007164 }
7165
7166 /**
7167 * @hide
7168 */
7169 @Override
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07007170 public void resolvePadding() {
7171 super.resolvePadding();
7172 int count = getChildCount();
7173 for (int i = 0; i < count; i++) {
7174 final View child = getChildAt(i);
Adam Powell05f35122014-11-10 17:47:37 -08007175 if (child.isLayoutDirectionInherited() && !child.isPaddingResolved()) {
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07007176 child.resolvePadding();
7177 }
7178 }
7179 }
7180
7181 /**
7182 * @hide
7183 */
7184 @Override
7185 protected void resolveDrawables() {
7186 super.resolveDrawables();
7187 int count = getChildCount();
7188 for (int i = 0; i < count; i++) {
7189 final View child = getChildAt(i);
Adam Powell05f35122014-11-10 17:47:37 -08007190 if (child.isLayoutDirectionInherited() && !child.areDrawablesResolved()) {
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07007191 child.resolveDrawables();
7192 }
7193 }
7194 }
7195
Fabrice Di Meglio1e0ed6b2012-10-18 16:06:52 -07007196 /**
7197 * @hide
7198 */
Fabrice Di Megliofcc33482012-10-18 11:11:51 -07007199 @Override
7200 public void resolveLayoutParams() {
7201 super.resolveLayoutParams();
7202 int count = getChildCount();
7203 for (int i = 0; i < count; i++) {
7204 final View child = getChildAt(i);
7205 child.resolveLayoutParams();
7206 }
7207 }
7208
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07007209 /**
7210 * @hide
7211 */
7212 @Override
Fabrice Di Meglio4457e852012-09-18 19:23:12 -07007213 public void resetResolvedLayoutDirection() {
7214 super.resetResolvedLayoutDirection();
7215
Fabrice Di Meglio4457e852012-09-18 19:23:12 -07007216 int count = getChildCount();
Fabrice Di Meglio80dc53d2011-06-21 18:36:33 -07007217 for (int i = 0; i < count; i++) {
7218 final View child = getChildAt(i);
Fabrice Di Meglioe56ffdc2012-09-23 14:51:16 -07007219 if (child.isLayoutDirectionInherited()) {
Fabrice Di Meglio7f86c802011-07-01 15:09:24 -07007220 child.resetResolvedLayoutDirection();
Fabrice Di Meglio80dc53d2011-06-21 18:36:33 -07007221 }
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07007222 }
7223 }
7224
7225 /**
7226 * @hide
7227 */
7228 @Override
7229 public void resetResolvedTextDirection() {
7230 super.resetResolvedTextDirection();
7231
7232 int count = getChildCount();
7233 for (int i = 0; i < count; i++) {
7234 final View child = getChildAt(i);
Fabrice Di Meglio97e146c2012-09-23 15:45:16 -07007235 if (child.isTextDirectionInherited()) {
Fabrice Di Meglio22268862011-06-27 18:13:18 -07007236 child.resetResolvedTextDirection();
7237 }
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07007238 }
7239 }
7240
7241 /**
7242 * @hide
7243 */
7244 @Override
7245 public void resetResolvedTextAlignment() {
7246 super.resetResolvedTextAlignment();
7247
7248 int count = getChildCount();
7249 for (int i = 0; i < count; i++) {
7250 final View child = getChildAt(i);
Fabrice Di Meglio1a7d4872012-09-23 16:19:58 -07007251 if (child.isTextAlignmentInherited()) {
Fabrice Di Meglio9da0f8a2012-03-13 19:37:57 -07007252 child.resetResolvedTextAlignment();
7253 }
7254 }
7255 }
7256
Fabrice Di Meglio22268862011-06-27 18:13:18 -07007257 /**
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07007258 * @hide
7259 */
7260 @Override
7261 public void resetResolvedPadding() {
7262 super.resetResolvedPadding();
7263
7264 int count = getChildCount();
7265 for (int i = 0; i < count; i++) {
7266 final View child = getChildAt(i);
7267 if (child.isLayoutDirectionInherited()) {
7268 child.resetResolvedPadding();
7269 }
7270 }
7271 }
7272
7273 /**
7274 * @hide
7275 */
7276 @Override
7277 protected void resetResolvedDrawables() {
7278 super.resetResolvedDrawables();
7279
7280 int count = getChildCount();
7281 for (int i = 0; i < count; i++) {
7282 final View child = getChildAt(i);
7283 if (child.isLayoutDirectionInherited()) {
7284 child.resetResolvedDrawables();
7285 }
7286 }
7287 }
7288
7289 /**
Patrick Dubroye0a799a2011-05-04 16:19:22 -07007290 * Return true if the pressed state should be delayed for children or descendants of this
7291 * ViewGroup. Generally, this should be done for containers that can scroll, such as a List.
7292 * This prevents the pressed state from appearing when the user is actually trying to scroll
7293 * the content.
7294 *
7295 * The default implementation returns true for compatibility reasons. Subclasses that do
7296 * not scroll should generally override this method and return false.
7297 */
7298 public boolean shouldDelayChildPressedState() {
7299 return true;
7300 }
7301
Adam Powell10ba2772014-04-15 09:46:51 -07007302 /**
7303 * @inheritDoc
7304 */
7305 @Override
7306 public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
7307 return false;
7308 }
7309
7310 /**
7311 * @inheritDoc
7312 */
7313 @Override
7314 public void onNestedScrollAccepted(View child, View target, int axes) {
7315 mNestedScrollAxes = axes;
7316 }
7317
7318 /**
7319 * @inheritDoc
7320 *
7321 * <p>The default implementation of onStopNestedScroll calls
7322 * {@link #stopNestedScroll()} to halt any recursive nested scrolling in progress.</p>
7323 */
7324 @Override
7325 public void onStopNestedScroll(View child) {
7326 // Stop any recursive nested scrolling.
7327 stopNestedScroll();
Adam Powelld4a22d42015-04-16 15:44:10 -07007328 mNestedScrollAxes = 0;
Adam Powell10ba2772014-04-15 09:46:51 -07007329 }
7330
7331 /**
7332 * @inheritDoc
7333 */
7334 @Override
7335 public void onNestedScroll(View target, int dxConsumed, int dyConsumed,
7336 int dxUnconsumed, int dyUnconsumed) {
Chris Banes61d50702016-03-23 13:11:45 +00007337 // Re-dispatch up the tree by default
7338 dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, null);
Adam Powell10ba2772014-04-15 09:46:51 -07007339 }
7340
7341 /**
7342 * @inheritDoc
7343 */
7344 @Override
7345 public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
Chris Banes61d50702016-03-23 13:11:45 +00007346 // Re-dispatch up the tree by default
7347 dispatchNestedPreScroll(dx, dy, consumed, null);
Adam Powell10ba2772014-04-15 09:46:51 -07007348 }
7349
7350 /**
7351 * @inheritDoc
7352 */
7353 @Override
Adam Powellb36e4f92014-05-01 10:23:33 -07007354 public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
Chris Banes61d50702016-03-23 13:11:45 +00007355 // Re-dispatch up the tree by default
7356 return dispatchNestedFling(velocityX, velocityY, consumed);
Adam Powell10ba2772014-04-15 09:46:51 -07007357 }
7358
7359 /**
Adam Powellb72be592014-07-16 21:41:31 -07007360 * @inheritDoc
7361 */
7362 @Override
7363 public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
Chris Banes61d50702016-03-23 13:11:45 +00007364 // Re-dispatch up the tree by default
7365 return dispatchNestedPreFling(velocityX, velocityY);
Adam Powellb72be592014-07-16 21:41:31 -07007366 }
7367
7368 /**
Adam Powell10ba2772014-04-15 09:46:51 -07007369 * Return the current axes of nested scrolling for this ViewGroup.
7370 *
7371 * <p>A ViewGroup returning something other than {@link #SCROLL_AXIS_NONE} is currently
7372 * acting as a nested scrolling parent for one or more descendant views in the hierarchy.</p>
7373 *
7374 * @return Flags indicating the current axes of nested scrolling
7375 * @see #SCROLL_AXIS_HORIZONTAL
7376 * @see #SCROLL_AXIS_VERTICAL
7377 * @see #SCROLL_AXIS_NONE
7378 */
7379 public int getNestedScrollAxes() {
7380 return mNestedScrollAxes;
7381 }
7382
Philip Milned7dd8902012-01-26 16:55:30 -08007383 /** @hide */
7384 protected void onSetLayoutParams(View child, LayoutParams layoutParams) {
Robert Carr5429daa2017-04-03 19:00:26 -07007385 requestLayout();
Philip Milned7dd8902012-01-26 16:55:30 -08007386 }
7387
George Mounte1803372014-02-26 19:00:52 +00007388 /** @hide */
7389 @Override
7390 public void captureTransitioningViews(List<View> transitioningViews) {
7391 if (getVisibility() != View.VISIBLE) {
7392 return;
7393 }
7394 if (isTransitionGroup()) {
7395 transitioningViews.add(this);
7396 } else {
7397 int count = getChildCount();
7398 for (int i = 0; i < count; i++) {
7399 View child = getChildAt(i);
7400 child.captureTransitioningViews(transitioningViews);
7401 }
7402 }
7403 }
7404
7405 /** @hide */
7406 @Override
George Mountabb352a2014-05-09 10:27:20 -07007407 public void findNamedViews(Map<String, View> namedElements) {
George Mountfe361d22014-07-08 17:25:25 -07007408 if (getVisibility() != VISIBLE && mGhostView == null) {
George Mounte1803372014-02-26 19:00:52 +00007409 return;
7410 }
George Mountabb352a2014-05-09 10:27:20 -07007411 super.findNamedViews(namedElements);
George Mounte1803372014-02-26 19:00:52 +00007412 int count = getChildCount();
7413 for (int i = 0; i < count; i++) {
7414 View child = getChildAt(i);
George Mountabb352a2014-05-09 10:27:20 -07007415 child.findNamedViews(namedElements);
George Mounte1803372014-02-26 19:00:52 +00007416 }
7417 }
7418
Patrick Dubroye0a799a2011-05-04 16:19:22 -07007419 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007420 * LayoutParams are used by views to tell their parents how they want to be
7421 * laid out. See
7422 * {@link android.R.styleable#ViewGroup_Layout ViewGroup Layout Attributes}
7423 * for a list of all child view attributes that this class supports.
Romain Guy8506ab42009-06-11 17:35:47 -07007424 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007425 * <p>
7426 * The base LayoutParams class just describes how big the view wants to be
7427 * for both width and height. For each dimension, it can specify one of:
7428 * <ul>
Dirk Dougherty75c66da2010-03-25 16:33:33 -07007429 * <li>FILL_PARENT (renamed MATCH_PARENT in API Level 8 and higher), which
7430 * means that the view wants to be as big as its parent (minus padding)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007431 * <li> WRAP_CONTENT, which means that the view wants to be just big enough
7432 * to enclose its content (plus padding)
Dirk Dougherty75c66da2010-03-25 16:33:33 -07007433 * <li> an exact number
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007434 * </ul>
7435 * There are subclasses of LayoutParams for different subclasses of
7436 * ViewGroup. For example, AbsoluteLayout has its own subclass of
Joe Fernandez558459f2011-10-13 16:47:36 -07007437 * LayoutParams which adds an X and Y value.</p>
7438 *
7439 * <div class="special reference">
7440 * <h3>Developer Guides</h3>
7441 * <p>For more information about creating user interface layouts, read the
7442 * <a href="{@docRoot}guide/topics/ui/declaring-layout.html">XML Layouts</a> developer
7443 * guide.</p></div>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007444 *
7445 * @attr ref android.R.styleable#ViewGroup_Layout_layout_height
7446 * @attr ref android.R.styleable#ViewGroup_Layout_layout_width
7447 */
7448 public static class LayoutParams {
7449 /**
Dirk Dougherty75c66da2010-03-25 16:33:33 -07007450 * Special value for the height or width requested by a View.
7451 * FILL_PARENT means that the view wants to be as big as its parent,
7452 * minus the parent's padding, if any. This value is deprecated
7453 * starting in API Level 8 and replaced by {@link #MATCH_PARENT}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007454 */
Romain Guy980a9382010-01-08 15:06:28 -08007455 @SuppressWarnings({"UnusedDeclaration"})
7456 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007457 public static final int FILL_PARENT = -1;
7458
7459 /**
7460 * Special value for the height or width requested by a View.
Gilles Debunnef5c6eff2010-02-09 19:08:36 -08007461 * MATCH_PARENT means that the view wants to be as big as its parent,
Dirk Dougherty75c66da2010-03-25 16:33:33 -07007462 * minus the parent's padding, if any. Introduced in API Level 8.
Romain Guy980a9382010-01-08 15:06:28 -08007463 */
7464 public static final int MATCH_PARENT = -1;
7465
7466 /**
7467 * Special value for the height or width requested by a View.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007468 * WRAP_CONTENT means that the view wants to be just large enough to fit
7469 * its own internal content, taking its own padding into account.
7470 */
7471 public static final int WRAP_CONTENT = -2;
7472
7473 /**
Dirk Dougherty75c66da2010-03-25 16:33:33 -07007474 * Information about how wide the view wants to be. Can be one of the
Mark Dolinerd0646dc2014-08-27 16:04:02 -07007475 * constants FILL_PARENT (replaced by MATCH_PARENT
7476 * in API Level 8) or WRAP_CONTENT, or an exact size.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007477 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07007478 @ViewDebug.ExportedProperty(category = "layout", mapping = {
Romain Guy980a9382010-01-08 15:06:28 -08007479 @ViewDebug.IntToString(from = MATCH_PARENT, to = "MATCH_PARENT"),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007480 @ViewDebug.IntToString(from = WRAP_CONTENT, to = "WRAP_CONTENT")
7481 })
7482 public int width;
7483
7484 /**
Dirk Dougherty75c66da2010-03-25 16:33:33 -07007485 * Information about how tall the view wants to be. Can be one of the
Mark Dolinerd0646dc2014-08-27 16:04:02 -07007486 * constants FILL_PARENT (replaced by MATCH_PARENT
7487 * in API Level 8) or WRAP_CONTENT, or an exact size.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007488 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07007489 @ViewDebug.ExportedProperty(category = "layout", mapping = {
Romain Guy980a9382010-01-08 15:06:28 -08007490 @ViewDebug.IntToString(from = MATCH_PARENT, to = "MATCH_PARENT"),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007491 @ViewDebug.IntToString(from = WRAP_CONTENT, to = "WRAP_CONTENT")
7492 })
7493 public int height;
7494
7495 /**
7496 * Used to animate layouts.
7497 */
7498 public LayoutAnimationController.AnimationParameters layoutAnimationParameters;
7499
7500 /**
7501 * Creates a new set of layout parameters. The values are extracted from
7502 * the supplied attributes set and context. The XML attributes mapped
7503 * to this set of layout parameters are:
7504 *
7505 * <ul>
7506 * <li><code>layout_width</code>: the width, either an exact value,
Dirk Dougherty75c66da2010-03-25 16:33:33 -07007507 * {@link #WRAP_CONTENT}, or {@link #FILL_PARENT} (replaced by
7508 * {@link #MATCH_PARENT} in API Level 8)</li>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007509 * <li><code>layout_height</code>: the height, either an exact value,
Dirk Dougherty75c66da2010-03-25 16:33:33 -07007510 * {@link #WRAP_CONTENT}, or {@link #FILL_PARENT} (replaced by
7511 * {@link #MATCH_PARENT} in API Level 8)</li>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007512 * </ul>
7513 *
7514 * @param c the application environment
7515 * @param attrs the set of attributes from which to extract the layout
7516 * parameters' values
7517 */
7518 public LayoutParams(Context c, AttributeSet attrs) {
7519 TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ViewGroup_Layout);
7520 setBaseAttributes(a,
7521 R.styleable.ViewGroup_Layout_layout_width,
7522 R.styleable.ViewGroup_Layout_layout_height);
7523 a.recycle();
7524 }
7525
7526 /**
7527 * Creates a new set of layout parameters with the specified width
7528 * and height.
7529 *
Dirk Dougherty75c66da2010-03-25 16:33:33 -07007530 * @param width the width, either {@link #WRAP_CONTENT},
7531 * {@link #FILL_PARENT} (replaced by {@link #MATCH_PARENT} in
7532 * API Level 8), or a fixed size in pixels
7533 * @param height the height, either {@link #WRAP_CONTENT},
7534 * {@link #FILL_PARENT} (replaced by {@link #MATCH_PARENT} in
7535 * API Level 8), or a fixed size in pixels
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007536 */
7537 public LayoutParams(int width, int height) {
7538 this.width = width;
7539 this.height = height;
7540 }
7541
7542 /**
7543 * Copy constructor. Clones the width and height values of the source.
7544 *
7545 * @param source The layout params to copy from.
7546 */
7547 public LayoutParams(LayoutParams source) {
7548 this.width = source.width;
7549 this.height = source.height;
7550 }
7551
7552 /**
7553 * Used internally by MarginLayoutParams.
7554 * @hide
7555 */
7556 LayoutParams() {
7557 }
7558
7559 /**
Dave Burke579e1402012-10-18 20:41:55 -07007560 * Extracts the layout parameters from the supplied attributes.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007561 *
7562 * @param a the style attributes to extract the parameters from
7563 * @param widthAttr the identifier of the width attribute
7564 * @param heightAttr the identifier of the height attribute
7565 */
7566 protected void setBaseAttributes(TypedArray a, int widthAttr, int heightAttr) {
Dave Burke579e1402012-10-18 20:41:55 -07007567 width = a.getLayoutDimension(widthAttr, "layout_width");
7568 height = a.getLayoutDimension(heightAttr, "layout_height");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007569 }
7570
7571 /**
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007572 * Resolve layout parameters depending on the layout direction. Subclasses that care about
7573 * layoutDirection changes should override this method. The default implementation does
7574 * nothing.
7575 *
7576 * @param layoutDirection the direction of the layout
7577 *
7578 * {@link View#LAYOUT_DIRECTION_LTR}
7579 * {@link View#LAYOUT_DIRECTION_RTL}
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007580 */
Fabrice Di Meglio2918ab62012-10-10 16:39:25 -07007581 public void resolveLayoutDirection(int layoutDirection) {
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007582 }
7583
7584 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007585 * Returns a String representation of this set of layout parameters.
7586 *
7587 * @param output the String to prepend to the internal representation
7588 * @return a String with the following format: output +
7589 * "ViewGroup.LayoutParams={ width=WIDTH, height=HEIGHT }"
Romain Guy8506ab42009-06-11 17:35:47 -07007590 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007591 * @hide
7592 */
7593 public String debug(String output) {
7594 return output + "ViewGroup.LayoutParams={ width="
7595 + sizeToString(width) + ", height=" + sizeToString(height) + " }";
7596 }
7597
7598 /**
Philip Milne10ca24a2012-04-23 15:38:27 -07007599 * Use {@code canvas} to draw suitable debugging annotations for these LayoutParameters.
7600 *
Andrei Stingaceanu12448152017-07-12 17:39:45 +01007601 * <p>This function is called automatically when the developer setting is enabled.<p/>
7602 *
7603 * <p>It is strongly advised to only call this function from debug builds as there is
7604 * a risk of leaking unwanted layout information.<p/>
7605 *
Philip Milne10ca24a2012-04-23 15:38:27 -07007606 * @param view the view that contains these layout parameters
7607 * @param canvas the canvas on which to draw
Andrei Stingaceanu12448152017-07-12 17:39:45 +01007608 * @param paint the paint used to draw through
Philip Milne10ca24a2012-04-23 15:38:27 -07007609 */
Philip Milne7b757812012-09-19 18:13:44 -07007610 public void onDebugDraw(View view, Canvas canvas, Paint paint) {
Philip Milne10ca24a2012-04-23 15:38:27 -07007611 }
7612
7613 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007614 * Converts the specified size to a readable String.
7615 *
7616 * @param size the size to convert
7617 * @return a String instance representing the supplied size
Romain Guy8506ab42009-06-11 17:35:47 -07007618 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007619 * @hide
7620 */
7621 protected static String sizeToString(int size) {
7622 if (size == WRAP_CONTENT) {
7623 return "wrap-content";
7624 }
Romain Guy980a9382010-01-08 15:06:28 -08007625 if (size == MATCH_PARENT) {
7626 return "match-parent";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007627 }
7628 return String.valueOf(size);
7629 }
Siva Velusamy0d857b92015-04-22 10:23:56 -07007630
7631 /** @hide */
7632 void encode(@NonNull ViewHierarchyEncoder encoder) {
7633 encoder.beginObject(this);
7634 encodeProperties(encoder);
7635 encoder.endObject();
7636 }
7637
7638 /** @hide */
7639 protected void encodeProperties(@NonNull ViewHierarchyEncoder encoder) {
7640 encoder.addProperty("width", width);
7641 encoder.addProperty("height", height);
7642 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007643 }
7644
7645 /**
7646 * Per-child layout information for layouts that support margins.
7647 * See
7648 * {@link android.R.styleable#ViewGroup_MarginLayout ViewGroup Margin Layout Attributes}
7649 * for a list of all child view attributes that this class supports.
Chet Haase353d3972017-06-29 07:54:19 -07007650 *
7651 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_margin
7652 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginHorizontal
7653 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginVertical
7654 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginLeft
7655 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginTop
7656 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginRight
7657 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginBottom
7658 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
7659 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007660 */
7661 public static class MarginLayoutParams extends ViewGroup.LayoutParams {
7662 /**
Adam Powella7a735f2014-10-09 12:54:52 -07007663 * The left margin in pixels of the child. Margin values should be positive.
Philip Milned7dd8902012-01-26 16:55:30 -08007664 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
7665 * to this field.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007666 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07007667 @ViewDebug.ExportedProperty(category = "layout")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007668 public int leftMargin;
7669
7670 /**
Adam Powella7a735f2014-10-09 12:54:52 -07007671 * The top margin in pixels of the child. Margin values should be positive.
Philip Milned7dd8902012-01-26 16:55:30 -08007672 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
7673 * to this field.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007674 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07007675 @ViewDebug.ExportedProperty(category = "layout")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007676 public int topMargin;
7677
7678 /**
Adam Powella7a735f2014-10-09 12:54:52 -07007679 * The right margin in pixels of the child. Margin values should be positive.
Philip Milned7dd8902012-01-26 16:55:30 -08007680 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
7681 * to this field.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007682 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07007683 @ViewDebug.ExportedProperty(category = "layout")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007684 public int rightMargin;
7685
7686 /**
Adam Powella7a735f2014-10-09 12:54:52 -07007687 * The bottom margin in pixels of the child. Margin values should be positive.
Philip Milned7dd8902012-01-26 16:55:30 -08007688 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
7689 * to this field.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007690 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07007691 @ViewDebug.ExportedProperty(category = "layout")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007692 public int bottomMargin;
7693
7694 /**
Adam Powella7a735f2014-10-09 12:54:52 -07007695 * The start margin in pixels of the child. Margin values should be positive.
Fabrice Di Meglio54546f22012-02-14 16:26:16 -08007696 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
7697 * to this field.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007698 */
7699 @ViewDebug.ExportedProperty(category = "layout")
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07007700 private int startMargin = DEFAULT_MARGIN_RELATIVE;
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007701
7702 /**
Adam Powella7a735f2014-10-09 12:54:52 -07007703 * The end margin in pixels of the child. Margin values should be positive.
Fabrice Di Meglio54546f22012-02-14 16:26:16 -08007704 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
7705 * to this field.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007706 */
7707 @ViewDebug.ExportedProperty(category = "layout")
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07007708 private int endMargin = DEFAULT_MARGIN_RELATIVE;
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007709
7710 /**
7711 * The default start and end margin.
Fabrice Di Megliof443f982012-07-13 20:24:03 -07007712 * @hide
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007713 */
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07007714 public static final int DEFAULT_MARGIN_RELATIVE = Integer.MIN_VALUE;
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007715
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007716 /**
7717 * Bit 0: layout direction
7718 * Bit 1: layout direction
7719 * Bit 2: left margin undefined
7720 * Bit 3: right margin undefined
7721 * Bit 4: is RTL compatibility mode
7722 * Bit 5: need resolution
7723 *
7724 * Bit 6 to 7 not used
7725 *
7726 * @hide
7727 */
7728 @ViewDebug.ExportedProperty(category = "layout", flagMapping = {
7729 @ViewDebug.FlagToString(mask = LAYOUT_DIRECTION_MASK,
7730 equals = LAYOUT_DIRECTION_MASK, name = "LAYOUT_DIRECTION"),
7731 @ViewDebug.FlagToString(mask = LEFT_MARGIN_UNDEFINED_MASK,
7732 equals = LEFT_MARGIN_UNDEFINED_MASK, name = "LEFT_MARGIN_UNDEFINED_MASK"),
7733 @ViewDebug.FlagToString(mask = RIGHT_MARGIN_UNDEFINED_MASK,
7734 equals = RIGHT_MARGIN_UNDEFINED_MASK, name = "RIGHT_MARGIN_UNDEFINED_MASK"),
7735 @ViewDebug.FlagToString(mask = RTL_COMPATIBILITY_MODE_MASK,
7736 equals = RTL_COMPATIBILITY_MODE_MASK, name = "RTL_COMPATIBILITY_MODE_MASK"),
7737 @ViewDebug.FlagToString(mask = NEED_RESOLUTION_MASK,
7738 equals = NEED_RESOLUTION_MASK, name = "NEED_RESOLUTION_MASK")
Jon Miranda4597e982014-07-29 07:25:49 -07007739 }, formatToHexString = true)
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007740 byte mMarginFlags;
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07007741
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007742 private static final int LAYOUT_DIRECTION_MASK = 0x00000003;
7743 private static final int LEFT_MARGIN_UNDEFINED_MASK = 0x00000004;
7744 private static final int RIGHT_MARGIN_UNDEFINED_MASK = 0x00000008;
7745 private static final int RTL_COMPATIBILITY_MODE_MASK = 0x00000010;
7746 private static final int NEED_RESOLUTION_MASK = 0x00000020;
Fabrice Di Megliof443f982012-07-13 20:24:03 -07007747
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007748 private static final int DEFAULT_MARGIN_RESOLVED = 0;
7749 private static final int UNDEFINED_MARGIN = DEFAULT_MARGIN_RELATIVE;
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07007750
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007751 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007752 * Creates a new set of layout parameters. The values are extracted from
7753 * the supplied attributes set and context.
7754 *
7755 * @param c the application environment
7756 * @param attrs the set of attributes from which to extract the layout
7757 * parameters' values
7758 */
7759 public MarginLayoutParams(Context c, AttributeSet attrs) {
7760 super();
7761
7762 TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ViewGroup_MarginLayout);
7763 setBaseAttributes(a,
7764 R.styleable.ViewGroup_MarginLayout_layout_width,
7765 R.styleable.ViewGroup_MarginLayout_layout_height);
7766
7767 int margin = a.getDimensionPixelSize(
7768 com.android.internal.R.styleable.ViewGroup_MarginLayout_layout_margin, -1);
7769 if (margin >= 0) {
7770 leftMargin = margin;
7771 topMargin = margin;
7772 rightMargin= margin;
7773 bottomMargin = margin;
7774 } else {
Chet Haase40b2de52016-11-28 16:11:42 -08007775 int horizontalMargin = a.getDimensionPixelSize(
7776 R.styleable.ViewGroup_MarginLayout_layout_marginHorizontal, -1);
7777 int verticalMargin = a.getDimensionPixelSize(
7778 R.styleable.ViewGroup_MarginLayout_layout_marginVertical, -1);
7779
7780 if (horizontalMargin >= 0) {
7781 leftMargin = horizontalMargin;
7782 rightMargin = horizontalMargin;
7783 } else {
7784 leftMargin = a.getDimensionPixelSize(
7785 R.styleable.ViewGroup_MarginLayout_layout_marginLeft,
7786 UNDEFINED_MARGIN);
7787 if (leftMargin == UNDEFINED_MARGIN) {
7788 mMarginFlags |= LEFT_MARGIN_UNDEFINED_MASK;
7789 leftMargin = DEFAULT_MARGIN_RESOLVED;
7790 }
7791 rightMargin = a.getDimensionPixelSize(
7792 R.styleable.ViewGroup_MarginLayout_layout_marginRight,
7793 UNDEFINED_MARGIN);
7794 if (rightMargin == UNDEFINED_MARGIN) {
7795 mMarginFlags |= RIGHT_MARGIN_UNDEFINED_MASK;
7796 rightMargin = DEFAULT_MARGIN_RESOLVED;
7797 }
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07007798 }
7799
Chet Haasecb3d0232017-05-24 18:27:14 -07007800 startMargin = a.getDimensionPixelSize(
7801 R.styleable.ViewGroup_MarginLayout_layout_marginStart,
7802 DEFAULT_MARGIN_RELATIVE);
7803 endMargin = a.getDimensionPixelSize(
7804 R.styleable.ViewGroup_MarginLayout_layout_marginEnd,
7805 DEFAULT_MARGIN_RELATIVE);
7806
Chet Haase40b2de52016-11-28 16:11:42 -08007807 if (verticalMargin >= 0) {
7808 topMargin = verticalMargin;
7809 bottomMargin = verticalMargin;
7810 } else {
7811 topMargin = a.getDimensionPixelSize(
7812 R.styleable.ViewGroup_MarginLayout_layout_marginTop,
7813 DEFAULT_MARGIN_RESOLVED);
7814 bottomMargin = a.getDimensionPixelSize(
7815 R.styleable.ViewGroup_MarginLayout_layout_marginBottom,
7816 DEFAULT_MARGIN_RESOLVED);
7817 }
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07007818
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007819 if (isMarginRelative()) {
7820 mMarginFlags |= NEED_RESOLUTION_MASK;
7821 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007822 }
7823
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07007824 final boolean hasRtlSupport = c.getApplicationInfo().hasRtlSupport();
7825 final int targetSdkVersion = c.getApplicationInfo().targetSdkVersion;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007826 if (targetSdkVersion < JELLY_BEAN_MR1 || !hasRtlSupport) {
7827 mMarginFlags |= RTL_COMPATIBILITY_MODE_MASK;
7828 }
7829
7830 // Layout direction is LTR by default
7831 mMarginFlags |= LAYOUT_DIRECTION_LTR;
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07007832
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007833 a.recycle();
7834 }
7835
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007836 public MarginLayoutParams(int width, int height) {
7837 super(width, height);
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07007838
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007839 mMarginFlags |= LEFT_MARGIN_UNDEFINED_MASK;
7840 mMarginFlags |= RIGHT_MARGIN_UNDEFINED_MASK;
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07007841
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007842 mMarginFlags &= ~NEED_RESOLUTION_MASK;
7843 mMarginFlags &= ~RTL_COMPATIBILITY_MODE_MASK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007844 }
7845
7846 /**
7847 * Copy constructor. Clones the width, height and margin values of the source.
7848 *
7849 * @param source The layout params to copy from.
7850 */
7851 public MarginLayoutParams(MarginLayoutParams source) {
7852 this.width = source.width;
7853 this.height = source.height;
7854
7855 this.leftMargin = source.leftMargin;
7856 this.topMargin = source.topMargin;
7857 this.rightMargin = source.rightMargin;
7858 this.bottomMargin = source.bottomMargin;
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007859 this.startMargin = source.startMargin;
7860 this.endMargin = source.endMargin;
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07007861
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007862 this.mMarginFlags = source.mMarginFlags;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007863 }
7864
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007865 public MarginLayoutParams(LayoutParams source) {
7866 super(source);
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07007867
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007868 mMarginFlags |= LEFT_MARGIN_UNDEFINED_MASK;
7869 mMarginFlags |= RIGHT_MARGIN_UNDEFINED_MASK;
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07007870
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007871 mMarginFlags &= ~NEED_RESOLUTION_MASK;
7872 mMarginFlags &= ~RTL_COMPATIBILITY_MODE_MASK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007873 }
7874
7875 /**
Adam Powelld7600832014-07-01 15:22:50 -07007876 * @hide Used internally.
7877 */
7878 public final void copyMarginsFrom(MarginLayoutParams source) {
7879 this.leftMargin = source.leftMargin;
7880 this.topMargin = source.topMargin;
7881 this.rightMargin = source.rightMargin;
7882 this.bottomMargin = source.bottomMargin;
7883 this.startMargin = source.startMargin;
7884 this.endMargin = source.endMargin;
7885
7886 this.mMarginFlags = source.mMarginFlags;
7887 }
7888
7889 /**
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007890 * Sets the margins, in pixels. A call to {@link android.view.View#requestLayout()} needs
7891 * to be done so that the new margins are taken into account. Left and right margins may be
7892 * overriden by {@link android.view.View#requestLayout()} depending on layout direction.
Adam Powella7a735f2014-10-09 12:54:52 -07007893 * Margin values should be positive.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007894 *
7895 * @param left the left margin size
7896 * @param top the top margin size
7897 * @param right the right margin size
7898 * @param bottom the bottom margin size
7899 *
7900 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginLeft
7901 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginTop
7902 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginRight
7903 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginBottom
7904 */
7905 public void setMargins(int left, int top, int right, int bottom) {
7906 leftMargin = left;
7907 topMargin = top;
7908 rightMargin = right;
7909 bottomMargin = bottom;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007910 mMarginFlags &= ~LEFT_MARGIN_UNDEFINED_MASK;
7911 mMarginFlags &= ~RIGHT_MARGIN_UNDEFINED_MASK;
7912 if (isMarginRelative()) {
7913 mMarginFlags |= NEED_RESOLUTION_MASK;
7914 } else {
7915 mMarginFlags &= ~NEED_RESOLUTION_MASK;
7916 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007917 }
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007918
7919 /**
7920 * Sets the relative margins, in pixels. A call to {@link android.view.View#requestLayout()}
7921 * needs to be done so that the new relative margins are taken into account. Left and right
7922 * margins may be overriden by {@link android.view.View#requestLayout()} depending on layout
Adam Powella7a735f2014-10-09 12:54:52 -07007923 * direction. Margin values should be positive.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007924 *
7925 * @param start the start margin size
7926 * @param top the top margin size
7927 * @param end the right margin size
7928 * @param bottom the bottom margin size
7929 *
7930 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
7931 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginTop
7932 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
7933 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginBottom
7934 *
7935 * @hide
7936 */
7937 public void setMarginsRelative(int start, int top, int end, int bottom) {
7938 startMargin = start;
7939 topMargin = top;
7940 endMargin = end;
7941 bottomMargin = bottom;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007942 mMarginFlags |= NEED_RESOLUTION_MASK;
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007943 }
7944
7945 /**
Adam Powella7a735f2014-10-09 12:54:52 -07007946 * Sets the relative start margin. Margin values should be positive.
Fabrice Di Meglioa40627d2012-09-11 16:47:21 -07007947 *
Fabrice Di Meglio61a21772012-09-12 16:33:13 -07007948 * @param start the start margin size
Fabrice Di Meglioa40627d2012-09-11 16:47:21 -07007949 *
7950 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
7951 */
7952 public void setMarginStart(int start) {
7953 startMargin = start;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007954 mMarginFlags |= NEED_RESOLUTION_MASK;
Fabrice Di Meglioa40627d2012-09-11 16:47:21 -07007955 }
7956
7957 /**
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007958 * Returns the start margin in pixels.
7959 *
7960 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
7961 *
7962 * @return the start margin in pixels.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007963 */
7964 public int getMarginStart() {
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07007965 if (startMargin != DEFAULT_MARGIN_RELATIVE) return startMargin;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007966 if ((mMarginFlags & NEED_RESOLUTION_MASK) == NEED_RESOLUTION_MASK) {
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07007967 doResolveMargins();
7968 }
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007969 switch(mMarginFlags & LAYOUT_DIRECTION_MASK) {
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07007970 case View.LAYOUT_DIRECTION_RTL:
7971 return rightMargin;
7972 case View.LAYOUT_DIRECTION_LTR:
7973 default:
7974 return leftMargin;
7975 }
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007976 }
7977
7978 /**
Adam Powella7a735f2014-10-09 12:54:52 -07007979 * Sets the relative end margin. Margin values should be positive.
Fabrice Di Meglioa40627d2012-09-11 16:47:21 -07007980 *
Fabrice Di Meglio61a21772012-09-12 16:33:13 -07007981 * @param end the end margin size
Fabrice Di Meglioa40627d2012-09-11 16:47:21 -07007982 *
7983 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
7984 */
7985 public void setMarginEnd(int end) {
7986 endMargin = end;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007987 mMarginFlags |= NEED_RESOLUTION_MASK;
Fabrice Di Meglioa40627d2012-09-11 16:47:21 -07007988 }
7989
7990 /**
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007991 * Returns the end margin in pixels.
7992 *
7993 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
7994 *
7995 * @return the end margin in pixels.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007996 */
7997 public int getMarginEnd() {
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07007998 if (endMargin != DEFAULT_MARGIN_RELATIVE) return endMargin;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007999 if ((mMarginFlags & NEED_RESOLUTION_MASK) == NEED_RESOLUTION_MASK) {
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07008000 doResolveMargins();
8001 }
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008002 switch(mMarginFlags & LAYOUT_DIRECTION_MASK) {
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07008003 case View.LAYOUT_DIRECTION_RTL:
8004 return leftMargin;
8005 case View.LAYOUT_DIRECTION_LTR:
8006 default:
8007 return rightMargin;
8008 }
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07008009 }
8010
8011 /**
8012 * Check if margins are relative.
8013 *
8014 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
8015 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
8016 *
Fabrice Di Megliof443f982012-07-13 20:24:03 -07008017 * @return true if either marginStart or marginEnd has been set.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07008018 */
8019 public boolean isMarginRelative() {
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07008020 return (startMargin != DEFAULT_MARGIN_RELATIVE || endMargin != DEFAULT_MARGIN_RELATIVE);
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07008021 }
8022
8023 /**
Fabrice Di Megliof443f982012-07-13 20:24:03 -07008024 * Set the layout direction
8025 * @param layoutDirection the layout direction.
8026 * Should be either {@link View#LAYOUT_DIRECTION_LTR}
8027 * or {@link View#LAYOUT_DIRECTION_RTL}.
8028 */
8029 public void setLayoutDirection(int layoutDirection) {
8030 if (layoutDirection != View.LAYOUT_DIRECTION_LTR &&
8031 layoutDirection != View.LAYOUT_DIRECTION_RTL) return;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008032 if (layoutDirection != (mMarginFlags & LAYOUT_DIRECTION_MASK)) {
8033 mMarginFlags &= ~LAYOUT_DIRECTION_MASK;
8034 mMarginFlags |= (layoutDirection & LAYOUT_DIRECTION_MASK);
8035 if (isMarginRelative()) {
8036 mMarginFlags |= NEED_RESOLUTION_MASK;
8037 } else {
8038 mMarginFlags &= ~NEED_RESOLUTION_MASK;
8039 }
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07008040 }
Fabrice Di Megliof443f982012-07-13 20:24:03 -07008041 }
8042
8043 /**
8044 * Retuns the layout direction. Can be either {@link View#LAYOUT_DIRECTION_LTR} or
8045 * {@link View#LAYOUT_DIRECTION_RTL}.
8046 *
8047 * @return the layout direction.
8048 */
8049 public int getLayoutDirection() {
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008050 return (mMarginFlags & LAYOUT_DIRECTION_MASK);
Fabrice Di Megliof443f982012-07-13 20:24:03 -07008051 }
8052
8053 /**
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07008054 * This will be called by {@link android.view.View#requestLayout()}. Left and Right margins
Fabrice Di Meglio98aec1c2012-02-13 16:54:05 -08008055 * may be overridden depending on layout direction.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07008056 */
8057 @Override
Fabrice Di Meglio2918ab62012-10-10 16:39:25 -07008058 public void resolveLayoutDirection(int layoutDirection) {
Fabrice Di Megliof443f982012-07-13 20:24:03 -07008059 setLayoutDirection(layoutDirection);
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07008060
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07008061 // No relative margin or pre JB-MR1 case or no need to resolve, just dont do anything
8062 // Will use the left and right margins if no relative margin is defined.
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008063 if (!isMarginRelative() ||
8064 (mMarginFlags & NEED_RESOLUTION_MASK) != NEED_RESOLUTION_MASK) return;
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07008065
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07008066 // Proceed with resolution
8067 doResolveMargins();
8068 }
8069
8070 private void doResolveMargins() {
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008071 if ((mMarginFlags & RTL_COMPATIBILITY_MODE_MASK) == RTL_COMPATIBILITY_MODE_MASK) {
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07008072 // if left or right margins are not defined and if we have some start or end margin
8073 // defined then use those start and end margins.
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008074 if ((mMarginFlags & LEFT_MARGIN_UNDEFINED_MASK) == LEFT_MARGIN_UNDEFINED_MASK
8075 && startMargin > DEFAULT_MARGIN_RELATIVE) {
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07008076 leftMargin = startMargin;
8077 }
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008078 if ((mMarginFlags & RIGHT_MARGIN_UNDEFINED_MASK) == RIGHT_MARGIN_UNDEFINED_MASK
8079 && endMargin > DEFAULT_MARGIN_RELATIVE) {
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07008080 rightMargin = endMargin;
8081 }
8082 } else {
8083 // We have some relative margins (either the start one or the end one or both). So use
8084 // them and override what has been defined for left and right margins. If either start
8085 // or end margin is not defined, just set it to default "0".
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008086 switch(mMarginFlags & LAYOUT_DIRECTION_MASK) {
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07008087 case View.LAYOUT_DIRECTION_RTL:
8088 leftMargin = (endMargin > DEFAULT_MARGIN_RELATIVE) ?
8089 endMargin : DEFAULT_MARGIN_RESOLVED;
8090 rightMargin = (startMargin > DEFAULT_MARGIN_RELATIVE) ?
8091 startMargin : DEFAULT_MARGIN_RESOLVED;
8092 break;
8093 case View.LAYOUT_DIRECTION_LTR:
8094 default:
8095 leftMargin = (startMargin > DEFAULT_MARGIN_RELATIVE) ?
8096 startMargin : DEFAULT_MARGIN_RESOLVED;
8097 rightMargin = (endMargin > DEFAULT_MARGIN_RELATIVE) ?
8098 endMargin : DEFAULT_MARGIN_RESOLVED;
8099 break;
8100 }
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07008101 }
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008102 mMarginFlags &= ~NEED_RESOLUTION_MASK;
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07008103 }
Philip Milne10ca24a2012-04-23 15:38:27 -07008104
Fabrice Di Meglio03b8d3a2012-09-27 17:05:27 -07008105 /**
8106 * @hide
8107 */
8108 public boolean isLayoutRtl() {
Fabrice Di Megliob365f912013-03-27 16:36:21 -07008109 return ((mMarginFlags & LAYOUT_DIRECTION_MASK) == View.LAYOUT_DIRECTION_RTL);
Fabrice Di Megliof443f982012-07-13 20:24:03 -07008110 }
8111
Philip Milne10ca24a2012-04-23 15:38:27 -07008112 @Override
Philip Milne7b757812012-09-19 18:13:44 -07008113 public void onDebugDraw(View view, Canvas canvas, Paint paint) {
8114 Insets oi = isLayoutModeOptical(view.mParent) ? view.getOpticalInsets() : Insets.NONE;
8115
8116 fillDifference(canvas,
8117 view.getLeft() + oi.left,
8118 view.getTop() + oi.top,
8119 view.getRight() - oi.right,
8120 view.getBottom() - oi.bottom,
8121 leftMargin,
8122 topMargin,
8123 rightMargin,
8124 bottomMargin,
8125 paint);
Philip Milne10ca24a2012-04-23 15:38:27 -07008126 }
Siva Velusamy0d857b92015-04-22 10:23:56 -07008127
8128 /** @hide */
8129 @Override
8130 protected void encodeProperties(@NonNull ViewHierarchyEncoder encoder) {
8131 super.encodeProperties(encoder);
8132 encoder.addProperty("leftMargin", leftMargin);
8133 encoder.addProperty("topMargin", topMargin);
8134 encoder.addProperty("rightMargin", rightMargin);
8135 encoder.addProperty("bottomMargin", bottomMargin);
8136 encoder.addProperty("startMargin", startMargin);
8137 encoder.addProperty("endMargin", endMargin);
8138 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008139 }
Adam Powell2b342f02010-08-18 18:14:13 -07008140
Jeff Brown20e987b2010-08-23 12:01:02 -07008141 /* Describes a touched view and the ids of the pointers that it has captured.
8142 *
8143 * This code assumes that pointer ids are always in the range 0..31 such that
8144 * it can use a bitfield to track which pointer ids are present.
8145 * As it happens, the lower layers of the input dispatch pipeline also use the
8146 * same trick so the assumption should be safe here...
8147 */
8148 private static final class TouchTarget {
8149 private static final int MAX_RECYCLED = 32;
Romain Guy6410c0a2013-06-17 11:21:58 -07008150 private static final Object sRecycleLock = new Object[0];
Jeff Brown20e987b2010-08-23 12:01:02 -07008151 private static TouchTarget sRecycleBin;
8152 private static int sRecycledCount;
Adam Powell2b342f02010-08-18 18:14:13 -07008153
Jeff Brown20e987b2010-08-23 12:01:02 -07008154 public static final int ALL_POINTER_IDS = -1; // all ones
Adam Powell2b342f02010-08-18 18:14:13 -07008155
Jeff Brown20e987b2010-08-23 12:01:02 -07008156 // The touched child view.
8157 public View child;
8158
8159 // The combined bit mask of pointer ids for all pointers captured by the target.
8160 public int pointerIdBits;
8161
8162 // The next target in the target list.
8163 public TouchTarget next;
8164
8165 private TouchTarget() {
Adam Powell2b342f02010-08-18 18:14:13 -07008166 }
8167
Alan Viverettea7b85e62016-01-22 10:14:02 -05008168 public static TouchTarget obtain(@NonNull View child, int pointerIdBits) {
8169 if (child == null) {
8170 throw new IllegalArgumentException("child must be non-null");
8171 }
8172
Jeff Brown20e987b2010-08-23 12:01:02 -07008173 final TouchTarget target;
8174 synchronized (sRecycleLock) {
Adam Powell816c3be2010-08-23 18:00:05 -07008175 if (sRecycleBin == null) {
Jeff Brown20e987b2010-08-23 12:01:02 -07008176 target = new TouchTarget();
Adam Powell816c3be2010-08-23 18:00:05 -07008177 } else {
Jeff Brown20e987b2010-08-23 12:01:02 -07008178 target = sRecycleBin;
8179 sRecycleBin = target.next;
8180 sRecycledCount--;
8181 target.next = null;
Adam Powell816c3be2010-08-23 18:00:05 -07008182 }
Adam Powell816c3be2010-08-23 18:00:05 -07008183 }
Jeff Brown20e987b2010-08-23 12:01:02 -07008184 target.child = child;
8185 target.pointerIdBits = pointerIdBits;
8186 return target;
8187 }
Adam Powell816c3be2010-08-23 18:00:05 -07008188
Jeff Brown20e987b2010-08-23 12:01:02 -07008189 public void recycle() {
Alan Viverettea7b85e62016-01-22 10:14:02 -05008190 if (child == null) {
8191 throw new IllegalStateException("already recycled once");
8192 }
8193
Jeff Brown20e987b2010-08-23 12:01:02 -07008194 synchronized (sRecycleLock) {
8195 if (sRecycledCount < MAX_RECYCLED) {
8196 next = sRecycleBin;
8197 sRecycleBin = this;
8198 sRecycledCount += 1;
Patrick Dubroyfb0547d22010-10-19 17:36:18 -07008199 } else {
8200 next = null;
Adam Powell816c3be2010-08-23 18:00:05 -07008201 }
Patrick Dubroyfb0547d22010-10-19 17:36:18 -07008202 child = null;
Adam Powell816c3be2010-08-23 18:00:05 -07008203 }
8204 }
Adam Powell2b342f02010-08-18 18:14:13 -07008205 }
Jeff Brown87b7f802011-06-21 18:35:45 -07008206
8207 /* Describes a hovered view. */
8208 private static final class HoverTarget {
8209 private static final int MAX_RECYCLED = 32;
Romain Guy6410c0a2013-06-17 11:21:58 -07008210 private static final Object sRecycleLock = new Object[0];
Jeff Brown87b7f802011-06-21 18:35:45 -07008211 private static HoverTarget sRecycleBin;
8212 private static int sRecycledCount;
8213
8214 // The hovered child view.
8215 public View child;
8216
8217 // The next target in the target list.
8218 public HoverTarget next;
8219
8220 private HoverTarget() {
8221 }
8222
Alan Viverettea7b85e62016-01-22 10:14:02 -05008223 public static HoverTarget obtain(@NonNull View child) {
8224 if (child == null) {
8225 throw new IllegalArgumentException("child must be non-null");
8226 }
8227
Jeff Brown87b7f802011-06-21 18:35:45 -07008228 final HoverTarget target;
8229 synchronized (sRecycleLock) {
8230 if (sRecycleBin == null) {
8231 target = new HoverTarget();
8232 } else {
8233 target = sRecycleBin;
8234 sRecycleBin = target.next;
Alan Viverettea7b85e62016-01-22 10:14:02 -05008235 sRecycledCount--;
Jeff Brown87b7f802011-06-21 18:35:45 -07008236 target.next = null;
8237 }
8238 }
8239 target.child = child;
8240 return target;
8241 }
8242
8243 public void recycle() {
Alan Viverettea7b85e62016-01-22 10:14:02 -05008244 if (child == null) {
8245 throw new IllegalStateException("already recycled once");
8246 }
8247
Jeff Brown87b7f802011-06-21 18:35:45 -07008248 synchronized (sRecycleLock) {
8249 if (sRecycledCount < MAX_RECYCLED) {
8250 next = sRecycleBin;
8251 sRecycleBin = this;
8252 sRecycledCount += 1;
8253 } else {
8254 next = null;
8255 }
8256 child = null;
8257 }
8258 }
8259 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07008260
8261 /**
Svet Ganov2f8fb1f2017-03-13 00:21:04 -07008262 * Pooled class that to hold the children for autifill.
8263 */
8264 static class ChildListForAutoFill extends ArrayList<View> {
8265 private static final int MAX_POOL_SIZE = 32;
8266
8267 private static final Pools.SimplePool<ChildListForAutoFill> sPool =
8268 new Pools.SimplePool<>(MAX_POOL_SIZE);
8269
8270 public static ChildListForAutoFill obtain() {
8271 ChildListForAutoFill list = sPool.acquire();
8272 if (list == null) {
8273 list = new ChildListForAutoFill();
8274 }
8275 return list;
8276 }
8277
8278 public void recycle() {
8279 clear();
8280 sPool.release(this);
8281 }
8282 }
8283
8284 /**
Svetoslav Ganov42138042012-03-20 11:51:39 -07008285 * Pooled class that orderes the children of a ViewGroup from start
8286 * to end based on how they are laid out and the layout direction.
8287 */
8288 static class ChildListForAccessibility {
8289
8290 private static final int MAX_POOL_SIZE = 32;
8291
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08008292 private static final SynchronizedPool<ChildListForAccessibility> sPool =
8293 new SynchronizedPool<ChildListForAccessibility>(MAX_POOL_SIZE);
Svetoslav Ganov42138042012-03-20 11:51:39 -07008294
8295 private final ArrayList<View> mChildren = new ArrayList<View>();
8296
8297 private final ArrayList<ViewLocationHolder> mHolders = new ArrayList<ViewLocationHolder>();
8298
8299 public static ChildListForAccessibility obtain(ViewGroup parent, boolean sort) {
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08008300 ChildListForAccessibility list = sPool.acquire();
8301 if (list == null) {
8302 list = new ChildListForAccessibility();
Svetoslav Ganov42138042012-03-20 11:51:39 -07008303 }
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08008304 list.init(parent, sort);
8305 return list;
Svetoslav Ganov42138042012-03-20 11:51:39 -07008306 }
8307
8308 public void recycle() {
Svetoslav Ganov42138042012-03-20 11:51:39 -07008309 clear();
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08008310 sPool.release(this);
Svetoslav Ganov42138042012-03-20 11:51:39 -07008311 }
8312
8313 public int getChildCount() {
8314 return mChildren.size();
8315 }
8316
8317 public View getChildAt(int index) {
8318 return mChildren.get(index);
8319 }
8320
Svetoslav Ganov42138042012-03-20 11:51:39 -07008321 private void init(ViewGroup parent, boolean sort) {
8322 ArrayList<View> children = mChildren;
8323 final int childCount = parent.getChildCount();
8324 for (int i = 0; i < childCount; i++) {
8325 View child = parent.getChildAt(i);
8326 children.add(child);
8327 }
8328 if (sort) {
8329 ArrayList<ViewLocationHolder> holders = mHolders;
8330 for (int i = 0; i < childCount; i++) {
8331 View child = children.get(i);
8332 ViewLocationHolder holder = ViewLocationHolder.obtain(parent, child);
8333 holders.add(holder);
8334 }
Svetoslav88e447b2014-10-09 15:49:02 -07008335 sort(holders);
Svetoslav Ganov42138042012-03-20 11:51:39 -07008336 for (int i = 0; i < childCount; i++) {
8337 ViewLocationHolder holder = holders.get(i);
8338 children.set(i, holder.mView);
8339 holder.recycle();
8340 }
8341 holders.clear();
8342 }
8343 }
8344
Svetoslav88e447b2014-10-09 15:49:02 -07008345 private void sort(ArrayList<ViewLocationHolder> holders) {
8346 // This is gross but the least risky solution. The current comparison
8347 // strategy breaks transitivity but produces very good results. Coming
8348 // up with a new strategy requires time which we do not have, so ...
8349 try {
8350 ViewLocationHolder.setComparisonStrategy(
8351 ViewLocationHolder.COMPARISON_STRATEGY_STRIPE);
8352 Collections.sort(holders);
8353 } catch (IllegalArgumentException iae) {
8354 // Note that in practice this occurs extremely rarely in a couple
8355 // of pathological cases.
8356 ViewLocationHolder.setComparisonStrategy(
8357 ViewLocationHolder.COMPARISON_STRATEGY_LOCATION);
8358 Collections.sort(holders);
8359 }
8360 }
8361
Svetoslav Ganov42138042012-03-20 11:51:39 -07008362 private void clear() {
8363 mChildren.clear();
8364 }
8365 }
8366
8367 /**
8368 * Pooled class that holds a View and its location with respect to
8369 * a specified root. This enables sorting of views based on their
8370 * coordinates without recomputing the position relative to the root
8371 * on every comparison.
8372 */
8373 static class ViewLocationHolder implements Comparable<ViewLocationHolder> {
8374
8375 private static final int MAX_POOL_SIZE = 32;
8376
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08008377 private static final SynchronizedPool<ViewLocationHolder> sPool =
8378 new SynchronizedPool<ViewLocationHolder>(MAX_POOL_SIZE);
Svetoslav Ganov42138042012-03-20 11:51:39 -07008379
Svetoslav88e447b2014-10-09 15:49:02 -07008380 public static final int COMPARISON_STRATEGY_STRIPE = 1;
8381
8382 public static final int COMPARISON_STRATEGY_LOCATION = 2;
8383
8384 private static int sComparisonStrategy = COMPARISON_STRATEGY_STRIPE;
8385
Svetoslav Ganov42138042012-03-20 11:51:39 -07008386 private final Rect mLocation = new Rect();
8387
8388 public View mView;
8389
8390 private int mLayoutDirection;
8391
8392 public static ViewLocationHolder obtain(ViewGroup root, View view) {
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08008393 ViewLocationHolder holder = sPool.acquire();
8394 if (holder == null) {
8395 holder = new ViewLocationHolder();
Svetoslav Ganov42138042012-03-20 11:51:39 -07008396 }
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08008397 holder.init(root, view);
8398 return holder;
Svetoslav Ganov42138042012-03-20 11:51:39 -07008399 }
8400
Svetoslav88e447b2014-10-09 15:49:02 -07008401 public static void setComparisonStrategy(int strategy) {
8402 sComparisonStrategy = strategy;
8403 }
8404
Svetoslav Ganov42138042012-03-20 11:51:39 -07008405 public void recycle() {
Svetoslav Ganov42138042012-03-20 11:51:39 -07008406 clear();
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08008407 sPool.release(this);
Svetoslav Ganov42138042012-03-20 11:51:39 -07008408 }
8409
8410 @Override
8411 public int compareTo(ViewLocationHolder another) {
8412 // This instance is greater than an invalid argument.
8413 if (another == null) {
8414 return 1;
8415 }
Svetoslav88e447b2014-10-09 15:49:02 -07008416
8417 if (sComparisonStrategy == COMPARISON_STRATEGY_STRIPE) {
8418 // First is above second.
8419 if (mLocation.bottom - another.mLocation.top <= 0) {
8420 return -1;
8421 }
8422 // First is below second.
8423 if (mLocation.top - another.mLocation.bottom >= 0) {
8424 return 1;
8425 }
8426 }
8427
Svetoslav04cab1b2014-08-25 18:35:57 -07008428 // We are ordering left-to-right, top-to-bottom.
Svetoslav Ganov42138042012-03-20 11:51:39 -07008429 if (mLayoutDirection == LAYOUT_DIRECTION_LTR) {
8430 final int leftDifference = mLocation.left - another.mLocation.left;
Svetoslav Ganov42138042012-03-20 11:51:39 -07008431 if (leftDifference != 0) {
8432 return leftDifference;
8433 }
8434 } else { // RTL
8435 final int rightDifference = mLocation.right - another.mLocation.right;
Svetoslav Ganov42138042012-03-20 11:51:39 -07008436 if (rightDifference != 0) {
8437 return -rightDifference;
8438 }
8439 }
Svetoslav04cab1b2014-08-25 18:35:57 -07008440 // We are ordering left-to-right, top-to-bottom.
8441 final int topDifference = mLocation.top - another.mLocation.top;
8442 if (topDifference != 0) {
8443 return topDifference;
8444 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07008445 // Break tie by height.
8446 final int heightDiference = mLocation.height() - another.mLocation.height();
8447 if (heightDiference != 0) {
8448 return -heightDiference;
8449 }
8450 // Break tie by width.
8451 final int widthDiference = mLocation.width() - another.mLocation.width();
8452 if (widthDiference != 0) {
8453 return -widthDiference;
8454 }
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07008455 // Just break the tie somehow. The accessibliity ids are unique
8456 // and stable, hence this is deterministic tie breaking.
8457 return mView.getAccessibilityViewId() - another.mView.getAccessibilityViewId();
Svetoslav Ganov42138042012-03-20 11:51:39 -07008458 }
8459
8460 private void init(ViewGroup root, View view) {
8461 Rect viewLocation = mLocation;
8462 view.getDrawingRect(viewLocation);
8463 root.offsetDescendantRectToMyCoords(view, viewLocation);
8464 mView = view;
Fabrice Di Meglioe56ffdc2012-09-23 14:51:16 -07008465 mLayoutDirection = root.getLayoutDirection();
Svetoslav Ganov42138042012-03-20 11:51:39 -07008466 }
8467
8468 private void clear() {
8469 mView = null;
8470 mLocation.set(0, 0, 0, 0);
8471 }
8472 }
Romain Guycbc67742012-04-27 16:12:57 -07008473
Romain Guy6410c0a2013-06-17 11:21:58 -07008474 private static void drawRect(Canvas canvas, Paint paint, int x1, int y1, int x2, int y2) {
Romain Guycbc67742012-04-27 16:12:57 -07008475 if (sDebugLines== null) {
Romain Guy6410c0a2013-06-17 11:21:58 -07008476 // TODO: This won't work with multiple UI threads in a single process
Romain Guycbc67742012-04-27 16:12:57 -07008477 sDebugLines = new float[16];
8478 }
8479
Romain Guycbc67742012-04-27 16:12:57 -07008480 sDebugLines[0] = x1;
8481 sDebugLines[1] = y1;
8482 sDebugLines[2] = x2;
8483 sDebugLines[3] = y1;
8484
8485 sDebugLines[4] = x2;
8486 sDebugLines[5] = y1;
8487 sDebugLines[6] = x2;
Philip Milne7b757812012-09-19 18:13:44 -07008488 sDebugLines[7] = y2;
Romain Guycbc67742012-04-27 16:12:57 -07008489
Philip Milne7b757812012-09-19 18:13:44 -07008490 sDebugLines[8] = x2;
Romain Guycbc67742012-04-27 16:12:57 -07008491 sDebugLines[9] = y2;
8492 sDebugLines[10] = x1;
8493 sDebugLines[11] = y2;
8494
Philip Milne7b757812012-09-19 18:13:44 -07008495 sDebugLines[12] = x1;
8496 sDebugLines[13] = y2;
Romain Guycbc67742012-04-27 16:12:57 -07008497 sDebugLines[14] = x1;
8498 sDebugLines[15] = y1;
8499
Philip Milne7b757812012-09-19 18:13:44 -07008500 canvas.drawLines(sDebugLines, paint);
Romain Guycbc67742012-04-27 16:12:57 -07008501 }
Siva Velusamy0d857b92015-04-22 10:23:56 -07008502
8503 /** @hide */
8504 @Override
8505 protected void encodeProperties(@NonNull ViewHierarchyEncoder encoder) {
8506 super.encodeProperties(encoder);
8507
8508 encoder.addProperty("focus:descendantFocusability", getDescendantFocusability());
8509 encoder.addProperty("drawing:clipChildren", getClipChildren());
8510 encoder.addProperty("drawing:clipToPadding", getClipToPadding());
8511 encoder.addProperty("drawing:childrenDrawingOrderEnabled", isChildrenDrawingOrderEnabled());
8512 encoder.addProperty("drawing:persistentDrawingCache", getPersistentDrawingCache());
8513
8514 int n = getChildCount();
8515 encoder.addProperty("meta:__childCount__", (short)n);
8516 for (int i = 0; i < n; i++) {
8517 encoder.addPropertyKey("meta:__child__" + i);
8518 getChildAt(i).encode(encoder);
8519 }
8520 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008521}