ViewGroup.java revision 1d9648df5198cbc47ecb836ce084e9258624e0d2
1b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/* 2b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Copyright (C) 2006 The Android Open Source Project 3fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius * 4b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Licensed under the Apache License, Version 2.0 (the "License"); 5b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * you may not use this file except in compliance with the License. 6b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * You may obtain a copy of the License at 7b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * 8b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * http://www.apache.org/licenses/LICENSE-2.0 9b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * 10b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Unless required by applicable law or agreed to in writing, software 11b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * distributed under the License is distributed on an "AS IS" BASIS, 12b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * See the License for the specific language governing permissions and 14b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * limitations under the License. 15b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 16b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 17b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querupackage android.view; 18b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 19b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruimport android.animation.LayoutTransition; 2050294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehoimport android.content.Context; 21b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruimport android.content.res.Configuration; 22b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruimport android.content.res.TypedArray; 23b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruimport android.graphics.Bitmap; 24b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruimport android.graphics.Canvas; 25b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruimport android.graphics.Color; 26b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruimport android.graphics.Insets; 27b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruimport android.graphics.Matrix; 28b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruimport android.graphics.Paint; 29b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruimport android.graphics.PointF; 30b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruimport android.graphics.Rect; 31b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruimport android.graphics.RectF; 32b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruimport android.graphics.Region; 33b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruimport android.os.Build; 34b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruimport android.os.Parcelable; 35b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruimport android.os.SystemClock; 36b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruimport android.util.AttributeSet; 37b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruimport android.util.Log; 38b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruimport android.util.Pools.SynchronizedPool; 39c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queruimport android.util.SparseArray; 40b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruimport android.view.accessibility.AccessibilityEvent; 41b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruimport android.view.accessibility.AccessibilityNodeInfo; 42b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruimport android.view.animation.Animation; 43b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruimport android.view.animation.AnimationUtils; 4450294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehoimport android.view.animation.LayoutAnimationController; 4550294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehoimport android.view.animation.Transformation; 4650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 47b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruimport com.android.internal.R; 48b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruimport com.android.internal.util.Predicate; 49b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 50b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruimport java.util.ArrayList; 51b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruimport java.util.Collections; 52b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruimport java.util.HashSet; 53b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 54b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruimport static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1; 55b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 56c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru/** 57b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * <p> 58b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * A <code>ViewGroup</code> is a special view that can contain other views 59b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * (called children.) The view group is the base class for layouts and views 6027f654740f2a26ad62a5c155af9199af9e69b889claireho * containers. This class also defines the 61b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * {@link android.view.ViewGroup.LayoutParams} class which serves as the base 6250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * class for layouts parameters. 6350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * </p> 6450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * 6550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * <p> 66b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Also see {@link LayoutParams} for layout attributes. 67b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * </p> 68b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * 69b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * <div class="special reference"> 70b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * <h3>Developer Guides</h3> 71b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * <p>For more information about creating user interface layouts, read the 72b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * <a href="{@docRoot}guide/topics/ui/declaring-layout.html">XML Layouts</a> developer 73b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * guide.</p></div> 74b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * 75b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * <p>Here is a complete implementation of a custom ViewGroup that implements 76b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * a simple {@link android.widget.FrameLayout} along with the ability to stack 77b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * children in left and right gutters.</p> 78b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * 79b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/CustomLayout.java 80b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Complete} 81b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * 82b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * <p>If you are implementing XML layout attributes as shown in the example, this is the 83b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * corresponding definition for them that would go in <code>res/values/attrs.xml</code>:</p> 84b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * 85b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * {@sample development/samples/ApiDemos/res/values/attrs.xml CustomLayout} 86b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * 87b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * <p>Finally the layout manager can be used in an XML layout like so:</p> 88b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * 89b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * {@sample development/samples/ApiDemos/res/layout/custom_layout.xml Complete} 90b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * 91b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @attr ref android.R.styleable#ViewGroup_clipChildren 92b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @attr ref android.R.styleable#ViewGroup_clipToPadding 93b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @attr ref android.R.styleable#ViewGroup_layoutAnimation 94b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @attr ref android.R.styleable#ViewGroup_animationCache 95b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @attr ref android.R.styleable#ViewGroup_persistentDrawingCache 96b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @attr ref android.R.styleable#ViewGroup_alwaysDrawnWithCache 97b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @attr ref android.R.styleable#ViewGroup_addStatesFromChildren 98b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @attr ref android.R.styleable#ViewGroup_descendantFocusability 99b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @attr ref android.R.styleable#ViewGroup_animateLayoutChanges 100b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 101b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querupublic abstract class ViewGroup extends View implements ViewParent, ViewManager { 102b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru private static final String TAG = "ViewGroup"; 103b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 104b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru private static final boolean DBG = false; 105b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru /** @hide */ 106b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru public static boolean DEBUG_DRAW = false; 107b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 108b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru /** 109b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Views which have been hidden or removed which need to be animated on 110b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * their way out. 111b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * This field should be made private, so it is hidden from the SDK. 112b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * {@hide} 113b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 114b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru protected ArrayList<View> mDisappearingChildren; 115b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 116b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru /** 117b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Listener used to propagate events indicating when children are added 118b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * and/or removed from a view group. 119b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * This field should be made private, so it is hidden from the SDK. 120b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * {@hide} 121b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 122b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru protected OnHierarchyChangeListener mOnHierarchyChangeListener; 123b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 124b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // The view contained within this ViewGroup that has or contains focus. 125b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru private View mFocused; 126b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 127b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru /** 128b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * A Transformation used when drawing children, to 129b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * apply on the child being drawn. 130b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 131b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru final Transformation mChildTransformation = new Transformation(); 132b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 133b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru /** 134b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Used to track the current invalidation region. 135b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 136b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru RectF mInvalidateRegion; 137b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 138b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru /** 139b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * A Transformation used to calculate a correct 140b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * invalidation area when the application is autoscaled. 141b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 142b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru Transformation mInvalidationTransformation; 143b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 144b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru // View currently under an ongoing drag 145b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru private View mCurrentDragView; 146b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 147b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru // Metadata about the ongoing drag 148b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru private DragEvent mCurrentDrag; 149b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru private HashSet<View> mDragNotifiedChildren; 150b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 151b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru // Does this group have a child that can accept the current drag payload? 152b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru private boolean mChildAcceptsDrag; 153b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 154b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru // Used during drag dispatch 155b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru private final PointF mLocalPoint = new PointF(); 156b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 157b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru // Layout animation 158b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru private LayoutAnimationController mLayoutAnimationController; 159b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru private Animation.AnimationListener mAnimationListener; 160b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 161b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru // First touch target in the linked list of touch targets. 162b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru private TouchTarget mFirstTouchTarget; 163b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 164b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru // For debugging only. You can see these in hierarchyviewer. 165b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"}) 166b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru @ViewDebug.ExportedProperty(category = "events") 167b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru private long mLastTouchDownTime; 168b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru @ViewDebug.ExportedProperty(category = "events") 169b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru private int mLastTouchDownIndex = -1; 170b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"}) 171b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru @ViewDebug.ExportedProperty(category = "events") 172b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru private float mLastTouchDownX; 173b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"}) 174b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru @ViewDebug.ExportedProperty(category = "events") 175b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru private float mLastTouchDownY; 176b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 177b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // First hover target in the linked list of hover targets. 178b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru // The hover targets are children which have received ACTION_HOVER_ENTER. 179b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru // They might not have actually handled the hover event, but we will 180b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru // continue sending hover events to them as long as the pointer remains over 181b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru // their bounds and the view group does not intercept hover. 182b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru private HoverTarget mFirstHoverTarget; 183b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 184b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru // True if the view group itself received a hover event. 185b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru // It might not have actually handled the hover event. 186b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru private boolean mHoveredSelf; 187b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 188b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru /** 189b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * Internal flags. 190b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * 191b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * This field should be made private, so it is hidden from the SDK. 192b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * {@hide} 193b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru */ 194b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru @ViewDebug.ExportedProperty(flagMapping = { 195b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru @ViewDebug.FlagToString(mask = FLAG_CLIP_CHILDREN, equals = FLAG_CLIP_CHILDREN, 196b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru name = "CLIP_CHILDREN"), 197b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru @ViewDebug.FlagToString(mask = FLAG_CLIP_TO_PADDING, equals = FLAG_CLIP_TO_PADDING, 198b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru name = "CLIP_TO_PADDING"), 199b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru @ViewDebug.FlagToString(mask = FLAG_PADDING_NOT_NULL, equals = FLAG_PADDING_NOT_NULL, 200b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru name = "PADDING_NOT_NULL") 201b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru }) 202b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru protected int mGroupFlags; 203b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 204b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru /** 205b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Either {@link #LAYOUT_MODE_CLIP_BOUNDS} or {@link #LAYOUT_MODE_OPTICAL_BOUNDS}. 206b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru */ 207b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru private int mLayoutMode = LAYOUT_MODE_UNDEFINED; 208b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 209b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru /** 210b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * NOTE: If you change the flags below make sure to reflect the changes 211b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * the DisplayList class 212b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru */ 213b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 214b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru // When set, ViewGroup invalidates only the child's rectangle 215b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru // Set by default 216b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru static final int FLAG_CLIP_CHILDREN = 0x1; 217b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 218b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru // When set, ViewGroup excludes the padding area from the invalidate rectangle 219b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru // Set by default 220b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru private static final int FLAG_CLIP_TO_PADDING = 0x2; 221b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 222b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru // When set, dispatchDraw() will invoke invalidate(); this is set by drawChild() when 223b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru // a child needs to be invalidated and FLAG_OPTIMIZE_INVALIDATE is set 224b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru static final int FLAG_INVALIDATE_REQUIRED = 0x4; 225b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 226b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru // When set, dispatchDraw() will run the layout animation and unset the flag 227b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru private static final int FLAG_RUN_ANIMATION = 0x8; 228b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 229b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru // When set, there is either no layout animation on the ViewGroup or the layout 230b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // animation is over 231b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru // Set by default 232b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru static final int FLAG_ANIMATION_DONE = 0x10; 233b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 234b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru // If set, this ViewGroup has padding; if unset there is no padding and we don't need 235b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru // to clip it, even if FLAG_CLIP_TO_PADDING is set 236b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru private static final int FLAG_PADDING_NOT_NULL = 0x20; 237b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 238b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru // When set, this ViewGroup caches its children in a Bitmap before starting a layout animation 239b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru // Set by default 240b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru private static final int FLAG_ANIMATION_CACHE = 0x40; 241b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 242b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru // When set, this ViewGroup converts calls to invalidate(Rect) to invalidate() during a 243b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru // layout animation; this avoid clobbering the hierarchy 244b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru // Automatically set when the layout animation starts, depending on the animation's 245b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // characteristics 246b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru static final int FLAG_OPTIMIZE_INVALIDATE = 0x80; 247b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 248b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru // When set, the next call to drawChild() will clear mChildTransformation's matrix 249b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru static final int FLAG_CLEAR_TRANSFORMATION = 0x100; 250b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 251b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru // When set, this ViewGroup invokes mAnimationListener.onAnimationEnd() and removes 252b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru // the children's Bitmap caches if necessary 253b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // This flag is set when the layout animation is over (after FLAG_ANIMATION_DONE is set) 254b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru private static final int FLAG_NOTIFY_ANIMATION_LISTENER = 0x200; 255b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 256b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru /** 257b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * When set, the drawing method will call {@link #getChildDrawingOrder(int, int)} 258b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * to get the index of the child to draw for that iteration. 259b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * 260b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * @hide 261b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru */ 262b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru protected static final int FLAG_USE_CHILD_DRAWING_ORDER = 0x400; 263b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 264b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru /** 265b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * When set, this ViewGroup supports static transformations on children; this causes 266b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} to be 267b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * invoked when a child is drawn. 268b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * 269b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * Any subclass overriding 270b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} should 271b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * set this flags in {@link #mGroupFlags}. 272b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * 273b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * {@hide} 274b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru */ 275b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru protected static final int FLAG_SUPPORT_STATIC_TRANSFORMATIONS = 0x800; 276b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 277b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru // When the previous drawChild() invocation used an alpha value that was lower than 278b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru // 1.0 and set it in mCachePaint 279b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru static final int FLAG_ALPHA_LOWER_THAN_ONE = 0x1000; 280b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 281b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru /** 282b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * When set, this ViewGroup's drawable states also include those 283b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * of its children. 284b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru */ 285b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru private static final int FLAG_ADD_STATES_FROM_CHILDREN = 0x2000; 286b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 287b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru /** 288b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * When set, this ViewGroup tries to always draw its children using their drawing cache. 289b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru */ 290b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru static final int FLAG_ALWAYS_DRAWN_WITH_CACHE = 0x4000; 291b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 292b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru /** 293b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * When set, and if FLAG_ALWAYS_DRAWN_WITH_CACHE is not set, this ViewGroup will try to 294b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * draw its children with their drawing cache. 295b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru */ 296b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru static final int FLAG_CHILDREN_DRAWN_WITH_CACHE = 0x8000; 297b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 298b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru /** 299b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * When set, this group will go through its list of children to notify them of 300b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * any drawable state change. 301b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru */ 302b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru private static final int FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE = 0x10000; 303b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 304b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru private static final int FLAG_MASK_FOCUSABILITY = 0x60000; 305b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 306b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru /** 307b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * This view will get focus before any of its descendants. 308b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru */ 309b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru public static final int FOCUS_BEFORE_DESCENDANTS = 0x20000; 310b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 311b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru /** 312b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * This view will get focus only if none of its descendants want it. 313b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru */ 314b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru public static final int FOCUS_AFTER_DESCENDANTS = 0x40000; 315b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 316b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru /** 317b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * This view will block any of its descendants from getting focus, even 318b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * if they are focusable. 319b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru */ 320b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru public static final int FOCUS_BLOCK_DESCENDANTS = 0x60000; 321b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 322b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru /** 323b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * Used to map between enum in attrubutes and flag values. 324b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru */ 325b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru private static final int[] DESCENDANT_FOCUSABILITY_FLAGS = 326b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru {FOCUS_BEFORE_DESCENDANTS, FOCUS_AFTER_DESCENDANTS, 327b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru FOCUS_BLOCK_DESCENDANTS}; 328b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 329b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru /** 330b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * When set, this ViewGroup should not intercept touch events. 331b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * {@hide} 332b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru */ 333b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru protected static final int FLAG_DISALLOW_INTERCEPT = 0x80000; 334b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 335b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru /** 336b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * When set, this ViewGroup will split MotionEvents to multiple child Views when appropriate. 337b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru */ 338b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru private static final int FLAG_SPLIT_MOTION_EVENTS = 0x200000; 339b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 340b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru /** 341b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * When set, this ViewGroup will not dispatch onAttachedToWindow calls 342b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * to children when adding new views. This is used to prevent multiple 343b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * onAttached calls when a ViewGroup adds children in its own onAttached method. 344b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru */ 345b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru private static final int FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW = 0x400000; 346b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 347b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru /** 348b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * When true, indicates that a layoutMode has been explicitly set, either with 349b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * an explicit call to {@link #setLayoutMode(int)} in code or from an XML resource. 350b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * This distinguishes the situation in which a layout mode was inherited from 351b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * one of the ViewGroup's ancestors and cached locally. 352b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru */ 353b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru private static final int FLAG_LAYOUT_MODE_WAS_EXPLICITLY_SET = 0x800000; 354b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 355b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru /** 356b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * Indicates which types of drawing caches are to be kept in memory. 357b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * This field should be made private, so it is hidden from the SDK. 358b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * {@hide} 359b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru */ 360b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru protected int mPersistentDrawingCache; 361b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 362b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru /** 363b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * Used to indicate that no drawing cache should be kept in memory. 364b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru */ 365b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru public static final int PERSISTENT_NO_CACHE = 0x0; 366b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 367b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru /** 368b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * Used to indicate that the animation drawing cache should be kept in memory. 369b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru */ 370b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru public static final int PERSISTENT_ANIMATION_CACHE = 0x1; 371b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 372b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru /** 373b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * Used to indicate that the scrolling drawing cache should be kept in memory. 374b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru */ 375b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru public static final int PERSISTENT_SCROLLING_CACHE = 0x2; 376b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 377b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru /** 378b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * Used to indicate that all drawing caches should be kept in memory. 379b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru */ 380b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru public static final int PERSISTENT_ALL_CACHES = 0x3; 381b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 382b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru // Layout Modes 383b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 384b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru private static final int LAYOUT_MODE_UNDEFINED = -1; 385b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 386b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru /** 387b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * This constant is a {@link #setLayoutMode(int) layoutMode}. 388b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Clip bounds are the raw values of {@link #getLeft() left}, {@link #getTop() top}, 389b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * {@link #getRight() right} and {@link #getBottom() bottom}. 390b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru */ 391b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru public static final int LAYOUT_MODE_CLIP_BOUNDS = 0; 392b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 393b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru /** 394b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * This constant is a {@link #setLayoutMode(int) layoutMode}. 395b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * Optical bounds describe where a widget appears to be. They sit inside the clip 396b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * bounds which need to cover a larger area to allow other effects, 397b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * such as shadows and glows, to be drawn. 398b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru */ 399b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru public static final int LAYOUT_MODE_OPTICAL_BOUNDS = 1; 400b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 401b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru /** @hide */ 402b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru public static int LAYOUT_MODE_DEFAULT = LAYOUT_MODE_CLIP_BOUNDS; 403b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 404b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru /** 405b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * We clip to padding when FLAG_CLIP_TO_PADDING and FLAG_PADDING_NOT_NULL 406b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * are set at the same time. 407b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru */ 408b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru protected static final int CLIP_TO_PADDING_MASK = FLAG_CLIP_TO_PADDING | FLAG_PADDING_NOT_NULL; 409b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 410b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru // Index of the child's left position in the mLocation array 411b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru private static final int CHILD_LEFT_INDEX = 0; 412b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru // Index of the child's top position in the mLocation array 413b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru private static final int CHILD_TOP_INDEX = 1; 414b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 415b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru // Child views of this ViewGroup 416b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru private View[] mChildren; 417b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru // Number of valid children in the mChildren array, the rest should be null or not 418b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // considered as children 419b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru private int mChildrenCount; 420b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 421b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru // Whether layout calls are currently being suppressed, controlled by calls to 422b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru // suppressLayout() 423b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru boolean mSuppressLayout = false; 424b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 425b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru // Whether any layout calls have actually been suppressed while mSuppressLayout 426b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // has been true. This tracks whether we need to issue a requestLayout() when 427b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru // layout is later re-enabled. 428b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru private boolean mLayoutCalledWhileSuppressed = false; 429b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 430b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru private static final int ARRAY_INITIAL_CAPACITY = 12; 431b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru private static final int ARRAY_CAPACITY_INCREMENT = 12; 432b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 433b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru private static Paint sDebugPaint; 434b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru private static float[] sDebugLines; 435b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 436b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Used to draw cached views 437b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru Paint mCachePaint; 438b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 439b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru // Used to animate add/remove changes in layout 440b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru private LayoutTransition mTransition; 441b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 442b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru // The set of views that are currently being transitioned. This list is used to track views 443b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru // being removed that should not actually be removed from the parent yet because they are 444b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru // being animated. 445b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru private ArrayList<View> mTransitioningViews; 446b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 447b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru // List of children changing visibility. This is used to potentially keep rendering 448b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru // views during a transition when they otherwise would have become gone/invisible 449b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru private ArrayList<View> mVisibilityChangingChildren; 450b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 451b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru // Indicates how many of this container's child subtrees contain transient state 452b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru @ViewDebug.ExportedProperty(category = "layout") 453b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru private int mChildCountWithTransientState = 0; 454b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 455b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru public ViewGroup(Context context) { 456b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru super(context); 457b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru initViewGroup(); 458b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru } 459b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 460b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru public ViewGroup(Context context, AttributeSet attrs) { 461b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru super(context, attrs); 462b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru initViewGroup(); 463b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru initFromAttributes(context, attrs); 464b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru } 465b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 466b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru public ViewGroup(Context context, AttributeSet attrs, int defStyle) { 467b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru super(context, attrs, defStyle); 468b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru initViewGroup(); 469b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru initFromAttributes(context, attrs); 470b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru } 471b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 472b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru private boolean debugDraw() { 473b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru return DEBUG_DRAW || mAttachInfo != null && mAttachInfo.mDebugLayout; 474b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru } 475b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 476b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru private void initViewGroup() { 477b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // ViewGroup doesn't draw by default 478b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (!debugDraw()) { 479b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru setFlags(WILL_NOT_DRAW, DRAW_MASK); 480b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru } 481b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru mGroupFlags |= FLAG_CLIP_CHILDREN; 482b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru mGroupFlags |= FLAG_CLIP_TO_PADDING; 483b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru mGroupFlags |= FLAG_ANIMATION_DONE; 484b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru mGroupFlags |= FLAG_ANIMATION_CACHE; 485b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru mGroupFlags |= FLAG_ALWAYS_DRAWN_WITH_CACHE; 486b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 487b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB) { 488b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru mGroupFlags |= FLAG_SPLIT_MOTION_EVENTS; 489b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru } 490b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 491b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru setDescendantFocusability(FOCUS_BEFORE_DESCENDANTS); 492b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 493b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru mChildren = new View[ARRAY_INITIAL_CAPACITY]; 494b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru mChildrenCount = 0; 495b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 496b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru mPersistentDrawingCache = PERSISTENT_SCROLLING_CACHE; 497b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru } 498b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 499b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru private void initFromAttributes(Context context, AttributeSet attrs) { 500b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru TypedArray a = context.obtainStyledAttributes(attrs, 501b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru R.styleable.ViewGroup); 502b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru 503b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru final int N = a.getIndexCount(); 504b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for (int i = 0; i < N; i++) { 505b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int attr = a.getIndex(i); 506b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru switch (attr) { 507b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru case R.styleable.ViewGroup_clipChildren: 508b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru setClipChildren(a.getBoolean(attr, true)); 509b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru break; 510b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru case R.styleable.ViewGroup_clipToPadding: 511b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru setClipToPadding(a.getBoolean(attr, true)); 512b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru break; 513b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru case R.styleable.ViewGroup_animationCache: 514b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru setAnimationCacheEnabled(a.getBoolean(attr, true)); 515b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru break; 516b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru case R.styleable.ViewGroup_persistentDrawingCache: 517b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru setPersistentDrawingCache(a.getInt(attr, PERSISTENT_SCROLLING_CACHE)); 518b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru break; 519b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru case R.styleable.ViewGroup_addStatesFromChildren: 520b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru setAddStatesFromChildren(a.getBoolean(attr, false)); 521b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru break; 522b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru case R.styleable.ViewGroup_alwaysDrawnWithCache: 523b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru setAlwaysDrawnWithCacheEnabled(a.getBoolean(attr, true)); 524b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru break; 525b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru case R.styleable.ViewGroup_layoutAnimation: 526b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int id = a.getResourceId(attr, -1); 527b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (id > 0) { 528b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru setLayoutAnimation(AnimationUtils.loadLayoutAnimation(mContext, id)); 529b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 530b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru break; 531b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru case R.styleable.ViewGroup_descendantFocusability: 532b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru setDescendantFocusability(DESCENDANT_FOCUSABILITY_FLAGS[a.getInt(attr, 0)]); 533b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru break; 534b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru case R.styleable.ViewGroup_splitMotionEvents: 535b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru setMotionEventSplittingEnabled(a.getBoolean(attr, false)); 536b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru break; 537b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru case R.styleable.ViewGroup_animateLayoutChanges: 538b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru boolean animateLayoutChanges = a.getBoolean(attr, false); 539b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (animateLayoutChanges) { 540b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru setLayoutTransition(new LayoutTransition()); 541b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 542b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru break; 543b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru case R.styleable.ViewGroup_layoutMode: 544b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru setLayoutMode(a.getInt(attr, LAYOUT_MODE_UNDEFINED)); 545b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru break; 546b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 547b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 548b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 549b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru a.recycle(); 550b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 551b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 552b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru /** 553b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * Gets the descendant focusability of this view group. The descendant 554b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * focusability defines the relationship between this view group and its 555b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * descendants when looking for a view to take focus in 556b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * {@link #requestFocus(int, android.graphics.Rect)}. 557b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * 558b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @return one of {@link #FOCUS_BEFORE_DESCENDANTS}, {@link #FOCUS_AFTER_DESCENDANTS}, 559b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * {@link #FOCUS_BLOCK_DESCENDANTS}. 560b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 561b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru @ViewDebug.ExportedProperty(category = "focus", mapping = { 562b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru @ViewDebug.IntToString(from = FOCUS_BEFORE_DESCENDANTS, to = "FOCUS_BEFORE_DESCENDANTS"), 563b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru @ViewDebug.IntToString(from = FOCUS_AFTER_DESCENDANTS, to = "FOCUS_AFTER_DESCENDANTS"), 564b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru @ViewDebug.IntToString(from = FOCUS_BLOCK_DESCENDANTS, to = "FOCUS_BLOCK_DESCENDANTS") 565b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru }) 566b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru public int getDescendantFocusability() { 567b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return mGroupFlags & FLAG_MASK_FOCUSABILITY; 568b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 569b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 570b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru /** 571b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Set the descendant focusability of this view group. This defines the relationship 572b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * between this view group and its descendants when looking for a view to 573b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * take focus in {@link #requestFocus(int, android.graphics.Rect)}. 574b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * 575b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @param focusability one of {@link #FOCUS_BEFORE_DESCENDANTS}, {@link #FOCUS_AFTER_DESCENDANTS}, 576b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * {@link #FOCUS_BLOCK_DESCENDANTS}. 577b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 578b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru public void setDescendantFocusability(int focusability) { 579b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru switch (focusability) { 580b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru case FOCUS_BEFORE_DESCENDANTS: 581b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru case FOCUS_AFTER_DESCENDANTS: 582b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru case FOCUS_BLOCK_DESCENDANTS: 583b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru break; 584b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru default: 585b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru throw new IllegalArgumentException("must be one of FOCUS_BEFORE_DESCENDANTS, " 586b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru + "FOCUS_AFTER_DESCENDANTS, FOCUS_BLOCK_DESCENDANTS"); 587b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 588b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru mGroupFlags &= ~FLAG_MASK_FOCUSABILITY; 589b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru mGroupFlags |= (focusability & FLAG_MASK_FOCUSABILITY); 590b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 591b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 592b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru /** 593b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * {@inheritDoc} 594b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 595b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru @Override 596b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru void handleFocusGainInternal(int direction, Rect previouslyFocusedRect) { 597b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (mFocused != null) { 598b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru mFocused.unFocus(); 599b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru mFocused = null; 600b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 601b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru super.handleFocusGainInternal(direction, previouslyFocusedRect); 602b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 603b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 604b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru /** 605b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * {@inheritDoc} 606b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 607b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru public void requestChildFocus(View child, View focused) { 608b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (DBG) { 609b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru System.out.println(this + " requestChildFocus()"); 610b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 611b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (getDescendantFocusability() == FOCUS_BLOCK_DESCENDANTS) { 612b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return; 613b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 614b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 615b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Unfocus us, if necessary 616b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru super.unFocus(); 617b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 618b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // We had a previous notion of who had focus. Clear it. 619b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (mFocused != child) { 620b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (mFocused != null) { 621b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru mFocused.unFocus(); 622b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 623b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 624b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru mFocused = child; 625b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 626b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (mParent != null) { 627b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru mParent.requestChildFocus(this, focused); 628b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 629b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru } 630b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 631b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru /** 632b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * {@inheritDoc} 633b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 634b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru public void focusableViewAvailable(View v) { 635b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (mParent != null 636b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // shortcut: don't report a new focusable view if we block our descendants from 637b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // getting focus 638b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru && (getDescendantFocusability() != FOCUS_BLOCK_DESCENDANTS) 639b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // shortcut: don't report a new focusable view if we already are focused 640b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // (and we don't prefer our descendants) 641b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // 642b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // note: knowing that mFocused is non-null is not a good enough reason 643b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // to break the traversal since in that case we'd actually have to find 644b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // the focused view and make sure it wasn't FOCUS_AFTER_DESCENDANTS and 645b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // an ancestor of v; this will get checked for at ViewAncestor 646b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru && !(isFocused() && getDescendantFocusability() != FOCUS_AFTER_DESCENDANTS)) { 647b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru mParent.focusableViewAvailable(v); 648b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 649b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 650b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 651b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru /** 652b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * {@inheritDoc} 653b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 654b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru public boolean showContextMenuForChild(View originalView) { 655b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return mParent != null && mParent.showContextMenuForChild(originalView); 656b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 657b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 658b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru /** 659b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * {@inheritDoc} 660b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 661b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback) { 662b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return mParent != null ? mParent.startActionModeForChild(originalView, callback) : null; 663b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 664b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 665b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru /** 666b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Find the nearest view in the specified direction that wants to take 667b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * focus. 668b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * 669b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @param focused The view that currently has focus 670b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and 671b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * FOCUS_RIGHT, or 0 for not applicable. 672b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 673b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru public View focusSearch(View focused, int direction) { 674b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (isRootNamespace()) { 675b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // root namespace means we should consider ourselves the top of the 676b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // tree for focus searching; otherwise we could be focus searching 677b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // into other tabs. see LocalActivityManager and TabHost for more info 678b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return FocusFinder.getInstance().findNextFocus(this, focused, direction); 679b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } else if (mParent != null) { 680b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return mParent.focusSearch(focused, direction); 681b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 682b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return null; 683b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 684b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 685b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru /** 686b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * {@inheritDoc} 687b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 688b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) { 689b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return false; 690b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 691b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 692b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru /** 693b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * {@inheritDoc} 694b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 695b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru @Override 696b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event) { 697b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru ViewParent parent = mParent; 698b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (parent == null) { 699b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return false; 700b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 701b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru final boolean propagate = onRequestSendAccessibilityEvent(child, event); 702b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (!propagate) { 703b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return false; 704b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 705b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return parent.requestSendAccessibilityEvent(this, event); 706b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 707b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 708b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru /** 709b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Called when a child has requested sending an {@link AccessibilityEvent} and 710b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * gives an opportunity to its parent to augment the event. 711b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * <p> 712b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * If an {@link android.view.View.AccessibilityDelegate} has been specified via calling 713b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * {@link android.view.View#setAccessibilityDelegate(android.view.View.AccessibilityDelegate)} its 714b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * {@link android.view.View.AccessibilityDelegate#onRequestSendAccessibilityEvent(ViewGroup, View, AccessibilityEvent)} 715b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * is responsible for handling this call. 716b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * </p> 717b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * 718b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @param child The child which requests sending the event. 719b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @param event The event to be sent. 720b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @return True if the event should be sent. 721b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * 722b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @see #requestSendAccessibilityEvent(View, AccessibilityEvent) 723b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 724b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) { 725b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (mAccessibilityDelegate != null) { 726b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return mAccessibilityDelegate.onRequestSendAccessibilityEvent(this, child, event); 727b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } else { 728b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return onRequestSendAccessibilityEventInternal(child, event); 729b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 730b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 731b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 732b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru /** 733b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @see #onRequestSendAccessibilityEvent(View, AccessibilityEvent) 734b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * 735b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Note: Called from the default {@link View.AccessibilityDelegate}. 736b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 737b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru boolean onRequestSendAccessibilityEventInternal(View child, AccessibilityEvent event) { 738b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return true; 739b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 740b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 741b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru /** 742b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Called when a child view has changed whether or not it is tracking transient state. 743b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * 744b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @hide 745b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 746b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru public void childHasTransientStateChanged(View child, boolean childHasTransientState) { 747b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru final boolean oldHasTransientState = hasTransientState(); 748b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (childHasTransientState) { 749b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru mChildCountWithTransientState++; 750b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } else { 751b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru mChildCountWithTransientState--; 752b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 753b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 754b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru final boolean newHasTransientState = hasTransientState(); 755b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (mParent != null && oldHasTransientState != newHasTransientState) { 756b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru try { 757b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru mParent.childHasTransientStateChanged(this, newHasTransientState); 758b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } catch (AbstractMethodError e) { 759b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru Log.e(TAG, mParent.getClass().getSimpleName() + 760b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru " does not fully implement ViewParent", e); 761b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 762b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 763b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 764b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 765b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru /** 766b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @hide 767b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 768b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru @Override 769b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru public boolean hasTransientState() { 770b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return mChildCountWithTransientState > 0 || super.hasTransientState(); 771b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 772b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 773b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru /** 774b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * {@inheritDoc} 775b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 776b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru @Override 777b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru public boolean dispatchUnhandledMove(View focused, int direction) { 778b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return mFocused != null && 779b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru mFocused.dispatchUnhandledMove(focused, direction); 780b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 781b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 782b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru /** 783b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * {@inheritDoc} 784b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 785b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru public void clearChildFocus(View child) { 786b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (DBG) { 787b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru System.out.println(this + " clearChildFocus()"); 788b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 789b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 790b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru mFocused = null; 791b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (mParent != null) { 792b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru mParent.clearChildFocus(this); 793b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 794b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 795b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 796b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru /** 797b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * {@inheritDoc} 798b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 799b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru @Override 800b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru public void clearFocus() { 801b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (DBG) { 802b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru System.out.println(this + " clearFocus()"); 803b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 804b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (mFocused == null) { 805b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru super.clearFocus(); 806b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } else { 807b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru View focused = mFocused; 808b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru mFocused = null; 809b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru focused.clearFocus(); 810b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 811b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 812b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 813b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru /** 814b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * {@inheritDoc} 815b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 816b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru @Override 817b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru void unFocus() { 818b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (DBG) { 819b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru System.out.println(this + " unFocus()"); 820b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 821b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (mFocused == null) { 822b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru super.unFocus(); 823b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } else { 824b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru mFocused.unFocus(); 825b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru mFocused = null; 826b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 827b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 828b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 829b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru /** 830b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Returns the focused child of this view, if any. The child may have focus 831b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * or contain focus. 832b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * 833b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @return the focused child or null. 834b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 835b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru public View getFocusedChild() { 836b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return mFocused; 837b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 838b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 839b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru /** 840b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Returns true if this view has or contains focus 841b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * 842b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @return true if this view has or contains focus 843b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 844b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru @Override 845b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru public boolean hasFocus() { 846b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return (mPrivateFlags & PFLAG_FOCUSED) != 0 || mFocused != null; 847b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 848b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 84959d709d503bab6e2b61931737e662dd293b40578ccornelius /* 85059d709d503bab6e2b61931737e662dd293b40578ccornelius * (non-Javadoc) 85159d709d503bab6e2b61931737e662dd293b40578ccornelius * 85259d709d503bab6e2b61931737e662dd293b40578ccornelius * @see android.view.View#findFocus() 85359d709d503bab6e2b61931737e662dd293b40578ccornelius */ 854fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius @Override 85559d709d503bab6e2b61931737e662dd293b40578ccornelius public View findFocus() { 85659d709d503bab6e2b61931737e662dd293b40578ccornelius if (DBG) { 85759d709d503bab6e2b61931737e662dd293b40578ccornelius System.out.println("Find focus in " + this + ": flags=" 85859d709d503bab6e2b61931737e662dd293b40578ccornelius + isFocused() + ", child=" + mFocused); 85959d709d503bab6e2b61931737e662dd293b40578ccornelius } 86059d709d503bab6e2b61931737e662dd293b40578ccornelius 86159d709d503bab6e2b61931737e662dd293b40578ccornelius if (isFocused()) { 862b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return this; 863b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 864b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 865b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (mFocused != null) { 866b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return mFocused.findFocus(); 867b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 868b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return null; 869b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 870b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 871b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru /** 872b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * {@inheritDoc} 873b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 874b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru @Override 875b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru public boolean hasFocusable() { 876b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) { 877b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return false; 878b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 879b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 880b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (isFocusable()) { 881b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return true; 882c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru } 883c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru 884c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru final int descendantFocusability = getDescendantFocusability(); 885c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) { 886c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru final int count = mChildrenCount; 887c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru final View[] children = mChildren; 888c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru 889c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru for (int i = 0; i < count; i++) { 890c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru final View child = children[i]; 891c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru if (child.hasFocusable()) { 892c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru return true; 893c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru } 894c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru } 895c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru } 896c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru 897c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru return false; 898c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru } 899c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru 900c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru /** 901c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru * {@inheritDoc} 902c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru */ 903c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru @Override 904c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru public void addFocusables(ArrayList<View> views, int direction, int focusableMode) { 905c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru final int focusableCount = views.size(); 906c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru 907c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru final int descendantFocusability = getDescendantFocusability(); 908c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru 909c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) { 910c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru final int count = mChildrenCount; 911c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru final View[] children = mChildren; 912c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru 913c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru for (int i = 0; i < count; i++) { 914c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru final View child = children[i]; 915c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) { 916c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru child.addFocusables(views, direction, focusableMode); 917c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru } 918c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru } 919c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru } 920c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru 921c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru // we add ourselves (if focusable) in all cases except for when we are 922c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru // FOCUS_AFTER_DESCENDANTS and there are some descendants focusable. this is 923c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru // to avoid the focus search finding layouts when a more precise search 924c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru // among the focusable children would be more interesting. 925c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru if (descendantFocusability != FOCUS_AFTER_DESCENDANTS 926c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru // No focusable descendants 927c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru || (focusableCount == views.size())) { 928c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru super.addFocusables(views, direction, focusableMode); 929c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru } 930c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru } 931c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru 932b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru @Override 933b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru public void findViewsWithText(ArrayList<View> outViews, CharSequence text, int flags) { 934b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru super.findViewsWithText(outViews, text, flags); 935b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru final int childrenCount = mChildrenCount; 936b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru final View[] children = mChildren; 937b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for (int i = 0; i < childrenCount; i++) { 938b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru View child = children[i]; 939b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE 940b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru && (child.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) { 941b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru child.findViewsWithText(outViews, text, flags); 942b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 943b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 944b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 945b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 946b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru @Override 947b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru View findViewByAccessibilityIdTraversal(int accessibilityId) { 948b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru View foundView = super.findViewByAccessibilityIdTraversal(accessibilityId); 949b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (foundView != null) { 950b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return foundView; 951b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 952b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru final int childrenCount = mChildrenCount; 953b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru final View[] children = mChildren; 954b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for (int i = 0; i < childrenCount; i++) { 955b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru View child = children[i]; 956b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru foundView = child.findViewByAccessibilityIdTraversal(accessibilityId); 957b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (foundView != null) { 958b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return foundView; 959b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 960b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 961b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return null; 962b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 963b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 964b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru /** 965b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * {@inheritDoc} 966b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 967b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru @Override 968b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru public void dispatchWindowFocusChanged(boolean hasFocus) { 969b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru super.dispatchWindowFocusChanged(hasFocus); 970b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru final int count = mChildrenCount; 971b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru final View[] children = mChildren; 972b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for (int i = 0; i < count; i++) { 973b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru children[i].dispatchWindowFocusChanged(hasFocus); 974b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 975b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 976b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 977b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru /** 978b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * {@inheritDoc} 979b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 980b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru @Override 981b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru public void addTouchables(ArrayList<View> views) { 982b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru super.addTouchables(views); 983b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 984b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru final int count = mChildrenCount; 985b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru final View[] children = mChildren; 986b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 987b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for (int i = 0; i < count; i++) { 988b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru final View child = children[i]; 989b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) { 990b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru child.addTouchables(views); 991b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 992b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 993b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 994b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 995b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru /** 996b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @hide 997b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 998b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru @Override 999b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru public void makeOptionalFitsSystemWindows() { 1000b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru super.makeOptionalFitsSystemWindows(); 1001b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru final int count = mChildrenCount; 1002b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru final View[] children = mChildren; 1003b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for (int i = 0; i < count; i++) { 1004b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru children[i].makeOptionalFitsSystemWindows(); 1005b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1006b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1007b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1008b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru /** 1009b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * {@inheritDoc} 1010b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 1011b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru @Override 1012b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru public void dispatchDisplayHint(int hint) { 1013b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru super.dispatchDisplayHint(hint); 1014b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru final int count = mChildrenCount; 1015b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru final View[] children = mChildren; 1016b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for (int i = 0; i < count; i++) { 1017b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru children[i].dispatchDisplayHint(hint); 1018b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1019b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1020b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1021b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru /** 1022b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Called when a view's visibility has changed. Notify the parent to take any appropriate 1023b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * action. 1024b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * 1025b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @param child The view whose visibility has changed 1026b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @param oldVisibility The previous visibility value (GONE, INVISIBLE, or VISIBLE). 1027b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @param newVisibility The new visibility value (GONE, INVISIBLE, or VISIBLE). 1028b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @hide 1029b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 1030b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru protected void onChildVisibilityChanged(View child, int oldVisibility, int newVisibility) { 1031b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (mTransition != null) { 1032b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (newVisibility == VISIBLE) { 1033b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru mTransition.showChild(this, child, oldVisibility); 1034b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } else { 1035b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru mTransition.hideChild(this, child, newVisibility); 1036b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (mTransitioningViews != null && mTransitioningViews.contains(child)) { 1037b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Only track this on disappearing views - appearing views are already visible 1038b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // and don't need special handling during drawChild() 1039b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (mVisibilityChangingChildren == null) { 1040b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru mVisibilityChangingChildren = new ArrayList<View>(); 1041b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1042b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru mVisibilityChangingChildren.add(child); 1043b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru addDisappearingView(child); 1044b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1045b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1046b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1047b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1048b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // in all cases, for drags 1049b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (mCurrentDrag != null) { 1050b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (newVisibility == VISIBLE) { 1051b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru notifyChildOfDrag(child); 1052b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1053b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1054b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1055b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1056b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru /** 1057b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * {@inheritDoc} 1058b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 1059b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru @Override 1060b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru protected void dispatchVisibilityChanged(View changedView, int visibility) { 1061b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru super.dispatchVisibilityChanged(changedView, visibility); 1062b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru final int count = mChildrenCount; 1063b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru final View[] children = mChildren; 1064b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for (int i = 0; i < count; i++) { 1065b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru children[i].dispatchVisibilityChanged(changedView, visibility); 1066b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1067b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1068b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1069b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru /** 1070b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * {@inheritDoc} 1071b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 1072b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru @Override 1073b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru public void dispatchWindowVisibilityChanged(int visibility) { 1074b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru super.dispatchWindowVisibilityChanged(visibility); 1075b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru final int count = mChildrenCount; 1076b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru final View[] children = mChildren; 1077b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for (int i = 0; i < count; i++) { 1078b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru children[i].dispatchWindowVisibilityChanged(visibility); 1079b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1080b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1081b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1082b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru /** 1083b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * {@inheritDoc} 1084b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 1085b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru @Override 1086b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru public void dispatchConfigurationChanged(Configuration newConfig) { 1087b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru super.dispatchConfigurationChanged(newConfig); 1088b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru final int count = mChildrenCount; 1089b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru final View[] children = mChildren; 1090b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for (int i = 0; i < count; i++) { 1091b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru children[i].dispatchConfigurationChanged(newConfig); 1092b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1093b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1094b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1095b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru /** 1096b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * {@inheritDoc} 1097b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 1098b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru public void recomputeViewAttributes(View child) { 1099b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 1100b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru ViewParent parent = mParent; 1101b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (parent != null) parent.recomputeViewAttributes(this); 1102b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1103b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1104b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1105b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru @Override 1106b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru void dispatchCollectViewAttributes(AttachInfo attachInfo, int visibility) { 1107b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if ((visibility & VISIBILITY_MASK) == VISIBLE) { 1108b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru super.dispatchCollectViewAttributes(attachInfo, visibility); 1109b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru final int count = mChildrenCount; 1110b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru final View[] children = mChildren; 1111b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for (int i = 0; i < count; i++) { 1112b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru final View child = children[i]; 1113b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru child.dispatchCollectViewAttributes(attachInfo, 1114b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru visibility | (child.mViewFlags&VISIBILITY_MASK)); 1115b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1116b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1117b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1118b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1119b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru /** 1120b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * {@inheritDoc} 1121b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 1122b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru public void bringChildToFront(View child) { 1123b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int index = indexOfChild(child); 1124b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (index >= 0) { 1125b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru removeFromArray(index); 1126b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru addInArray(child, mChildrenCount); 1127b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru child.mParent = this; 1128b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1129b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1130b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1131b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru /** 1132b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * {@inheritDoc} 1133b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 1134b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // TODO: Write real docs 1135b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru @Override 1136b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru public boolean dispatchDragEvent(DragEvent event) { 1137b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru boolean retval = false; 1138b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru final float tx = event.mX; 1139b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru final float ty = event.mY; 1140b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1141b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru ViewRootImpl root = getViewRootImpl(); 1142b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1143b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Dispatch down the view hierarchy 1144b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru switch (event.mAction) { 1145b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru case DragEvent.ACTION_DRAG_STARTED: { 1146b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // clear state to recalculate which views we drag over 1147b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru mCurrentDragView = null; 1148b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1149b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Set up our tracking of drag-started notifications 1150b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru mCurrentDrag = DragEvent.obtain(event); 1151b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (mDragNotifiedChildren == null) { 1152b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru mDragNotifiedChildren = new HashSet<View>(); 1153b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } else { 1154b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru mDragNotifiedChildren.clear(); 1155b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1156b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1157b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Now dispatch down to our children, caching the responses 1158b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru mChildAcceptsDrag = false; 1159b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru final int count = mChildrenCount; 1160b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru final View[] children = mChildren; 1161b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for (int i = 0; i < count; i++) { 1162b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru final View child = children[i]; 1163b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru child.mPrivateFlags2 &= ~View.DRAG_MASK; 1164b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (child.getVisibility() == VISIBLE) { 1165b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru final boolean handled = notifyChildOfDrag(children[i]); 1166b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (handled) { 1167b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru mChildAcceptsDrag = true; 1168b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1169b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1170b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1171b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1172b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Return HANDLED if one of our children can accept the drag 1173b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (mChildAcceptsDrag) { 1174b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru retval = true; 1175b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1176b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } break; 1177b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1178b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru case DragEvent.ACTION_DRAG_ENDED: { 1179b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Release the bookkeeping now that the drag lifecycle has ended 1180b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (mDragNotifiedChildren != null) { 1181b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for (View child : mDragNotifiedChildren) { 1182b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // If a child was notified about an ongoing drag, it's told that it's over 1183b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru child.dispatchDragEvent(event); 1184b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru child.mPrivateFlags2 &= ~View.DRAG_MASK; 1185b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru child.refreshDrawableState(); 1186b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1187b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1188b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru mDragNotifiedChildren.clear(); 1189b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (mCurrentDrag != null) { 1190b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru mCurrentDrag.recycle(); 1191b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru mCurrentDrag = null; 1192b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1193b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 119450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 1195b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // We consider drag-ended to have been handled if one of our children 1196b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // had offered to handle the drag. 119750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (mChildAcceptsDrag) { 119850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho retval = true; 1199b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1200b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } break; 1201b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 120250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho case DragEvent.ACTION_DRAG_LOCATION: { 120350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // Find the [possibly new] drag target 1204b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru final View target = findFrontmostDroppableChildAt(event.mX, event.mY, mLocalPoint); 1205b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1206b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // If we've changed apparent drag target, tell the view root which view 1207b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // we're over now [for purposes of the eventual drag-recipient-changed 1208b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // notifications to the framework] and tell the new target that the drag 1209b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // has entered its bounds. The root will see setDragFocus() calls all 1210b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // the way down to the final leaf view that is handling the LOCATION event 1211b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // before reporting the new potential recipient to the framework. 1212b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (mCurrentDragView != target) { 1213b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru root.setDragFocus(target); 1214b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1215b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru final int action = event.mAction; 1216b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // If we've dragged off of a child view, send it the EXITED message 1217b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (mCurrentDragView != null) { 1218b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru final View view = mCurrentDragView; 1219b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru event.mAction = DragEvent.ACTION_DRAG_EXITED; 1220b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru view.dispatchDragEvent(event); 1221b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru view.mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED; 1222b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru view.refreshDrawableState(); 1223b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1224b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru mCurrentDragView = target; 1225b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1226b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // If we've dragged over a new child view, send it the ENTERED message 1227b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (target != null) { 1228b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru event.mAction = DragEvent.ACTION_DRAG_ENTERED; 1229b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru target.dispatchDragEvent(event); 1230b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru target.mPrivateFlags2 |= View.PFLAG2_DRAG_HOVERED; 1231b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru target.refreshDrawableState(); 1232b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1233b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru event.mAction = action; // restore the event's original state 1234b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1235b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1236b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Dispatch the actual drag location notice, localized into its coordinates 1237b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (target != null) { 1238b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru event.mX = mLocalPoint.x; 1239b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru event.mY = mLocalPoint.y; 1240b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1241b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru retval = target.dispatchDragEvent(event); 1242b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1243b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru event.mX = tx; 1244b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru event.mY = ty; 1245b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1246b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } break; 1247b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1248b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru /* Entered / exited dispatch 1249b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * 1250b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * DRAG_ENTERED is not dispatched downwards from ViewGroup. The reason for this is 1251b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * that we're about to get the corresponding LOCATION event, which we will use to 1252b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * determine which of our children is the new target; at that point we will 1253b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * push a DRAG_ENTERED down to the new target child [which may itself be a ViewGroup]. 1254b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * 1255b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * DRAG_EXITED *is* dispatched all the way down immediately: once we know the 1256b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * drag has left this ViewGroup, we know by definition that every contained subview 1257b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * is also no longer under the drag point. 1258b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 1259b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1260b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru case DragEvent.ACTION_DRAG_EXITED: { 1261b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (mCurrentDragView != null) { 1262b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru final View view = mCurrentDragView; 1263b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru view.dispatchDragEvent(event); 1264b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru view.mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED; 1265b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru view.refreshDrawableState(); 1266b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1267b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru mCurrentDragView = null; 1268b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1269b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } break; 1270b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1271b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru case DragEvent.ACTION_DROP: { 1272b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (ViewDebug.DEBUG_DRAG) Log.d(View.VIEW_LOG_TAG, "Drop event: " + event); 1273b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru View target = findFrontmostDroppableChildAt(event.mX, event.mY, mLocalPoint); 1274b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (target != null) { 1275b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (ViewDebug.DEBUG_DRAG) Log.d(View.VIEW_LOG_TAG, " dispatch drop to " + target); 1276b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru event.mX = mLocalPoint.x; 1277b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru event.mY = mLocalPoint.y; 1278b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru retval = target.dispatchDragEvent(event); 1279b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru event.mX = tx; 1280b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru event.mY = ty; 1281b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } else { 1282b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru if (ViewDebug.DEBUG_DRAG) { 1283b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru Log.d(View.VIEW_LOG_TAG, " not dropped on an accepting view"); 1284b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1285b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1286b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } break; 1287b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1288b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1289b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // If none of our children could handle the event, try here 1290b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (!retval) { 1291b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Call up to the View implementation that dispatches to installed listeners 1292b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru retval = super.dispatchDragEvent(event); 1293b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1294b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return retval; 1295b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1296b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1297b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Find the frontmost child view that lies under the given point, and calculate 1298b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // the position within its own local coordinate system. 1299b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru View findFrontmostDroppableChildAt(float x, float y, PointF outLocalPoint) { 1300b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru final int count = mChildrenCount; 1301b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru final View[] children = mChildren; 1302b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for (int i = count - 1; i >= 0; i--) { 1303b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru final View child = children[i]; 1304b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (!child.canAcceptDrag()) { 1305b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru continue; 1306b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1307b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1308b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (isTransformedTouchPointInView(x, y, child, outLocalPoint)) { 1309b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return child; 1310b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1311b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1312b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return null; 1313b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1314b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1315b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru boolean notifyChildOfDrag(View child) { 1316b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (ViewDebug.DEBUG_DRAG) { 1317b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru Log.d(View.VIEW_LOG_TAG, "Sending drag-started to view: " + child); 1318b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1319b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1320b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru boolean canAccept = false; 1321b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (! mDragNotifiedChildren.contains(child)) { 1322b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru mDragNotifiedChildren.add(child); 1323b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru canAccept = child.dispatchDragEvent(mCurrentDrag); 1324b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (canAccept && !child.canAcceptDrag()) { 1325b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru child.mPrivateFlags2 |= View.PFLAG2_DRAG_CAN_ACCEPT; 1326b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru child.refreshDrawableState(); 1327b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru } 1328b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1329b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return canAccept; 1330b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1331b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1332b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru @Override 1333b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru public void dispatchWindowSystemUiVisiblityChanged(int visible) { 1334b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru super.dispatchWindowSystemUiVisiblityChanged(visible); 1335b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1336b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru final int count = mChildrenCount; 1337b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru final View[] children = mChildren; 1338b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for (int i=0; i <count; i++) { 1339b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru final View child = children[i]; 1340b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru child.dispatchWindowSystemUiVisiblityChanged(visible); 1341b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1342b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1343b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1344b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru @Override 1345b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru public void dispatchSystemUiVisibilityChanged(int visible) { 1346b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru super.dispatchSystemUiVisibilityChanged(visible); 1347b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1348b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru final int count = mChildrenCount; 1349b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru final View[] children = mChildren; 1350b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for (int i=0; i <count; i++) { 1351b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru final View child = children[i]; 1352b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru child.dispatchSystemUiVisibilityChanged(visible); 1353b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1354b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1355b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1356b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru @Override 1357b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru boolean updateLocalSystemUiVisibility(int localValue, int localChanges) { 1358b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru boolean changed = super.updateLocalSystemUiVisibility(localValue, localChanges); 1359b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1360b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru final int count = mChildrenCount; 1361b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru final View[] children = mChildren; 1362b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for (int i=0; i <count; i++) { 1363b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru final View child = children[i]; 1364b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru changed |= child.updateLocalSystemUiVisibility(localValue, localChanges); 1365b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1366b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return changed; 1367b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1368b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1369b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru /** 1370b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * {@inheritDoc} 1371b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 1372b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru @Override 1373b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru public boolean dispatchKeyEventPreIme(KeyEvent event) { 1374b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) 1375b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) { 1376b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return super.dispatchKeyEventPreIme(event); 1377b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS) 1378b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru == PFLAG_HAS_BOUNDS) { 1379b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return mFocused.dispatchKeyEventPreIme(event); 1380b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1381b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return false; 1382b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1383b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1384b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru /** 1385b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * {@inheritDoc} 1386b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 1387b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru @Override 1388b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru public boolean dispatchKeyEvent(KeyEvent event) { 1389b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (mInputEventConsistencyVerifier != null) { 1390b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru mInputEventConsistencyVerifier.onKeyEvent(event, 1); 1391b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1392b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1393b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) 1394b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) { 1395b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (super.dispatchKeyEvent(event)) { 1396b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return true; 1397b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1398b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS) 1399b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru == PFLAG_HAS_BOUNDS) { 1400b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (mFocused.dispatchKeyEvent(event)) { 1401b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return true; 1402b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1403b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1404b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1405b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (mInputEventConsistencyVerifier != null) { 1406b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru mInputEventConsistencyVerifier.onUnhandledEvent(event, 1); 1407b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1408b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return false; 1409b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1410b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1411b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru /** 1412b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * {@inheritDoc} 1413b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 1414b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru @Override 1415b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru public boolean dispatchKeyShortcutEvent(KeyEvent event) { 1416b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) 1417b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) { 1418b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return super.dispatchKeyShortcutEvent(event); 1419b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS) 142059d709d503bab6e2b61931737e662dd293b40578ccornelius == PFLAG_HAS_BOUNDS) { 1421b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return mFocused.dispatchKeyShortcutEvent(event); 1422b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1423b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return false; 1424b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1425b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1426b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru /** 1427b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * {@inheritDoc} 1428b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 1429b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru @Override 1430b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru public boolean dispatchTrackballEvent(MotionEvent event) { 1431b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (mInputEventConsistencyVerifier != null) { 1432b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru mInputEventConsistencyVerifier.onTrackballEvent(event, 1); 1433b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1434b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1435b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) 1436b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) { 1437b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (super.dispatchTrackballEvent(event)) { 1438b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return true; 1439b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1440b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS) 1441b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru == PFLAG_HAS_BOUNDS) { 1442b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (mFocused.dispatchTrackballEvent(event)) { 1443b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return true; 1444b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1445b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1446b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1447b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (mInputEventConsistencyVerifier != null) { 1448b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru mInputEventConsistencyVerifier.onUnhandledEvent(event, 1); 1449b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho } 1450b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho return false; 1451b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1452c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru 1453b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru /** 1454b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * {@inheritDoc} 1455b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 1456b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru @SuppressWarnings({"ConstantConditions"}) 1457b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru @Override 1458b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru protected boolean dispatchHoverEvent(MotionEvent event) { 1459b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru final int action = event.getAction(); 1460b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1461b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // First check whether the view group wants to intercept the hover event. 1462b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru final boolean interceptHover = onInterceptHoverEvent(event); 1463b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru event.setAction(action); // restore action in case it was changed 1464b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho 1465b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho MotionEvent eventNoHistory = event; 1466b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho boolean handled = false; 1467b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho 1468b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho // Send events to the hovered children and build a new list of hover targets until 1469b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho // one is found that handles the event. 1470b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho HoverTarget firstOldHoverTarget = mFirstHoverTarget; 1471b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho mFirstHoverTarget = null; 1472b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho if (!interceptHover && action != MotionEvent.ACTION_HOVER_EXIT) { 1473b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho final float x = event.getX(); 1474b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho final float y = event.getY(); 1475b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru final int childrenCount = mChildrenCount; 1476b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho if (childrenCount != 0) { 1477b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru final View[] children = mChildren; 1478b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru HoverTarget lastHoverTarget = null; 1479b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for (int i = childrenCount - 1; i >= 0; i--) { 1480b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru final View child = children[i]; 1481b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (!canViewReceivePointerEvents(child) 1482b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru || !isTransformedTouchPointInView(x, y, child, null)) { 1483b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho continue; 1484b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1485b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1486b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho // Obtain a hover target for this child. Dequeue it from the 1487b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // old hover target list if the child was previously hovered. 1488b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho HoverTarget hoverTarget = firstOldHoverTarget; 1489b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho final boolean wasHovered; 1490b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho for (HoverTarget predecessor = null; ;) { 1491b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho if (hoverTarget == null) { 1492b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho hoverTarget = HoverTarget.obtain(child); 1493b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho wasHovered = false; 1494b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho break; 1495b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1496b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho 1497b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho if (hoverTarget.child == child) { 1498b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho if (predecessor != null) { 1499b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru predecessor.next = hoverTarget.next; 1500b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } else { 1501b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru firstOldHoverTarget = hoverTarget.next; 1502b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho } 1503b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru hoverTarget.next = null; 1504b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru wasHovered = true; 1505b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru break; 1506b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1507b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1508b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru predecessor = hoverTarget; 1509b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru hoverTarget = hoverTarget.next; 1510b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1511b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1512b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Enqueue the hover target onto the new hover target list. 1513b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (lastHoverTarget != null) { 1514b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru lastHoverTarget.next = hoverTarget; 1515b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } else { 1516b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru lastHoverTarget = hoverTarget; 1517b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru mFirstHoverTarget = hoverTarget; 1518b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1519b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1520b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Dispatch the event to the child. 1521b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (action == MotionEvent.ACTION_HOVER_ENTER) { 152250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (!wasHovered) { 152350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // Send the enter as is. 152450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho handled |= dispatchTransformedGenericPointerEvent( 152550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho event, child); // enter 152650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 152750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } else if (action == MotionEvent.ACTION_HOVER_MOVE) { 152850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (!wasHovered) { 152950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // Synthesize an enter from a move. 153050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory); 153150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho eventNoHistory.setAction(MotionEvent.ACTION_HOVER_ENTER); 153250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho handled |= dispatchTransformedGenericPointerEvent( 153350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho eventNoHistory, child); // enter 153450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho eventNoHistory.setAction(action); 153550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 153650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho handled |= dispatchTransformedGenericPointerEvent( 153750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho eventNoHistory, child); // move 153850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } else { 153950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // Send the move as is. 154050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho handled |= dispatchTransformedGenericPointerEvent(event, child); 154150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 154250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 154350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (handled) { 154450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho break; 154550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 154650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 154750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 154850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 154950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 155050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // Send exit events to all previously hovered children that are no longer hovered. 155150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho while (firstOldHoverTarget != null) { 155250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho final View child = firstOldHoverTarget.child; 155350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 155450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // Exit the old hovered child. 155550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (action == MotionEvent.ACTION_HOVER_EXIT) { 155650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // Send the exit as is. 155750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho handled |= dispatchTransformedGenericPointerEvent( 155850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho event, child); // exit 155950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } else { 156050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // Synthesize an exit from a move or enter. 156150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // Ignore the result because hover focus has moved to a different view. 156250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (action == MotionEvent.ACTION_HOVER_MOVE) { 156350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho dispatchTransformedGenericPointerEvent( 156450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho event, child); // move 156550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 156650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory); 156750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho eventNoHistory.setAction(MotionEvent.ACTION_HOVER_EXIT); 156850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho dispatchTransformedGenericPointerEvent( 156950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho eventNoHistory, child); // exit 157050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho eventNoHistory.setAction(action); 157150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 157250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 157350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho final HoverTarget nextOldHoverTarget = firstOldHoverTarget.next; 157450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho firstOldHoverTarget.recycle(); 157550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho firstOldHoverTarget = nextOldHoverTarget; 157650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 157750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 157850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // Send events to the view group itself if no children have handled it. 157950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho boolean newHoveredSelf = !handled; 158050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (newHoveredSelf == mHoveredSelf) { 158150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (newHoveredSelf) { 158250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // Send event to the view group as before. 158350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho handled |= super.dispatchHoverEvent(event); 158450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 158550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } else { 158650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (mHoveredSelf) { 158750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // Exit the view group. 158850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (action == MotionEvent.ACTION_HOVER_EXIT) { 158950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // Send the exit as is. 159050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho handled |= super.dispatchHoverEvent(event); // exit 159150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } else { 159250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // Synthesize an exit from a move or enter. 159350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // Ignore the result because hover focus is moving to a different view. 159450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (action == MotionEvent.ACTION_HOVER_MOVE) { 159550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho super.dispatchHoverEvent(event); // move 159650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 159750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory); 159850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho eventNoHistory.setAction(MotionEvent.ACTION_HOVER_EXIT); 159950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho super.dispatchHoverEvent(eventNoHistory); // exit 160050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho eventNoHistory.setAction(action); 160150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 160250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho mHoveredSelf = false; 160350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 160450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 160550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (newHoveredSelf) { 160650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // Enter the view group. 160750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (action == MotionEvent.ACTION_HOVER_ENTER) { 160850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // Send the enter as is. 160950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho handled |= super.dispatchHoverEvent(event); // enter 161050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho mHoveredSelf = true; 161150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } else if (action == MotionEvent.ACTION_HOVER_MOVE) { 161250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // Synthesize an enter from a move. 161350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory); 161450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho eventNoHistory.setAction(MotionEvent.ACTION_HOVER_ENTER); 161550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho handled |= super.dispatchHoverEvent(eventNoHistory); // enter 161650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho eventNoHistory.setAction(action); 161750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 161850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho handled |= super.dispatchHoverEvent(eventNoHistory); // move 161950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho mHoveredSelf = true; 162050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 162150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 162250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 162350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 162450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // Recycle the copy of the event that we made. 162550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (eventNoHistory != event) { 162650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho eventNoHistory.recycle(); 162750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 162850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 162950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // Done. 163050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho return handled; 163150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 163250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 163350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho private void exitHoverTargets() { 163450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (mHoveredSelf || mFirstHoverTarget != null) { 163550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho final long now = SystemClock.uptimeMillis(); 163650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho MotionEvent event = MotionEvent.obtain(now, now, 163750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho MotionEvent.ACTION_HOVER_EXIT, 0.0f, 0.0f, 0); 163850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho event.setSource(InputDevice.SOURCE_TOUCHSCREEN); 163950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho dispatchHoverEvent(event); 164050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho event.recycle(); 164150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 164250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 164350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 164450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho private void cancelHoverTarget(View view) { 164550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho HoverTarget predecessor = null; 164650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho HoverTarget target = mFirstHoverTarget; 164750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho while (target != null) { 164850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho final HoverTarget next = target.next; 164950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (target.child == view) { 165050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (predecessor == null) { 165150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho mFirstHoverTarget = next; 165250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } else { 165350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho predecessor.next = next; 165450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 165550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho target.recycle(); 165650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 165750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho final long now = SystemClock.uptimeMillis(); 165850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho MotionEvent event = MotionEvent.obtain(now, now, 165950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho MotionEvent.ACTION_HOVER_EXIT, 0.0f, 0.0f, 0); 166050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho event.setSource(InputDevice.SOURCE_TOUCHSCREEN); 166150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho view.dispatchHoverEvent(event); 166250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho event.recycle(); 166350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho return; 166450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 166550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho predecessor = target; 166650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho target = next; 166750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 166850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 166950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 167050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho /** @hide */ 167150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho @Override 167250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho protected boolean hasHoveredChild() { 167350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho return mFirstHoverTarget != null; 167450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 167550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 167650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho @Override 167750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho public void addChildrenForAccessibility(ArrayList<View> childrenForAccessibility) { 167850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho ChildListForAccessibility children = ChildListForAccessibility.obtain(this, true); 167950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho try { 168050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho final int childrenCount = children.getChildCount(); 168150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho for (int i = 0; i < childrenCount; i++) { 168250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho View child = children.getChildAt(i); 168350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) { 168450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (child.includeForAccessibility()) { 168550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho childrenForAccessibility.add(child); 168650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } else { 168750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho child.addChildrenForAccessibility(childrenForAccessibility); 168850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 168950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 169050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 169150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } finally { 169250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho children.recycle(); 169350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 169450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 169550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 169650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho /** 169750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * @hide 169850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho */ 169950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho @Override 170050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho public void childAccessibilityStateChanged(View child) { 170150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (mParent != null) { 170250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho mParent.childAccessibilityStateChanged(child); 170350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 170450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 170550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 170650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho /** 170750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * Implement this method to intercept hover events before they are handled 170850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * by child views. 170950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * <p> 171050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * This method is called before dispatching a hover event to a child of 171150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * the view group or to the view group's own {@link #onHoverEvent} to allow 171250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * the view group a chance to intercept the hover event. 171350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * This method can also be used to watch all pointer motions that occur within 171450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * the bounds of the view group even when the pointer is hovering over 171550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * a child of the view group rather than over the view group itself. 171650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * </p><p> 171750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * The view group can prevent its children from receiving hover events by 171850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * implementing this method and returning <code>true</code> to indicate 171950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * that it would like to intercept hover events. The view group must 172050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * continuously return <code>true</code> from {@link #onInterceptHoverEvent} 172150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * for as long as it wishes to continue intercepting hover events from 172250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * its children. 172350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * </p><p> 172450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * Interception preserves the invariant that at most one view can be 172550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * hovered at a time by transferring hover focus from the currently hovered 172650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * child to the view group or vice-versa as needed. 172750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * </p><p> 172850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * If this method returns <code>true</code> and a child is already hovered, then the 172950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * child view will first receive a hover exit event and then the view group 173050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * itself will receive a hover enter event in {@link #onHoverEvent}. 173150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * Likewise, if this method had previously returned <code>true</code> to intercept hover 173250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * events and instead returns <code>false</code> while the pointer is hovering 173350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * within the bounds of one of a child, then the view group will first receive a 173450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * hover exit event in {@link #onHoverEvent} and then the hovered child will 173550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * receive a hover enter event. 173650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * </p><p> 173750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * The default implementation always returns false. 173850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * </p> 173950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * 174050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * @param event The motion event that describes the hover. 174150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * @return True if the view group would like to intercept the hover event 174250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * and prevent its children from receiving it. 174350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho */ 174450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho public boolean onInterceptHoverEvent(MotionEvent event) { 174550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho return false; 174650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 174750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 174850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho private static MotionEvent obtainMotionEventNoHistoryOrSelf(MotionEvent event) { 174950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (event.getHistorySize() == 0) { 175050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho return event; 175150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 175250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho return MotionEvent.obtainNoHistory(event); 175350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 175450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 175550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho /** 175650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * {@inheritDoc} 175750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho */ 175850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho @Override 175950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho protected boolean dispatchGenericPointerEvent(MotionEvent event) { 176050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // Send the event to the child under the pointer. 176150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho final int childrenCount = mChildrenCount; 176250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (childrenCount != 0) { 176350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho final View[] children = mChildren; 176450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho final float x = event.getX(); 176550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho final float y = event.getY(); 176650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 176750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho final boolean customOrder = isChildrenDrawingOrderEnabled(); 176850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho for (int i = childrenCount - 1; i >= 0; i--) { 176950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho final int childIndex = customOrder ? getChildDrawingOrder(childrenCount, i) : i; 177050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho final View child = children[childIndex]; 177150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (!canViewReceivePointerEvents(child) 177250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho || !isTransformedTouchPointInView(x, y, child, null)) { 177350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho continue; 177450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 177550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 177650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (dispatchTransformedGenericPointerEvent(event, child)) { 177750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho return true; 177850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 177950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 178050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 178150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 178250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // No child handled the event. Send it to this view group. 178350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho return super.dispatchGenericPointerEvent(event); 178450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 178550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 178650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho /** 178750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * {@inheritDoc} 178850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho */ 178950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho @Override 179050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho protected boolean dispatchGenericFocusedEvent(MotionEvent event) { 179150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // Send the event to the focused child or to this view group if it has focus. 179250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) 179350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) { 179450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho return super.dispatchGenericFocusedEvent(event); 179550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS) 179650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho == PFLAG_HAS_BOUNDS) { 179750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho return mFocused.dispatchGenericMotionEvent(event); 179850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 179950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho return false; 180050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 180150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 180250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho /** 180350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * Dispatches a generic pointer event to a child, taking into account 180450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * transformations that apply to the child. 180550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * 180650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * @param event The event to send. 180750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * @param child The view to send the event to. 180850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * @return {@code true} if the child handled the event. 180950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho */ 181050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho private boolean dispatchTransformedGenericPointerEvent(MotionEvent event, View child) { 181150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho final float offsetX = mScrollX - child.mLeft; 181250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho final float offsetY = mScrollY - child.mTop; 181350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 181450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho boolean handled; 181550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (!child.hasIdentityMatrix()) { 181650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho MotionEvent transformedEvent = MotionEvent.obtain(event); 181750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho transformedEvent.offsetLocation(offsetX, offsetY); 181850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho transformedEvent.transform(child.getInverseMatrix()); 181950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho handled = child.dispatchGenericMotionEvent(transformedEvent); 182050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho transformedEvent.recycle(); 182150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } else { 182250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho event.offsetLocation(offsetX, offsetY); 182350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho handled = child.dispatchGenericMotionEvent(event); 182450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho event.offsetLocation(-offsetX, -offsetY); 182550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 182650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho return handled; 182750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 182850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 182950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho /** 183050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * {@inheritDoc} 183150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho */ 183250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho @Override 183350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho public boolean dispatchTouchEvent(MotionEvent ev) { 183450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (mInputEventConsistencyVerifier != null) { 183550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho mInputEventConsistencyVerifier.onTouchEvent(ev, 1); 183650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 183750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 183850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho boolean handled = false; 183950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (onFilterTouchEventForSecurity(ev)) { 184050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho final int action = ev.getAction(); 184150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho final int actionMasked = action & MotionEvent.ACTION_MASK; 184250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 184350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // Handle an initial down. 184450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (actionMasked == MotionEvent.ACTION_DOWN) { 184550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // Throw away all previous state when starting a new touch gesture. 184650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // The framework may have dropped the up or cancel event for the previous gesture 184750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // due to an app switch, ANR, or some other state change. 184850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho cancelAndClearTouchTargets(ev); 184950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho resetTouchState(); 185050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 185150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 185250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // Check for interception. 185350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho final boolean intercepted; 185450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (actionMasked == MotionEvent.ACTION_DOWN 185550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho || mFirstTouchTarget != null) { 185650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0; 185750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (!disallowIntercept) { 185850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho intercepted = onInterceptTouchEvent(ev); 185950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho ev.setAction(action); // restore action in case it was changed 186050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } else { 186150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho intercepted = false; 186250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 186350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } else { 186450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // There are no touch targets and this action is not an initial down 186550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // so this view group continues to intercept touches. 186650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho intercepted = true; 186750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 186850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 186950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // Check for cancelation. 187050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho final boolean canceled = resetCancelNextUpFlag(this) 187150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho || actionMasked == MotionEvent.ACTION_CANCEL; 187250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 187350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // Update list of touch targets for pointer down, if needed. 187450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho final boolean split = (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) != 0; 187550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho TouchTarget newTouchTarget = null; 187650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho boolean alreadyDispatchedToNewTouchTarget = false; 187750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (!canceled && !intercepted) { 187850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (actionMasked == MotionEvent.ACTION_DOWN 187950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho || (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN) 188050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho || actionMasked == MotionEvent.ACTION_HOVER_MOVE) { 188150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho final int actionIndex = ev.getActionIndex(); // always 0 for down 188250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho final int idBitsToAssign = split ? 1 << ev.getPointerId(actionIndex) 188350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho : TouchTarget.ALL_POINTER_IDS; 188450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 188550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // Clean up earlier touch targets for this pointer id in case they 188650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // have become out of sync. 188750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho removePointersFromTouchTargets(idBitsToAssign); 188850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 188950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho final int childrenCount = mChildrenCount; 189050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (newTouchTarget == null && childrenCount != 0) { 189150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho final float x = ev.getX(actionIndex); 189250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho final float y = ev.getY(actionIndex); 189350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // Find a child that can receive the event. 189450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // Scan children from front to back. 189550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho final View[] children = mChildren; 189650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 189750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho final boolean customOrder = isChildrenDrawingOrderEnabled(); 189850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho for (int i = childrenCount - 1; i >= 0; i--) { 189950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho final int childIndex = customOrder ? 190050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho getChildDrawingOrder(childrenCount, i) : i; 190150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho final View child = children[childIndex]; 190250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (!canViewReceivePointerEvents(child) 190350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho || !isTransformedTouchPointInView(x, y, child, null)) { 190450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho continue; 190550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 190650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 190750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho newTouchTarget = getTouchTarget(child); 190850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (newTouchTarget != null) { 190950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // Child is already receiving touch within its bounds. 191050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // Give it the new pointer in addition to the ones it is handling. 191150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho newTouchTarget.pointerIdBits |= idBitsToAssign; 191250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho break; 191350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 191450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 191550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho resetCancelNextUpFlag(child); 191650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) { 191750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // Child wants to receive touch within its bounds. 191850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho mLastTouchDownTime = ev.getDownTime(); 191950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho mLastTouchDownIndex = childIndex; 192050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho mLastTouchDownX = ev.getX(); 192150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho mLastTouchDownY = ev.getY(); 192250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho newTouchTarget = addTouchTarget(child, idBitsToAssign); 192350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho alreadyDispatchedToNewTouchTarget = true; 192450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho break; 192550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 192650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 192750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 192850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 192950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (newTouchTarget == null && mFirstTouchTarget != null) { 193050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // Did not find a child to receive the event. 193150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // Assign the pointer to the least recently added target. 193250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho newTouchTarget = mFirstTouchTarget; 193350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho while (newTouchTarget.next != null) { 193450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho newTouchTarget = newTouchTarget.next; 193550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 193650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho newTouchTarget.pointerIdBits |= idBitsToAssign; 193750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 193850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 193950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 194050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 194150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // Dispatch to touch targets. 194250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (mFirstTouchTarget == null) { 194350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // No touch targets so treat this as an ordinary view. 194450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho handled = dispatchTransformedTouchEvent(ev, canceled, null, 194550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho TouchTarget.ALL_POINTER_IDS); 194650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } else { 194750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // Dispatch to touch targets, excluding the new touch target if we already 194850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // dispatched to it. Cancel touch targets if necessary. 194950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho TouchTarget predecessor = null; 195050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho TouchTarget target = mFirstTouchTarget; 195150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho while (target != null) { 195250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho final TouchTarget next = target.next; 195350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) { 195450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho handled = true; 195550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } else { 195650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho final boolean cancelChild = resetCancelNextUpFlag(target.child) 195750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho || intercepted; 195850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (dispatchTransformedTouchEvent(ev, cancelChild, 195950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho target.child, target.pointerIdBits)) { 196050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho handled = true; 196150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 196250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (cancelChild) { 196350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (predecessor == null) { 196450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho mFirstTouchTarget = next; 196550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } else { 196650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho predecessor.next = next; 196750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 196850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho target.recycle(); 196950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho target = next; 197050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho continue; 197150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 197250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 197350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho predecessor = target; 197450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho target = next; 197550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 197650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 197750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 197850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // Update list of touch targets for pointer up or cancel, if needed. 197950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (canceled 198050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho || actionMasked == MotionEvent.ACTION_UP 198150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho || actionMasked == MotionEvent.ACTION_HOVER_MOVE) { 198250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho resetTouchState(); 198350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } else if (split && actionMasked == MotionEvent.ACTION_POINTER_UP) { 198450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho final int actionIndex = ev.getActionIndex(); 198550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho final int idBitsToRemove = 1 << ev.getPointerId(actionIndex); 198650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho removePointersFromTouchTargets(idBitsToRemove); 198750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 198850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 198950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 199050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (!handled && mInputEventConsistencyVerifier != null) { 199150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho mInputEventConsistencyVerifier.onUnhandledEvent(ev, 1); 199250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 199350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho return handled; 199450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 199550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 199650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho /** 199750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * Resets all touch state in preparation for a new cycle. 199850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho */ 199950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho private void resetTouchState() { 200050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho clearTouchTargets(); 200150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho resetCancelNextUpFlag(this); 200250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT; 200350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 200450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 200550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho /** 200650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * Resets the cancel next up flag. 200750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * Returns true if the flag was previously set. 200850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho */ 200950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho private static boolean resetCancelNextUpFlag(View view) { 201050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if ((view.mPrivateFlags & PFLAG_CANCEL_NEXT_UP_EVENT) != 0) { 201150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho view.mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT; 201250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho return true; 201350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 201450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho return false; 201550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 201650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 201750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho /** 201850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * Clears all touch targets. 201950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho */ 202050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho private void clearTouchTargets() { 202150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho TouchTarget target = mFirstTouchTarget; 202250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (target != null) { 202350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho do { 202450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho TouchTarget next = target.next; 202550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho target.recycle(); 202650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho target = next; 202750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } while (target != null); 202850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho mFirstTouchTarget = null; 202950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 203050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 203150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 203250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho /** 203350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * Cancels and clears all touch targets. 203450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho */ 203550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho private void cancelAndClearTouchTargets(MotionEvent event) { 203650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (mFirstTouchTarget != null) { 203750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho boolean syntheticEvent = false; 203850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (event == null) { 203950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho final long now = SystemClock.uptimeMillis(); 204050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho event = MotionEvent.obtain(now, now, 204150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0); 204250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho event.setSource(InputDevice.SOURCE_TOUCHSCREEN); 204350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho syntheticEvent = true; 204450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 204550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 204650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho for (TouchTarget target = mFirstTouchTarget; target != null; target = target.next) { 204750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho resetCancelNextUpFlag(target.child); 204850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho dispatchTransformedTouchEvent(event, true, target.child, target.pointerIdBits); 204950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 205050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho clearTouchTargets(); 205150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 205250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (syntheticEvent) { 205350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho event.recycle(); 205450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 205550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 205650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 205750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 205850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho /** 205950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * Gets the touch target for specified child view. 206050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * Returns null if not found. 206150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho */ 206250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho private TouchTarget getTouchTarget(View child) { 206350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho for (TouchTarget target = mFirstTouchTarget; target != null; target = target.next) { 206450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (target.child == child) { 206550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho return target; 206650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 206750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 206850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho return null; 206950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 207050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 207150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho /** 207250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * Adds a touch target for specified child to the beginning of the list. 207350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * Assumes the target child is not already present. 207450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho */ 207550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho private TouchTarget addTouchTarget(View child, int pointerIdBits) { 207650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho TouchTarget target = TouchTarget.obtain(child, pointerIdBits); 207750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho target.next = mFirstTouchTarget; 207850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho mFirstTouchTarget = target; 207950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho return target; 208050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 208150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 208250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho /** 208350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * Removes the pointer ids from consideration. 208450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho */ 208550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho private void removePointersFromTouchTargets(int pointerIdBits) { 208650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho TouchTarget predecessor = null; 208750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho TouchTarget target = mFirstTouchTarget; 208850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho while (target != null) { 208950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho final TouchTarget next = target.next; 209050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if ((target.pointerIdBits & pointerIdBits) != 0) { 209150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho target.pointerIdBits &= ~pointerIdBits; 209250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (target.pointerIdBits == 0) { 209350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (predecessor == null) { 209450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho mFirstTouchTarget = next; 209550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } else { 209650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho predecessor.next = next; 209750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 209850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho target.recycle(); 209950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho target = next; 210050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho continue; 210150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 210250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 210350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho predecessor = target; 210450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho target = next; 210550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 210650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 210750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 210850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho private void cancelTouchTarget(View view) { 210950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho TouchTarget predecessor = null; 211050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho TouchTarget target = mFirstTouchTarget; 211150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho while (target != null) { 211250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho final TouchTarget next = target.next; 211350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (target.child == view) { 211450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (predecessor == null) { 211550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho mFirstTouchTarget = next; 211650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } else { 211750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho predecessor.next = next; 211850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 211950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho target.recycle(); 212050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 212150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho final long now = SystemClock.uptimeMillis(); 212250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho MotionEvent event = MotionEvent.obtain(now, now, 212350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0); 2124 event.setSource(InputDevice.SOURCE_TOUCHSCREEN); 2125 view.dispatchTouchEvent(event); 2126 event.recycle(); 2127 return; 2128 } 2129 predecessor = target; 2130 target = next; 2131 } 2132 } 2133 2134 /** 2135 * Returns true if a child view can receive pointer events. 2136 * @hide 2137 */ 2138 private static boolean canViewReceivePointerEvents(View child) { 2139 return (child.mViewFlags & VISIBILITY_MASK) == VISIBLE 2140 || child.getAnimation() != null; 2141 } 2142 2143 /** 2144 * Returns true if a child view contains the specified point when transformed 2145 * into its coordinate space. 2146 * Child must not be null. 2147 * @hide 2148 */ 2149 protected boolean isTransformedTouchPointInView(float x, float y, View child, 2150 PointF outLocalPoint) { 2151 float localX = x + mScrollX - child.mLeft; 2152 float localY = y + mScrollY - child.mTop; 2153 if (! child.hasIdentityMatrix() && mAttachInfo != null) { 2154 final float[] localXY = mAttachInfo.mTmpTransformLocation; 2155 localXY[0] = localX; 2156 localXY[1] = localY; 2157 child.getInverseMatrix().mapPoints(localXY); 2158 localX = localXY[0]; 2159 localY = localXY[1]; 2160 } 2161 final boolean isInView = child.pointInView(localX, localY); 2162 if (isInView && outLocalPoint != null) { 2163 outLocalPoint.set(localX, localY); 2164 } 2165 return isInView; 2166 } 2167 2168 /** 2169 * Transforms a motion event into the coordinate space of a particular child view, 2170 * filters out irrelevant pointer ids, and overrides its action if necessary. 2171 * If child is null, assumes the MotionEvent will be sent to this ViewGroup instead. 2172 */ 2173 private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel, 2174 View child, int desiredPointerIdBits) { 2175 final boolean handled; 2176 2177 // Canceling motions is a special case. We don't need to perform any transformations 2178 // or filtering. The important part is the action, not the contents. 2179 final int oldAction = event.getAction(); 2180 if (cancel || oldAction == MotionEvent.ACTION_CANCEL) { 2181 event.setAction(MotionEvent.ACTION_CANCEL); 2182 if (child == null) { 2183 handled = super.dispatchTouchEvent(event); 2184 } else { 2185 handled = child.dispatchTouchEvent(event); 2186 } 2187 event.setAction(oldAction); 2188 return handled; 2189 } 2190 2191 // Calculate the number of pointers to deliver. 2192 final int oldPointerIdBits = event.getPointerIdBits(); 2193 final int newPointerIdBits = oldPointerIdBits & desiredPointerIdBits; 2194 2195 // If for some reason we ended up in an inconsistent state where it looks like we 2196 // might produce a motion event with no pointers in it, then drop the event. 2197 if (newPointerIdBits == 0) { 2198 return false; 2199 } 2200 2201 // If the number of pointers is the same and we don't need to perform any fancy 2202 // irreversible transformations, then we can reuse the motion event for this 2203 // dispatch as long as we are careful to revert any changes we make. 2204 // Otherwise we need to make a copy. 2205 final MotionEvent transformedEvent; 2206 if (newPointerIdBits == oldPointerIdBits) { 2207 if (child == null || child.hasIdentityMatrix()) { 2208 if (child == null) { 2209 handled = super.dispatchTouchEvent(event); 2210 } else { 2211 final float offsetX = mScrollX - child.mLeft; 2212 final float offsetY = mScrollY - child.mTop; 2213 event.offsetLocation(offsetX, offsetY); 2214 2215 handled = child.dispatchTouchEvent(event); 2216 2217 event.offsetLocation(-offsetX, -offsetY); 2218 } 2219 return handled; 2220 } 2221 transformedEvent = MotionEvent.obtain(event); 2222 } else { 2223 transformedEvent = event.split(newPointerIdBits); 2224 } 2225 2226 // Perform any necessary transformations and dispatch. 2227 if (child == null) { 2228 handled = super.dispatchTouchEvent(transformedEvent); 2229 } else { 2230 final float offsetX = mScrollX - child.mLeft; 2231 final float offsetY = mScrollY - child.mTop; 2232 transformedEvent.offsetLocation(offsetX, offsetY); 2233 if (! child.hasIdentityMatrix()) { 2234 transformedEvent.transform(child.getInverseMatrix()); 2235 } 2236 2237 handled = child.dispatchTouchEvent(transformedEvent); 2238 } 2239 2240 // Done. 2241 transformedEvent.recycle(); 2242 return handled; 2243 } 2244 2245 /** 2246 * Enable or disable the splitting of MotionEvents to multiple children during touch event 2247 * dispatch. This behavior is enabled by default for applications that target an 2248 * SDK version of {@link Build.VERSION_CODES#HONEYCOMB} or newer. 2249 * 2250 * <p>When this option is enabled MotionEvents may be split and dispatched to different child 2251 * views depending on where each pointer initially went down. This allows for user interactions 2252 * such as scrolling two panes of content independently, chording of buttons, and performing 2253 * independent gestures on different pieces of content. 2254 * 2255 * @param split <code>true</code> to allow MotionEvents to be split and dispatched to multiple 2256 * child views. <code>false</code> to only allow one child view to be the target of 2257 * any MotionEvent received by this ViewGroup. 2258 */ 2259 public void setMotionEventSplittingEnabled(boolean split) { 2260 // TODO Applications really shouldn't change this setting mid-touch event, 2261 // but perhaps this should handle that case and send ACTION_CANCELs to any child views 2262 // with gestures in progress when this is changed. 2263 if (split) { 2264 mGroupFlags |= FLAG_SPLIT_MOTION_EVENTS; 2265 } else { 2266 mGroupFlags &= ~FLAG_SPLIT_MOTION_EVENTS; 2267 } 2268 } 2269 2270 /** 2271 * Returns true if MotionEvents dispatched to this ViewGroup can be split to multiple children. 2272 * @return true if MotionEvents dispatched to this ViewGroup can be split to multiple children. 2273 */ 2274 public boolean isMotionEventSplittingEnabled() { 2275 return (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) == FLAG_SPLIT_MOTION_EVENTS; 2276 } 2277 2278 /** 2279 * {@inheritDoc} 2280 */ 2281 public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) { 2282 2283 if (disallowIntercept == ((mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0)) { 2284 // We're already in this state, assume our ancestors are too 2285 return; 2286 } 2287 2288 if (disallowIntercept) { 2289 mGroupFlags |= FLAG_DISALLOW_INTERCEPT; 2290 } else { 2291 mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT; 2292 } 2293 2294 // Pass it up to our parent 2295 if (mParent != null) { 2296 mParent.requestDisallowInterceptTouchEvent(disallowIntercept); 2297 } 2298 } 2299 2300 /** 2301 * Implement this method to intercept all touch screen motion events. This 2302 * allows you to watch events as they are dispatched to your children, and 2303 * take ownership of the current gesture at any point. 2304 * 2305 * <p>Using this function takes some care, as it has a fairly complicated 2306 * interaction with {@link View#onTouchEvent(MotionEvent) 2307 * View.onTouchEvent(MotionEvent)}, and using it requires implementing 2308 * that method as well as this one in the correct way. Events will be 2309 * received in the following order: 2310 * 2311 * <ol> 2312 * <li> You will receive the down event here. 2313 * <li> The down event will be handled either by a child of this view 2314 * group, or given to your own onTouchEvent() method to handle; this means 2315 * you should implement onTouchEvent() to return true, so you will 2316 * continue to see the rest of the gesture (instead of looking for 2317 * a parent view to handle it). Also, by returning true from 2318 * onTouchEvent(), you will not receive any following 2319 * events in onInterceptTouchEvent() and all touch processing must 2320 * happen in onTouchEvent() like normal. 2321 * <li> For as long as you return false from this function, each following 2322 * event (up to and including the final up) will be delivered first here 2323 * and then to the target's onTouchEvent(). 2324 * <li> If you return true from here, you will not receive any 2325 * following events: the target view will receive the same event but 2326 * with the action {@link MotionEvent#ACTION_CANCEL}, and all further 2327 * events will be delivered to your onTouchEvent() method and no longer 2328 * appear here. 2329 * </ol> 2330 * 2331 * @param ev The motion event being dispatched down the hierarchy. 2332 * @return Return true to steal motion events from the children and have 2333 * them dispatched to this ViewGroup through onTouchEvent(). 2334 * The current target will receive an ACTION_CANCEL event, and no further 2335 * messages will be delivered here. 2336 */ 2337 public boolean onInterceptTouchEvent(MotionEvent ev) { 2338 return false; 2339 } 2340 2341 /** 2342 * {@inheritDoc} 2343 * 2344 * Looks for a view to give focus to respecting the setting specified by 2345 * {@link #getDescendantFocusability()}. 2346 * 2347 * Uses {@link #onRequestFocusInDescendants(int, android.graphics.Rect)} to 2348 * find focus within the children of this group when appropriate. 2349 * 2350 * @see #FOCUS_BEFORE_DESCENDANTS 2351 * @see #FOCUS_AFTER_DESCENDANTS 2352 * @see #FOCUS_BLOCK_DESCENDANTS 2353 * @see #onRequestFocusInDescendants(int, android.graphics.Rect) 2354 */ 2355 @Override 2356 public boolean requestFocus(int direction, Rect previouslyFocusedRect) { 2357 if (DBG) { 2358 System.out.println(this + " ViewGroup.requestFocus direction=" 2359 + direction); 2360 } 2361 int descendantFocusability = getDescendantFocusability(); 2362 2363 switch (descendantFocusability) { 2364 case FOCUS_BLOCK_DESCENDANTS: 2365 return super.requestFocus(direction, previouslyFocusedRect); 2366 case FOCUS_BEFORE_DESCENDANTS: { 2367 final boolean took = super.requestFocus(direction, previouslyFocusedRect); 2368 return took ? took : onRequestFocusInDescendants(direction, previouslyFocusedRect); 2369 } 2370 case FOCUS_AFTER_DESCENDANTS: { 2371 final boolean took = onRequestFocusInDescendants(direction, previouslyFocusedRect); 2372 return took ? took : super.requestFocus(direction, previouslyFocusedRect); 2373 } 2374 default: 2375 throw new IllegalStateException("descendant focusability must be " 2376 + "one of FOCUS_BEFORE_DESCENDANTS, FOCUS_AFTER_DESCENDANTS, FOCUS_BLOCK_DESCENDANTS " 2377 + "but is " + descendantFocusability); 2378 } 2379 } 2380 2381 /** 2382 * Look for a descendant to call {@link View#requestFocus} on. 2383 * Called by {@link ViewGroup#requestFocus(int, android.graphics.Rect)} 2384 * when it wants to request focus within its children. Override this to 2385 * customize how your {@link ViewGroup} requests focus within its children. 2386 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 2387 * @param previouslyFocusedRect The rectangle (in this View's coordinate system) 2388 * to give a finer grained hint about where focus is coming from. May be null 2389 * if there is no hint. 2390 * @return Whether focus was taken. 2391 */ 2392 @SuppressWarnings({"ConstantConditions"}) 2393 protected boolean onRequestFocusInDescendants(int direction, 2394 Rect previouslyFocusedRect) { 2395 int index; 2396 int increment; 2397 int end; 2398 int count = mChildrenCount; 2399 if ((direction & FOCUS_FORWARD) != 0) { 2400 index = 0; 2401 increment = 1; 2402 end = count; 2403 } else { 2404 index = count - 1; 2405 increment = -1; 2406 end = -1; 2407 } 2408 final View[] children = mChildren; 2409 for (int i = index; i != end; i += increment) { 2410 View child = children[i]; 2411 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) { 2412 if (child.requestFocus(direction, previouslyFocusedRect)) { 2413 return true; 2414 } 2415 } 2416 } 2417 return false; 2418 } 2419 2420 /** 2421 * {@inheritDoc} 2422 * 2423 * @hide 2424 */ 2425 @Override 2426 public void dispatchStartTemporaryDetach() { 2427 super.dispatchStartTemporaryDetach(); 2428 final int count = mChildrenCount; 2429 final View[] children = mChildren; 2430 for (int i = 0; i < count; i++) { 2431 children[i].dispatchStartTemporaryDetach(); 2432 } 2433 } 2434 2435 /** 2436 * {@inheritDoc} 2437 * 2438 * @hide 2439 */ 2440 @Override 2441 public void dispatchFinishTemporaryDetach() { 2442 super.dispatchFinishTemporaryDetach(); 2443 final int count = mChildrenCount; 2444 final View[] children = mChildren; 2445 for (int i = 0; i < count; i++) { 2446 children[i].dispatchFinishTemporaryDetach(); 2447 } 2448 } 2449 2450 /** 2451 * {@inheritDoc} 2452 */ 2453 @Override 2454 void dispatchAttachedToWindow(AttachInfo info, int visibility) { 2455 mGroupFlags |= FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW; 2456 super.dispatchAttachedToWindow(info, visibility); 2457 mGroupFlags &= ~FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW; 2458 2459 final int count = mChildrenCount; 2460 final View[] children = mChildren; 2461 for (int i = 0; i < count; i++) { 2462 final View child = children[i]; 2463 child.dispatchAttachedToWindow(info, 2464 visibility | (child.mViewFlags & VISIBILITY_MASK)); 2465 } 2466 } 2467 2468 @Override 2469 void dispatchScreenStateChanged(int screenState) { 2470 super.dispatchScreenStateChanged(screenState); 2471 2472 final int count = mChildrenCount; 2473 final View[] children = mChildren; 2474 for (int i = 0; i < count; i++) { 2475 children[i].dispatchScreenStateChanged(screenState); 2476 } 2477 } 2478 2479 @Override 2480 boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) { 2481 boolean handled = false; 2482 if (includeForAccessibility()) { 2483 handled = super.dispatchPopulateAccessibilityEventInternal(event); 2484 if (handled) { 2485 return handled; 2486 } 2487 } 2488 // Let our children have a shot in populating the event. 2489 ChildListForAccessibility children = ChildListForAccessibility.obtain(this, true); 2490 try { 2491 final int childCount = children.getChildCount(); 2492 for (int i = 0; i < childCount; i++) { 2493 View child = children.getChildAt(i); 2494 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) { 2495 handled = child.dispatchPopulateAccessibilityEvent(event); 2496 if (handled) { 2497 return handled; 2498 } 2499 } 2500 } 2501 } finally { 2502 children.recycle(); 2503 } 2504 return false; 2505 } 2506 2507 @Override 2508 void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) { 2509 super.onInitializeAccessibilityNodeInfoInternal(info); 2510 if (mAttachInfo != null) { 2511 ArrayList<View> childrenForAccessibility = mAttachInfo.mTempArrayList; 2512 childrenForAccessibility.clear(); 2513 addChildrenForAccessibility(childrenForAccessibility); 2514 final int childrenForAccessibilityCount = childrenForAccessibility.size(); 2515 for (int i = 0; i < childrenForAccessibilityCount; i++) { 2516 View child = childrenForAccessibility.get(i); 2517 info.addChild(child); 2518 } 2519 childrenForAccessibility.clear(); 2520 } 2521 } 2522 2523 @Override 2524 void onInitializeAccessibilityEventInternal(AccessibilityEvent event) { 2525 super.onInitializeAccessibilityEventInternal(event); 2526 event.setClassName(ViewGroup.class.getName()); 2527 } 2528 2529 /** 2530 * @hide 2531 */ 2532 @Override 2533 public void resetAccessibilityStateChanged() { 2534 super.resetAccessibilityStateChanged(); 2535 View[] children = mChildren; 2536 final int childCount = mChildrenCount; 2537 for (int i = 0; i < childCount; i++) { 2538 View child = children[i]; 2539 child.resetAccessibilityStateChanged(); 2540 } 2541 } 2542 2543 /** 2544 * {@inheritDoc} 2545 */ 2546 @Override 2547 void dispatchDetachedFromWindow() { 2548 // If we still have a touch target, we are still in the process of 2549 // dispatching motion events to a child; we need to get rid of that 2550 // child to avoid dispatching events to it after the window is torn 2551 // down. To make sure we keep the child in a consistent state, we 2552 // first send it an ACTION_CANCEL motion event. 2553 cancelAndClearTouchTargets(null); 2554 2555 // Similarly, set ACTION_EXIT to all hover targets and clear them. 2556 exitHoverTargets(); 2557 2558 // In case view is detached while transition is running 2559 mLayoutCalledWhileSuppressed = false; 2560 2561 // Tear down our drag tracking 2562 mDragNotifiedChildren = null; 2563 if (mCurrentDrag != null) { 2564 mCurrentDrag.recycle(); 2565 mCurrentDrag = null; 2566 } 2567 2568 final int count = mChildrenCount; 2569 final View[] children = mChildren; 2570 for (int i = 0; i < count; i++) { 2571 children[i].dispatchDetachedFromWindow(); 2572 } 2573 super.dispatchDetachedFromWindow(); 2574 } 2575 2576 /** 2577 * @hide 2578 */ 2579 @Override 2580 protected void internalSetPadding(int left, int top, int right, int bottom) { 2581 super.internalSetPadding(left, top, right, bottom); 2582 2583 if ((mPaddingLeft | mPaddingTop | mPaddingRight | mPaddingBottom) != 0) { 2584 mGroupFlags |= FLAG_PADDING_NOT_NULL; 2585 } else { 2586 mGroupFlags &= ~FLAG_PADDING_NOT_NULL; 2587 } 2588 } 2589 2590 /** 2591 * {@inheritDoc} 2592 */ 2593 @Override 2594 protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) { 2595 super.dispatchSaveInstanceState(container); 2596 final int count = mChildrenCount; 2597 final View[] children = mChildren; 2598 for (int i = 0; i < count; i++) { 2599 View c = children[i]; 2600 if ((c.mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED) { 2601 c.dispatchSaveInstanceState(container); 2602 } 2603 } 2604 } 2605 2606 /** 2607 * Perform dispatching of a {@link #saveHierarchyState(android.util.SparseArray)} freeze()} 2608 * to only this view, not to its children. For use when overriding 2609 * {@link #dispatchSaveInstanceState(android.util.SparseArray)} dispatchFreeze()} to allow 2610 * subclasses to freeze their own state but not the state of their children. 2611 * 2612 * @param container the container 2613 */ 2614 protected void dispatchFreezeSelfOnly(SparseArray<Parcelable> container) { 2615 super.dispatchSaveInstanceState(container); 2616 } 2617 2618 /** 2619 * {@inheritDoc} 2620 */ 2621 @Override 2622 protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) { 2623 super.dispatchRestoreInstanceState(container); 2624 final int count = mChildrenCount; 2625 final View[] children = mChildren; 2626 for (int i = 0; i < count; i++) { 2627 View c = children[i]; 2628 if ((c.mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED) { 2629 c.dispatchRestoreInstanceState(container); 2630 } 2631 } 2632 } 2633 2634 /** 2635 * Perform dispatching of a {@link #restoreHierarchyState(android.util.SparseArray)} 2636 * to only this view, not to its children. For use when overriding 2637 * {@link #dispatchRestoreInstanceState(android.util.SparseArray)} to allow 2638 * subclasses to thaw their own state but not the state of their children. 2639 * 2640 * @param container the container 2641 */ 2642 protected void dispatchThawSelfOnly(SparseArray<Parcelable> container) { 2643 super.dispatchRestoreInstanceState(container); 2644 } 2645 2646 /** 2647 * Enables or disables the drawing cache for each child of this view group. 2648 * 2649 * @param enabled true to enable the cache, false to dispose of it 2650 */ 2651 protected void setChildrenDrawingCacheEnabled(boolean enabled) { 2652 if (enabled || (mPersistentDrawingCache & PERSISTENT_ALL_CACHES) != PERSISTENT_ALL_CACHES) { 2653 final View[] children = mChildren; 2654 final int count = mChildrenCount; 2655 for (int i = 0; i < count; i++) { 2656 children[i].setDrawingCacheEnabled(enabled); 2657 } 2658 } 2659 } 2660 2661 @Override 2662 protected void onAnimationStart() { 2663 super.onAnimationStart(); 2664 2665 // When this ViewGroup's animation starts, build the cache for the children 2666 if ((mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE) { 2667 final int count = mChildrenCount; 2668 final View[] children = mChildren; 2669 final boolean buildCache = !isHardwareAccelerated(); 2670 2671 for (int i = 0; i < count; i++) { 2672 final View child = children[i]; 2673 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) { 2674 child.setDrawingCacheEnabled(true); 2675 if (buildCache) { 2676 child.buildDrawingCache(true); 2677 } 2678 } 2679 } 2680 2681 mGroupFlags |= FLAG_CHILDREN_DRAWN_WITH_CACHE; 2682 } 2683 } 2684 2685 @Override 2686 protected void onAnimationEnd() { 2687 super.onAnimationEnd(); 2688 2689 // When this ViewGroup's animation ends, destroy the cache of the children 2690 if ((mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE) { 2691 mGroupFlags &= ~FLAG_CHILDREN_DRAWN_WITH_CACHE; 2692 2693 if ((mPersistentDrawingCache & PERSISTENT_ANIMATION_CACHE) == 0) { 2694 setChildrenDrawingCacheEnabled(false); 2695 } 2696 } 2697 } 2698 2699 @Override 2700 Bitmap createSnapshot(Bitmap.Config quality, int backgroundColor, boolean skipChildren) { 2701 int count = mChildrenCount; 2702 int[] visibilities = null; 2703 2704 if (skipChildren) { 2705 visibilities = new int[count]; 2706 for (int i = 0; i < count; i++) { 2707 View child = getChildAt(i); 2708 visibilities[i] = child.getVisibility(); 2709 if (visibilities[i] == View.VISIBLE) { 2710 child.setVisibility(INVISIBLE); 2711 } 2712 } 2713 } 2714 2715 Bitmap b = super.createSnapshot(quality, backgroundColor, skipChildren); 2716 2717 if (skipChildren) { 2718 for (int i = 0; i < count; i++) { 2719 getChildAt(i).setVisibility(visibilities[i]); 2720 } 2721 } 2722 2723 return b; 2724 } 2725 2726 /** Return true if this ViewGroup is laying out using optical bounds. */ 2727 boolean isLayoutModeOptical() { 2728 return mLayoutMode == LAYOUT_MODE_OPTICAL_BOUNDS; 2729 } 2730 2731 Insets computeOpticalInsets() { 2732 if (isLayoutModeOptical()) { 2733 int left = 0; 2734 int top = 0; 2735 int right = 0; 2736 int bottom = 0; 2737 for (int i = 0; i < mChildrenCount; i++) { 2738 View child = getChildAt(i); 2739 if (child.getVisibility() == VISIBLE) { 2740 Insets insets = child.getOpticalInsets(); 2741 left = Math.max(left, insets.left); 2742 top = Math.max(top, insets.top); 2743 right = Math.max(right, insets.right); 2744 bottom = Math.max(bottom, insets.bottom); 2745 } 2746 } 2747 return Insets.of(left, top, right, bottom); 2748 } else { 2749 return Insets.NONE; 2750 } 2751 } 2752 2753 private static void fillRect(Canvas canvas, Paint paint, int x1, int y1, int x2, int y2) { 2754 if (x1 != x2 && y1 != y2) { 2755 if (x1 > x2) { 2756 int tmp = x1; x1 = x2; x2 = tmp; 2757 } 2758 if (y1 > y2) { 2759 int tmp = y1; y1 = y2; y2 = tmp; 2760 } 2761 canvas.drawRect(x1, y1, x2, y2, paint); 2762 } 2763 } 2764 2765 private static int sign(int x) { 2766 return (x >= 0) ? 1 : -1; 2767 } 2768 2769 private static void drawCorner(Canvas c, Paint paint, int x1, int y1, int dx, int dy, int lw) { 2770 fillRect(c, paint, x1, y1, x1 + dx, y1 + lw * sign(dy)); 2771 fillRect(c, paint, x1, y1, x1 + lw * sign(dx), y1 + dy); 2772 } 2773 2774 private int dipsToPixels(int dips) { 2775 float scale = getContext().getResources().getDisplayMetrics().density; 2776 return (int) (dips * scale + 0.5f); 2777 } 2778 2779 private void drawRectCorners(Canvas canvas, int x1, int y1, int x2, int y2, Paint paint, 2780 int lineLength, int lineWidth) { 2781 drawCorner(canvas, paint, x1, y1, lineLength, lineLength, lineWidth); 2782 drawCorner(canvas, paint, x1, y2, lineLength, -lineLength, lineWidth); 2783 drawCorner(canvas, paint, x2, y1, -lineLength, lineLength, lineWidth); 2784 drawCorner(canvas, paint, x2, y2, -lineLength, -lineLength, lineWidth); 2785 } 2786 2787 private static void fillDifference(Canvas canvas, 2788 int x2, int y2, int x3, int y3, 2789 int dx1, int dy1, int dx2, int dy2, Paint paint) { 2790 int x1 = x2 - dx1; 2791 int y1 = y2 - dy1; 2792 2793 int x4 = x3 + dx2; 2794 int y4 = y3 + dy2; 2795 2796 fillRect(canvas, paint, x1, y1, x4, y2); 2797 fillRect(canvas, paint, x1, y2, x2, y3); 2798 fillRect(canvas, paint, x3, y2, x4, y3); 2799 fillRect(canvas, paint, x1, y3, x4, y4); 2800 } 2801 2802 /** 2803 * @hide 2804 */ 2805 protected void onDebugDrawMargins(Canvas canvas, Paint paint) { 2806 for (int i = 0; i < getChildCount(); i++) { 2807 View c = getChildAt(i); 2808 c.getLayoutParams().onDebugDraw(c, canvas, paint); 2809 } 2810 } 2811 2812 /** 2813 * @hide 2814 */ 2815 protected void onDebugDraw(Canvas canvas) { 2816 Paint paint = getDebugPaint(); 2817 2818 // Draw optical bounds 2819 { 2820 paint.setColor(Color.RED); 2821 paint.setStyle(Paint.Style.STROKE); 2822 2823 for (int i = 0; i < getChildCount(); i++) { 2824 View c = getChildAt(i); 2825 Insets insets = c.getOpticalInsets(); 2826 2827 drawRect(canvas, paint, 2828 c.getLeft() + insets.left, 2829 c.getTop() + insets.top, 2830 c.getRight() - insets.right - 1, 2831 c.getBottom() - insets.bottom - 1); 2832 } 2833 } 2834 2835 // Draw margins 2836 { 2837 paint.setColor(Color.argb(63, 255, 0, 255)); 2838 paint.setStyle(Paint.Style.FILL); 2839 2840 onDebugDrawMargins(canvas, paint); 2841 } 2842 2843 // Draw clip bounds 2844 { 2845 paint.setColor(Color.rgb(63, 127, 255)); 2846 paint.setStyle(Paint.Style.FILL); 2847 2848 int lineLength = dipsToPixels(8); 2849 int lineWidth = dipsToPixels(1); 2850 for (int i = 0; i < getChildCount(); i++) { 2851 View c = getChildAt(i); 2852 drawRectCorners(canvas, c.getLeft(), c.getTop(), c.getRight(), c.getBottom(), 2853 paint, lineLength, lineWidth); 2854 } 2855 } 2856 } 2857 2858 /** 2859 * {@inheritDoc} 2860 */ 2861 @Override 2862 protected void dispatchDraw(Canvas canvas) { 2863 final int count = mChildrenCount; 2864 final View[] children = mChildren; 2865 int flags = mGroupFlags; 2866 2867 if ((flags & FLAG_RUN_ANIMATION) != 0 && canAnimate()) { 2868 final boolean cache = (mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE; 2869 2870 final boolean buildCache = !isHardwareAccelerated(); 2871 for (int i = 0; i < count; i++) { 2872 final View child = children[i]; 2873 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) { 2874 final LayoutParams params = child.getLayoutParams(); 2875 attachLayoutAnimationParameters(child, params, i, count); 2876 bindLayoutAnimation(child); 2877 if (cache) { 2878 child.setDrawingCacheEnabled(true); 2879 if (buildCache) { 2880 child.buildDrawingCache(true); 2881 } 2882 } 2883 } 2884 } 2885 2886 final LayoutAnimationController controller = mLayoutAnimationController; 2887 if (controller.willOverlap()) { 2888 mGroupFlags |= FLAG_OPTIMIZE_INVALIDATE; 2889 } 2890 2891 controller.start(); 2892 2893 mGroupFlags &= ~FLAG_RUN_ANIMATION; 2894 mGroupFlags &= ~FLAG_ANIMATION_DONE; 2895 2896 if (cache) { 2897 mGroupFlags |= FLAG_CHILDREN_DRAWN_WITH_CACHE; 2898 } 2899 2900 if (mAnimationListener != null) { 2901 mAnimationListener.onAnimationStart(controller.getAnimation()); 2902 } 2903 } 2904 2905 int saveCount = 0; 2906 final boolean clipToPadding = (flags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK; 2907 if (clipToPadding) { 2908 saveCount = canvas.save(); 2909 canvas.clipRect(mScrollX + mPaddingLeft, mScrollY + mPaddingTop, 2910 mScrollX + mRight - mLeft - mPaddingRight, 2911 mScrollY + mBottom - mTop - mPaddingBottom); 2912 2913 } 2914 2915 // We will draw our child's animation, let's reset the flag 2916 mPrivateFlags &= ~PFLAG_DRAW_ANIMATION; 2917 mGroupFlags &= ~FLAG_INVALIDATE_REQUIRED; 2918 2919 boolean more = false; 2920 final long drawingTime = getDrawingTime(); 2921 2922 if ((flags & FLAG_USE_CHILD_DRAWING_ORDER) == 0) { 2923 for (int i = 0; i < count; i++) { 2924 final View child = children[i]; 2925 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) { 2926 more |= drawChild(canvas, child, drawingTime); 2927 } 2928 } 2929 } else { 2930 for (int i = 0; i < count; i++) { 2931 final View child = children[getChildDrawingOrder(count, i)]; 2932 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) { 2933 more |= drawChild(canvas, child, drawingTime); 2934 } 2935 } 2936 } 2937 2938 // Draw any disappearing views that have animations 2939 if (mDisappearingChildren != null) { 2940 final ArrayList<View> disappearingChildren = mDisappearingChildren; 2941 final int disappearingCount = disappearingChildren.size() - 1; 2942 // Go backwards -- we may delete as animations finish 2943 for (int i = disappearingCount; i >= 0; i--) { 2944 final View child = disappearingChildren.get(i); 2945 more |= drawChild(canvas, child, drawingTime); 2946 } 2947 } 2948 2949 if (debugDraw()) { 2950 onDebugDraw(canvas); 2951 } 2952 2953 if (clipToPadding) { 2954 canvas.restoreToCount(saveCount); 2955 } 2956 2957 // mGroupFlags might have been updated by drawChild() 2958 flags = mGroupFlags; 2959 2960 if ((flags & FLAG_INVALIDATE_REQUIRED) == FLAG_INVALIDATE_REQUIRED) { 2961 invalidate(true); 2962 } 2963 2964 if ((flags & FLAG_ANIMATION_DONE) == 0 && (flags & FLAG_NOTIFY_ANIMATION_LISTENER) == 0 && 2965 mLayoutAnimationController.isDone() && !more) { 2966 // We want to erase the drawing cache and notify the listener after the 2967 // next frame is drawn because one extra invalidate() is caused by 2968 // drawChild() after the animation is over 2969 mGroupFlags |= FLAG_NOTIFY_ANIMATION_LISTENER; 2970 final Runnable end = new Runnable() { 2971 public void run() { 2972 notifyAnimationListener(); 2973 } 2974 }; 2975 post(end); 2976 } 2977 } 2978 2979 /** 2980 * Returns the ViewGroupOverlay for this view group, creating it if it does 2981 * not yet exist. In addition to {@link ViewOverlay}'s support for drawables, 2982 * {@link ViewGroupOverlay} allows views to be added to the overlay. These 2983 * views, like overlay drawables, are visual-only; they do not receive input 2984 * events and should not be used as anything other than a temporary 2985 * representation of a view in a parent container, such as might be used 2986 * by an animation effect. 2987 * 2988 * <p>Note: Overlays do not currently work correctly with {@link 2989 * SurfaceView} or {@link TextureView}; contents in overlays for these 2990 * types of views may not display correctly.</p> 2991 * 2992 * @return The ViewGroupOverlay object for this view. 2993 * @see ViewGroupOverlay 2994 */ 2995 @Override 2996 public ViewGroupOverlay getOverlay() { 2997 if (mOverlay == null) { 2998 mOverlay = new ViewGroupOverlay(mContext, this); 2999 } 3000 return (ViewGroupOverlay) mOverlay; 3001 } 3002 3003 /** 3004 * Returns the index of the child to draw for this iteration. Override this 3005 * if you want to change the drawing order of children. By default, it 3006 * returns i. 3007 * <p> 3008 * NOTE: In order for this method to be called, you must enable child ordering 3009 * first by calling {@link #setChildrenDrawingOrderEnabled(boolean)}. 3010 * 3011 * @param i The current iteration. 3012 * @return The index of the child to draw this iteration. 3013 * 3014 * @see #setChildrenDrawingOrderEnabled(boolean) 3015 * @see #isChildrenDrawingOrderEnabled() 3016 */ 3017 protected int getChildDrawingOrder(int childCount, int i) { 3018 return i; 3019 } 3020 3021 private void notifyAnimationListener() { 3022 mGroupFlags &= ~FLAG_NOTIFY_ANIMATION_LISTENER; 3023 mGroupFlags |= FLAG_ANIMATION_DONE; 3024 3025 if (mAnimationListener != null) { 3026 final Runnable end = new Runnable() { 3027 public void run() { 3028 mAnimationListener.onAnimationEnd(mLayoutAnimationController.getAnimation()); 3029 } 3030 }; 3031 post(end); 3032 } 3033 3034 if ((mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE) { 3035 mGroupFlags &= ~FLAG_CHILDREN_DRAWN_WITH_CACHE; 3036 if ((mPersistentDrawingCache & PERSISTENT_ANIMATION_CACHE) == 0) { 3037 setChildrenDrawingCacheEnabled(false); 3038 } 3039 } 3040 3041 invalidate(true); 3042 } 3043 3044 /** 3045 * This method is used to cause children of this ViewGroup to restore or recreate their 3046 * display lists. It is called by getDisplayList() when the parent ViewGroup does not need 3047 * to recreate its own display list, which would happen if it went through the normal 3048 * draw/dispatchDraw mechanisms. 3049 * 3050 * @hide 3051 */ 3052 @Override 3053 protected void dispatchGetDisplayList() { 3054 final int count = mChildrenCount; 3055 final View[] children = mChildren; 3056 for (int i = 0; i < count; i++) { 3057 final View child = children[i]; 3058 if (((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) && 3059 child.hasStaticLayer()) { 3060 child.mRecreateDisplayList = (child.mPrivateFlags & PFLAG_INVALIDATED) 3061 == PFLAG_INVALIDATED; 3062 child.mPrivateFlags &= ~PFLAG_INVALIDATED; 3063 child.getDisplayList(); 3064 child.mRecreateDisplayList = false; 3065 } 3066 } 3067 if (mOverlay != null) { 3068 View overlayView = mOverlay.getOverlayView(); 3069 overlayView.mRecreateDisplayList = (overlayView.mPrivateFlags & PFLAG_INVALIDATED) 3070 == PFLAG_INVALIDATED; 3071 overlayView.mPrivateFlags &= ~PFLAG_INVALIDATED; 3072 overlayView.getDisplayList(); 3073 overlayView.mRecreateDisplayList = false; 3074 } 3075 } 3076 3077 /** 3078 * Draw one child of this View Group. This method is responsible for getting 3079 * the canvas in the right state. This includes clipping, translating so 3080 * that the child's scrolled origin is at 0, 0, and applying any animation 3081 * transformations. 3082 * 3083 * @param canvas The canvas on which to draw the child 3084 * @param child Who to draw 3085 * @param drawingTime The time at which draw is occurring 3086 * @return True if an invalidate() was issued 3087 */ 3088 protected boolean drawChild(Canvas canvas, View child, long drawingTime) { 3089 return child.draw(canvas, this, drawingTime); 3090 } 3091 3092 /** 3093 * Returns whether ths group's children are clipped to their bounds before drawing. 3094 * The default value is true. 3095 * @see #setClipChildren(boolean) 3096 * 3097 * @return True if the group's children will be clipped to their bounds, 3098 * false otherwise. 3099 */ 3100 public boolean getClipChildren() { 3101 return ((mGroupFlags & FLAG_CLIP_CHILDREN) != 0); 3102 } 3103 3104 /** 3105 * By default, children are clipped to their bounds before drawing. This 3106 * allows view groups to override this behavior for animations, etc. 3107 * 3108 * @param clipChildren true to clip children to their bounds, 3109 * false otherwise 3110 * @attr ref android.R.styleable#ViewGroup_clipChildren 3111 */ 3112 public void setClipChildren(boolean clipChildren) { 3113 boolean previousValue = (mGroupFlags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN; 3114 if (clipChildren != previousValue) { 3115 setBooleanFlag(FLAG_CLIP_CHILDREN, clipChildren); 3116 for (int i = 0; i < mChildrenCount; ++i) { 3117 View child = getChildAt(i); 3118 if (child.mDisplayList != null) { 3119 child.mDisplayList.setClipChildren(clipChildren); 3120 } 3121 } 3122 } 3123 } 3124 3125 /** 3126 * By default, children are clipped to the padding of the ViewGroup. This 3127 * allows view groups to override this behavior 3128 * 3129 * @param clipToPadding true to clip children to the padding of the 3130 * group, false otherwise 3131 * @attr ref android.R.styleable#ViewGroup_clipToPadding 3132 */ 3133 public void setClipToPadding(boolean clipToPadding) { 3134 setBooleanFlag(FLAG_CLIP_TO_PADDING, clipToPadding); 3135 } 3136 3137 /** 3138 * {@inheritDoc} 3139 */ 3140 @Override 3141 public void dispatchSetSelected(boolean selected) { 3142 final View[] children = mChildren; 3143 final int count = mChildrenCount; 3144 for (int i = 0; i < count; i++) { 3145 children[i].setSelected(selected); 3146 } 3147 } 3148 3149 /** 3150 * {@inheritDoc} 3151 */ 3152 @Override 3153 public void dispatchSetActivated(boolean activated) { 3154 final View[] children = mChildren; 3155 final int count = mChildrenCount; 3156 for (int i = 0; i < count; i++) { 3157 children[i].setActivated(activated); 3158 } 3159 } 3160 3161 @Override 3162 protected void dispatchSetPressed(boolean pressed) { 3163 final View[] children = mChildren; 3164 final int count = mChildrenCount; 3165 for (int i = 0; i < count; i++) { 3166 final View child = children[i]; 3167 // Children that are clickable on their own should not 3168 // show a pressed state when their parent view does. 3169 // Clearing a pressed state always propagates. 3170 if (!pressed || (!child.isClickable() && !child.isLongClickable())) { 3171 child.setPressed(pressed); 3172 } 3173 } 3174 } 3175 3176 /** 3177 * When this property is set to true, this ViewGroup supports static transformations on 3178 * children; this causes 3179 * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} to be 3180 * invoked when a child is drawn. 3181 * 3182 * Any subclass overriding 3183 * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} should 3184 * set this property to true. 3185 * 3186 * @param enabled True to enable static transformations on children, false otherwise. 3187 * 3188 * @see #getChildStaticTransformation(View, android.view.animation.Transformation) 3189 */ 3190 protected void setStaticTransformationsEnabled(boolean enabled) { 3191 setBooleanFlag(FLAG_SUPPORT_STATIC_TRANSFORMATIONS, enabled); 3192 } 3193 3194 /** 3195 * Sets <code>t</code> to be the static transformation of the child, if set, returning a 3196 * boolean to indicate whether a static transform was set. The default implementation 3197 * simply returns <code>false</code>; subclasses may override this method for different 3198 * behavior. {@link #setStaticTransformationsEnabled(boolean)} must be set to true 3199 * for this method to be called. 3200 * 3201 * @param child The child view whose static transform is being requested 3202 * @param t The Transformation which will hold the result 3203 * @return true if the transformation was set, false otherwise 3204 * @see #setStaticTransformationsEnabled(boolean) 3205 */ 3206 protected boolean getChildStaticTransformation(View child, Transformation t) { 3207 return false; 3208 } 3209 3210 /** 3211 * {@hide} 3212 */ 3213 @Override 3214 protected View findViewTraversal(int id) { 3215 if (id == mID) { 3216 return this; 3217 } 3218 3219 final View[] where = mChildren; 3220 final int len = mChildrenCount; 3221 3222 for (int i = 0; i < len; i++) { 3223 View v = where[i]; 3224 3225 if ((v.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) { 3226 v = v.findViewById(id); 3227 3228 if (v != null) { 3229 return v; 3230 } 3231 } 3232 } 3233 3234 return null; 3235 } 3236 3237 /** 3238 * {@hide} 3239 */ 3240 @Override 3241 protected View findViewWithTagTraversal(Object tag) { 3242 if (tag != null && tag.equals(mTag)) { 3243 return this; 3244 } 3245 3246 final View[] where = mChildren; 3247 final int len = mChildrenCount; 3248 3249 for (int i = 0; i < len; i++) { 3250 View v = where[i]; 3251 3252 if ((v.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) { 3253 v = v.findViewWithTag(tag); 3254 3255 if (v != null) { 3256 return v; 3257 } 3258 } 3259 } 3260 3261 return null; 3262 } 3263 3264 /** 3265 * {@hide} 3266 */ 3267 @Override 3268 protected View findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip) { 3269 if (predicate.apply(this)) { 3270 return this; 3271 } 3272 3273 final View[] where = mChildren; 3274 final int len = mChildrenCount; 3275 3276 for (int i = 0; i < len; i++) { 3277 View v = where[i]; 3278 3279 if (v != childToSkip && (v.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) { 3280 v = v.findViewByPredicate(predicate); 3281 3282 if (v != null) { 3283 return v; 3284 } 3285 } 3286 } 3287 3288 return null; 3289 } 3290 3291 /** 3292 * <p>Adds a child view. If no layout parameters are already set on the child, the 3293 * default parameters for this ViewGroup are set on the child.</p> 3294 * 3295 * <p><strong>Note:</strong> do not invoke this method from 3296 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)}, 3297 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p> 3298 * 3299 * @param child the child view to add 3300 * 3301 * @see #generateDefaultLayoutParams() 3302 */ 3303 public void addView(View child) { 3304 addView(child, -1); 3305 } 3306 3307 /** 3308 * Adds a child view. If no layout parameters are already set on the child, the 3309 * default parameters for this ViewGroup are set on the child. 3310 * 3311 * <p><strong>Note:</strong> do not invoke this method from 3312 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)}, 3313 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p> 3314 * 3315 * @param child the child view to add 3316 * @param index the position at which to add the child 3317 * 3318 * @see #generateDefaultLayoutParams() 3319 */ 3320 public void addView(View child, int index) { 3321 LayoutParams params = child.getLayoutParams(); 3322 if (params == null) { 3323 params = generateDefaultLayoutParams(); 3324 if (params == null) { 3325 throw new IllegalArgumentException("generateDefaultLayoutParams() cannot return null"); 3326 } 3327 } 3328 addView(child, index, params); 3329 } 3330 3331 /** 3332 * Adds a child view with this ViewGroup's default layout parameters and the 3333 * specified width and height. 3334 * 3335 * <p><strong>Note:</strong> do not invoke this method from 3336 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)}, 3337 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p> 3338 * 3339 * @param child the child view to add 3340 */ 3341 public void addView(View child, int width, int height) { 3342 final LayoutParams params = generateDefaultLayoutParams(); 3343 params.width = width; 3344 params.height = height; 3345 addView(child, -1, params); 3346 } 3347 3348 /** 3349 * Adds a child view with the specified layout parameters. 3350 * 3351 * <p><strong>Note:</strong> do not invoke this method from 3352 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)}, 3353 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p> 3354 * 3355 * @param child the child view to add 3356 * @param params the layout parameters to set on the child 3357 */ 3358 public void addView(View child, LayoutParams params) { 3359 addView(child, -1, params); 3360 } 3361 3362 /** 3363 * Adds a child view with the specified layout parameters. 3364 * 3365 * <p><strong>Note:</strong> do not invoke this method from 3366 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)}, 3367 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p> 3368 * 3369 * @param child the child view to add 3370 * @param index the position at which to add the child 3371 * @param params the layout parameters to set on the child 3372 */ 3373 public void addView(View child, int index, LayoutParams params) { 3374 if (DBG) { 3375 System.out.println(this + " addView"); 3376 } 3377 3378 // addViewInner() will call child.requestLayout() when setting the new LayoutParams 3379 // therefore, we call requestLayout() on ourselves before, so that the child's request 3380 // will be blocked at our level 3381 requestLayout(); 3382 invalidate(true); 3383 addViewInner(child, index, params, false); 3384 } 3385 3386 /** 3387 * {@inheritDoc} 3388 */ 3389 public void updateViewLayout(View view, ViewGroup.LayoutParams params) { 3390 if (!checkLayoutParams(params)) { 3391 throw new IllegalArgumentException("Invalid LayoutParams supplied to " + this); 3392 } 3393 if (view.mParent != this) { 3394 throw new IllegalArgumentException("Given view not a child of " + this); 3395 } 3396 view.setLayoutParams(params); 3397 } 3398 3399 /** 3400 * {@inheritDoc} 3401 */ 3402 protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { 3403 return p != null; 3404 } 3405 3406 /** 3407 * Interface definition for a callback to be invoked when the hierarchy 3408 * within this view changed. The hierarchy changes whenever a child is added 3409 * to or removed from this view. 3410 */ 3411 public interface OnHierarchyChangeListener { 3412 /** 3413 * Called when a new child is added to a parent view. 3414 * 3415 * @param parent the view in which a child was added 3416 * @param child the new child view added in the hierarchy 3417 */ 3418 void onChildViewAdded(View parent, View child); 3419 3420 /** 3421 * Called when a child is removed from a parent view. 3422 * 3423 * @param parent the view from which the child was removed 3424 * @param child the child removed from the hierarchy 3425 */ 3426 void onChildViewRemoved(View parent, View child); 3427 } 3428 3429 /** 3430 * Register a callback to be invoked when a child is added to or removed 3431 * from this view. 3432 * 3433 * @param listener the callback to invoke on hierarchy change 3434 */ 3435 public void setOnHierarchyChangeListener(OnHierarchyChangeListener listener) { 3436 mOnHierarchyChangeListener = listener; 3437 } 3438 3439 /** 3440 * @hide 3441 */ 3442 protected void onViewAdded(View child) { 3443 if (mOnHierarchyChangeListener != null) { 3444 mOnHierarchyChangeListener.onChildViewAdded(this, child); 3445 } 3446 } 3447 3448 /** 3449 * @hide 3450 */ 3451 protected void onViewRemoved(View child) { 3452 if (mOnHierarchyChangeListener != null) { 3453 mOnHierarchyChangeListener.onChildViewRemoved(this, child); 3454 } 3455 } 3456 3457 private void clearCachedLayoutMode() { 3458 if (!getBooleanFlag(FLAG_LAYOUT_MODE_WAS_EXPLICITLY_SET)) { 3459 mLayoutMode = LAYOUT_MODE_UNDEFINED; 3460 } 3461 } 3462 3463 @Override 3464 protected void onAttachedToWindow() { 3465 super.onAttachedToWindow(); 3466 clearCachedLayoutMode(); 3467 } 3468 3469 @Override 3470 protected void onDetachedFromWindow() { 3471 super.onDetachedFromWindow(); 3472 clearCachedLayoutMode(); 3473 } 3474 3475 /** 3476 * Adds a view during layout. This is useful if in your onLayout() method, 3477 * you need to add more views (as does the list view for example). 3478 * 3479 * If index is negative, it means put it at the end of the list. 3480 * 3481 * @param child the view to add to the group 3482 * @param index the index at which the child must be added 3483 * @param params the layout parameters to associate with the child 3484 * @return true if the child was added, false otherwise 3485 */ 3486 protected boolean addViewInLayout(View child, int index, LayoutParams params) { 3487 return addViewInLayout(child, index, params, false); 3488 } 3489 3490 /** 3491 * Adds a view during layout. This is useful if in your onLayout() method, 3492 * you need to add more views (as does the list view for example). 3493 * 3494 * If index is negative, it means put it at the end of the list. 3495 * 3496 * @param child the view to add to the group 3497 * @param index the index at which the child must be added 3498 * @param params the layout parameters to associate with the child 3499 * @param preventRequestLayout if true, calling this method will not trigger a 3500 * layout request on child 3501 * @return true if the child was added, false otherwise 3502 */ 3503 protected boolean addViewInLayout(View child, int index, LayoutParams params, 3504 boolean preventRequestLayout) { 3505 child.mParent = null; 3506 addViewInner(child, index, params, preventRequestLayout); 3507 child.mPrivateFlags = (child.mPrivateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN; 3508 return true; 3509 } 3510 3511 /** 3512 * Prevents the specified child to be laid out during the next layout pass. 3513 * 3514 * @param child the child on which to perform the cleanup 3515 */ 3516 protected void cleanupLayoutState(View child) { 3517 child.mPrivateFlags &= ~View.PFLAG_FORCE_LAYOUT; 3518 } 3519 3520 private void addViewInner(View child, int index, LayoutParams params, 3521 boolean preventRequestLayout) { 3522 3523 if (mTransition != null) { 3524 // Don't prevent other add transitions from completing, but cancel remove 3525 // transitions to let them complete the process before we add to the container 3526 mTransition.cancel(LayoutTransition.DISAPPEARING); 3527 } 3528 3529 if (child.getParent() != null) { 3530 throw new IllegalStateException("The specified child already has a parent. " + 3531 "You must call removeView() on the child's parent first."); 3532 } 3533 3534 if (mTransition != null) { 3535 mTransition.addChild(this, child); 3536 } 3537 3538 if (!checkLayoutParams(params)) { 3539 params = generateLayoutParams(params); 3540 } 3541 3542 if (preventRequestLayout) { 3543 child.mLayoutParams = params; 3544 } else { 3545 child.setLayoutParams(params); 3546 } 3547 3548 if (index < 0) { 3549 index = mChildrenCount; 3550 } 3551 3552 addInArray(child, index); 3553 3554 // tell our children 3555 if (preventRequestLayout) { 3556 child.assignParent(this); 3557 } else { 3558 child.mParent = this; 3559 } 3560 3561 if (child.hasFocus()) { 3562 requestChildFocus(child, child.findFocus()); 3563 } 3564 3565 AttachInfo ai = mAttachInfo; 3566 if (ai != null && (mGroupFlags & FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW) == 0) { 3567 boolean lastKeepOn = ai.mKeepScreenOn; 3568 ai.mKeepScreenOn = false; 3569 child.dispatchAttachedToWindow(mAttachInfo, (mViewFlags&VISIBILITY_MASK)); 3570 if (ai.mKeepScreenOn) { 3571 needGlobalAttributesUpdate(true); 3572 } 3573 ai.mKeepScreenOn = lastKeepOn; 3574 } 3575 3576 if (child.isLayoutDirectionInherited()) { 3577 child.resetRtlProperties(); 3578 } 3579 3580 onViewAdded(child); 3581 3582 if ((child.mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE) { 3583 mGroupFlags |= FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE; 3584 } 3585 3586 if (child.hasTransientState()) { 3587 childHasTransientStateChanged(child, true); 3588 } 3589 } 3590 3591 private void addInArray(View child, int index) { 3592 View[] children = mChildren; 3593 final int count = mChildrenCount; 3594 final int size = children.length; 3595 if (index == count) { 3596 if (size == count) { 3597 mChildren = new View[size + ARRAY_CAPACITY_INCREMENT]; 3598 System.arraycopy(children, 0, mChildren, 0, size); 3599 children = mChildren; 3600 } 3601 children[mChildrenCount++] = child; 3602 } else if (index < count) { 3603 if (size == count) { 3604 mChildren = new View[size + ARRAY_CAPACITY_INCREMENT]; 3605 System.arraycopy(children, 0, mChildren, 0, index); 3606 System.arraycopy(children, index, mChildren, index + 1, count - index); 3607 children = mChildren; 3608 } else { 3609 System.arraycopy(children, index, children, index + 1, count - index); 3610 } 3611 children[index] = child; 3612 mChildrenCount++; 3613 if (mLastTouchDownIndex >= index) { 3614 mLastTouchDownIndex++; 3615 } 3616 } else { 3617 throw new IndexOutOfBoundsException("index=" + index + " count=" + count); 3618 } 3619 } 3620 3621 // This method also sets the child's mParent to null 3622 private void removeFromArray(int index) { 3623 final View[] children = mChildren; 3624 if (!(mTransitioningViews != null && mTransitioningViews.contains(children[index]))) { 3625 children[index].mParent = null; 3626 } 3627 final int count = mChildrenCount; 3628 if (index == count - 1) { 3629 children[--mChildrenCount] = null; 3630 } else if (index >= 0 && index < count) { 3631 System.arraycopy(children, index + 1, children, index, count - index - 1); 3632 children[--mChildrenCount] = null; 3633 } else { 3634 throw new IndexOutOfBoundsException(); 3635 } 3636 if (mLastTouchDownIndex == index) { 3637 mLastTouchDownTime = 0; 3638 mLastTouchDownIndex = -1; 3639 } else if (mLastTouchDownIndex > index) { 3640 mLastTouchDownIndex--; 3641 } 3642 } 3643 3644 // This method also sets the children's mParent to null 3645 private void removeFromArray(int start, int count) { 3646 final View[] children = mChildren; 3647 final int childrenCount = mChildrenCount; 3648 3649 start = Math.max(0, start); 3650 final int end = Math.min(childrenCount, start + count); 3651 3652 if (start == end) { 3653 return; 3654 } 3655 3656 if (end == childrenCount) { 3657 for (int i = start; i < end; i++) { 3658 children[i].mParent = null; 3659 children[i] = null; 3660 } 3661 } else { 3662 for (int i = start; i < end; i++) { 3663 children[i].mParent = null; 3664 } 3665 3666 // Since we're looping above, we might as well do the copy, but is arraycopy() 3667 // faster than the extra 2 bounds checks we would do in the loop? 3668 System.arraycopy(children, end, children, start, childrenCount - end); 3669 3670 for (int i = childrenCount - (end - start); i < childrenCount; i++) { 3671 children[i] = null; 3672 } 3673 } 3674 3675 mChildrenCount -= (end - start); 3676 } 3677 3678 private void bindLayoutAnimation(View child) { 3679 Animation a = mLayoutAnimationController.getAnimationForView(child); 3680 child.setAnimation(a); 3681 } 3682 3683 /** 3684 * Subclasses should override this method to set layout animation 3685 * parameters on the supplied child. 3686 * 3687 * @param child the child to associate with animation parameters 3688 * @param params the child's layout parameters which hold the animation 3689 * parameters 3690 * @param index the index of the child in the view group 3691 * @param count the number of children in the view group 3692 */ 3693 protected void attachLayoutAnimationParameters(View child, 3694 LayoutParams params, int index, int count) { 3695 LayoutAnimationController.AnimationParameters animationParams = 3696 params.layoutAnimationParameters; 3697 if (animationParams == null) { 3698 animationParams = new LayoutAnimationController.AnimationParameters(); 3699 params.layoutAnimationParameters = animationParams; 3700 } 3701 3702 animationParams.count = count; 3703 animationParams.index = index; 3704 } 3705 3706 /** 3707 * {@inheritDoc} 3708 * 3709 * <p><strong>Note:</strong> do not invoke this method from 3710 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)}, 3711 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p> 3712 */ 3713 public void removeView(View view) { 3714 removeViewInternal(view); 3715 requestLayout(); 3716 invalidate(true); 3717 } 3718 3719 /** 3720 * Removes a view during layout. This is useful if in your onLayout() method, 3721 * you need to remove more views. 3722 * 3723 * <p><strong>Note:</strong> do not invoke this method from 3724 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)}, 3725 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p> 3726 * 3727 * @param view the view to remove from the group 3728 */ 3729 public void removeViewInLayout(View view) { 3730 removeViewInternal(view); 3731 } 3732 3733 /** 3734 * Removes a range of views during layout. This is useful if in your onLayout() method, 3735 * you need to remove more views. 3736 * 3737 * <p><strong>Note:</strong> do not invoke this method from 3738 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)}, 3739 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p> 3740 * 3741 * @param start the index of the first view to remove from the group 3742 * @param count the number of views to remove from the group 3743 */ 3744 public void removeViewsInLayout(int start, int count) { 3745 removeViewsInternal(start, count); 3746 } 3747 3748 /** 3749 * Removes the view at the specified position in the group. 3750 * 3751 * <p><strong>Note:</strong> do not invoke this method from 3752 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)}, 3753 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p> 3754 * 3755 * @param index the position in the group of the view to remove 3756 */ 3757 public void removeViewAt(int index) { 3758 removeViewInternal(index, getChildAt(index)); 3759 requestLayout(); 3760 invalidate(true); 3761 } 3762 3763 /** 3764 * Removes the specified range of views from the group. 3765 * 3766 * <p><strong>Note:</strong> do not invoke this method from 3767 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)}, 3768 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p> 3769 * 3770 * @param start the first position in the group of the range of views to remove 3771 * @param count the number of views to remove 3772 */ 3773 public void removeViews(int start, int count) { 3774 removeViewsInternal(start, count); 3775 requestLayout(); 3776 invalidate(true); 3777 } 3778 3779 private void removeViewInternal(View view) { 3780 final int index = indexOfChild(view); 3781 if (index >= 0) { 3782 removeViewInternal(index, view); 3783 } 3784 } 3785 3786 private void removeViewInternal(int index, View view) { 3787 3788 if (mTransition != null) { 3789 mTransition.removeChild(this, view); 3790 } 3791 3792 boolean clearChildFocus = false; 3793 if (view == mFocused) { 3794 view.unFocus(); 3795 clearChildFocus = true; 3796 } 3797 3798 if (view.isAccessibilityFocused()) { 3799 view.clearAccessibilityFocus(); 3800 } 3801 3802 cancelTouchTarget(view); 3803 cancelHoverTarget(view); 3804 3805 if (view.getAnimation() != null || 3806 (mTransitioningViews != null && mTransitioningViews.contains(view))) { 3807 addDisappearingView(view); 3808 } else if (view.mAttachInfo != null) { 3809 view.dispatchDetachedFromWindow(); 3810 } 3811 3812 if (view.hasTransientState()) { 3813 childHasTransientStateChanged(view, false); 3814 } 3815 3816 needGlobalAttributesUpdate(false); 3817 3818 removeFromArray(index); 3819 3820 if (clearChildFocus) { 3821 clearChildFocus(view); 3822 if (!rootViewRequestFocus()) { 3823 notifyGlobalFocusCleared(this); 3824 } 3825 } 3826 3827 onViewRemoved(view); 3828 } 3829 3830 /** 3831 * Sets the LayoutTransition object for this ViewGroup. If the LayoutTransition object is 3832 * not null, changes in layout which occur because of children being added to or removed from 3833 * the ViewGroup will be animated according to the animations defined in that LayoutTransition 3834 * object. By default, the transition object is null (so layout changes are not animated). 3835 * 3836 * @param transition The LayoutTransition object that will animated changes in layout. A value 3837 * of <code>null</code> means no transition will run on layout changes. 3838 * @attr ref android.R.styleable#ViewGroup_animateLayoutChanges 3839 */ 3840 public void setLayoutTransition(LayoutTransition transition) { 3841 if (mTransition != null) { 3842 mTransition.removeTransitionListener(mLayoutTransitionListener); 3843 } 3844 mTransition = transition; 3845 if (mTransition != null) { 3846 mTransition.addTransitionListener(mLayoutTransitionListener); 3847 } 3848 } 3849 3850 /** 3851 * Gets the LayoutTransition object for this ViewGroup. If the LayoutTransition object is 3852 * not null, changes in layout which occur because of children being added to or removed from 3853 * the ViewGroup will be animated according to the animations defined in that LayoutTransition 3854 * object. By default, the transition object is null (so layout changes are not animated). 3855 * 3856 * @return LayoutTranstion The LayoutTransition object that will animated changes in layout. 3857 * A value of <code>null</code> means no transition will run on layout changes. 3858 */ 3859 public LayoutTransition getLayoutTransition() { 3860 return mTransition; 3861 } 3862 3863 private void removeViewsInternal(int start, int count) { 3864 final View focused = mFocused; 3865 final boolean detach = mAttachInfo != null; 3866 boolean clearChildFocus = false; 3867 3868 final View[] children = mChildren; 3869 final int end = start + count; 3870 3871 for (int i = start; i < end; i++) { 3872 final View view = children[i]; 3873 3874 if (mTransition != null) { 3875 mTransition.removeChild(this, view); 3876 } 3877 3878 if (view == focused) { 3879 view.unFocus(); 3880 clearChildFocus = true; 3881 } 3882 3883 if (view.isAccessibilityFocused()) { 3884 view.clearAccessibilityFocus(); 3885 } 3886 3887 cancelTouchTarget(view); 3888 cancelHoverTarget(view); 3889 3890 if (view.getAnimation() != null || 3891 (mTransitioningViews != null && mTransitioningViews.contains(view))) { 3892 addDisappearingView(view); 3893 } else if (detach) { 3894 view.dispatchDetachedFromWindow(); 3895 } 3896 3897 if (view.hasTransientState()) { 3898 childHasTransientStateChanged(view, false); 3899 } 3900 3901 needGlobalAttributesUpdate(false); 3902 3903 onViewRemoved(view); 3904 } 3905 3906 removeFromArray(start, count); 3907 3908 if (clearChildFocus) { 3909 clearChildFocus(focused); 3910 if (!rootViewRequestFocus()) { 3911 notifyGlobalFocusCleared(focused); 3912 } 3913 } 3914 } 3915 3916 /** 3917 * Call this method to remove all child views from the 3918 * ViewGroup. 3919 * 3920 * <p><strong>Note:</strong> do not invoke this method from 3921 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)}, 3922 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p> 3923 */ 3924 public void removeAllViews() { 3925 removeAllViewsInLayout(); 3926 requestLayout(); 3927 invalidate(true); 3928 } 3929 3930 /** 3931 * Called by a ViewGroup subclass to remove child views from itself, 3932 * when it must first know its size on screen before it can calculate how many 3933 * child views it will render. An example is a Gallery or a ListView, which 3934 * may "have" 50 children, but actually only render the number of children 3935 * that can currently fit inside the object on screen. Do not call 3936 * this method unless you are extending ViewGroup and understand the 3937 * view measuring and layout pipeline. 3938 * 3939 * <p><strong>Note:</strong> do not invoke this method from 3940 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)}, 3941 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p> 3942 */ 3943 public void removeAllViewsInLayout() { 3944 final int count = mChildrenCount; 3945 if (count <= 0) { 3946 return; 3947 } 3948 3949 final View[] children = mChildren; 3950 mChildrenCount = 0; 3951 3952 final View focused = mFocused; 3953 final boolean detach = mAttachInfo != null; 3954 boolean clearChildFocus = false; 3955 3956 needGlobalAttributesUpdate(false); 3957 3958 for (int i = count - 1; i >= 0; i--) { 3959 final View view = children[i]; 3960 3961 if (mTransition != null) { 3962 mTransition.removeChild(this, view); 3963 } 3964 3965 if (view == focused) { 3966 view.unFocus(); 3967 clearChildFocus = true; 3968 } 3969 3970 if (view.isAccessibilityFocused()) { 3971 view.clearAccessibilityFocus(); 3972 } 3973 3974 cancelTouchTarget(view); 3975 cancelHoverTarget(view); 3976 3977 if (view.getAnimation() != null || 3978 (mTransitioningViews != null && mTransitioningViews.contains(view))) { 3979 addDisappearingView(view); 3980 } else if (detach) { 3981 view.dispatchDetachedFromWindow(); 3982 } 3983 3984 if (view.hasTransientState()) { 3985 childHasTransientStateChanged(view, false); 3986 } 3987 3988 onViewRemoved(view); 3989 3990 view.mParent = null; 3991 children[i] = null; 3992 } 3993 3994 if (clearChildFocus) { 3995 clearChildFocus(focused); 3996 if (!rootViewRequestFocus()) { 3997 notifyGlobalFocusCleared(focused); 3998 } 3999 } 4000 } 4001 4002 /** 4003 * Finishes the removal of a detached view. This method will dispatch the detached from 4004 * window event and notify the hierarchy change listener. 4005 * <p> 4006 * This method is intended to be lightweight and makes no assumptions about whether the 4007 * parent or child should be redrawn. Proper use of this method will include also making 4008 * any appropriate {@link #requestLayout()} or {@link #invalidate()} calls. 4009 * For example, callers can {@link #post(Runnable) post} a {@link Runnable} 4010 * which performs a {@link #requestLayout()} on the next frame, after all detach/remove 4011 * calls are finished, causing layout to be run prior to redrawing the view hierarchy. 4012 * 4013 * @param child the child to be definitely removed from the view hierarchy 4014 * @param animate if true and the view has an animation, the view is placed in the 4015 * disappearing views list, otherwise, it is detached from the window 4016 * 4017 * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams) 4018 * @see #detachAllViewsFromParent() 4019 * @see #detachViewFromParent(View) 4020 * @see #detachViewFromParent(int) 4021 */ 4022 protected void removeDetachedView(View child, boolean animate) { 4023 if (mTransition != null) { 4024 mTransition.removeChild(this, child); 4025 } 4026 4027 if (child == mFocused) { 4028 child.clearFocus(); 4029 } 4030 4031 child.clearAccessibilityFocus(); 4032 4033 cancelTouchTarget(child); 4034 cancelHoverTarget(child); 4035 4036 if ((animate && child.getAnimation() != null) || 4037 (mTransitioningViews != null && mTransitioningViews.contains(child))) { 4038 addDisappearingView(child); 4039 } else if (child.mAttachInfo != null) { 4040 child.dispatchDetachedFromWindow(); 4041 } 4042 4043 if (child.hasTransientState()) { 4044 childHasTransientStateChanged(child, false); 4045 } 4046 4047 onViewRemoved(child); 4048 } 4049 4050 /** 4051 * Attaches a view to this view group. Attaching a view assigns this group as the parent, 4052 * sets the layout parameters and puts the view in the list of children so that 4053 * it can be retrieved by calling {@link #getChildAt(int)}. 4054 * <p> 4055 * This method is intended to be lightweight and makes no assumptions about whether the 4056 * parent or child should be redrawn. Proper use of this method will include also making 4057 * any appropriate {@link #requestLayout()} or {@link #invalidate()} calls. 4058 * For example, callers can {@link #post(Runnable) post} a {@link Runnable} 4059 * which performs a {@link #requestLayout()} on the next frame, after all detach/attach 4060 * calls are finished, causing layout to be run prior to redrawing the view hierarchy. 4061 * <p> 4062 * This method should be called only for views which were detached from their parent. 4063 * 4064 * @param child the child to attach 4065 * @param index the index at which the child should be attached 4066 * @param params the layout parameters of the child 4067 * 4068 * @see #removeDetachedView(View, boolean) 4069 * @see #detachAllViewsFromParent() 4070 * @see #detachViewFromParent(View) 4071 * @see #detachViewFromParent(int) 4072 */ 4073 protected void attachViewToParent(View child, int index, LayoutParams params) { 4074 child.mLayoutParams = params; 4075 4076 if (index < 0) { 4077 index = mChildrenCount; 4078 } 4079 4080 addInArray(child, index); 4081 4082 child.mParent = this; 4083 child.mPrivateFlags = (child.mPrivateFlags & ~PFLAG_DIRTY_MASK 4084 & ~PFLAG_DRAWING_CACHE_VALID) 4085 | PFLAG_DRAWN | PFLAG_INVALIDATED; 4086 this.mPrivateFlags |= PFLAG_INVALIDATED; 4087 4088 if (child.hasFocus()) { 4089 requestChildFocus(child, child.findFocus()); 4090 } 4091 } 4092 4093 /** 4094 * Detaches a view from its parent. Detaching a view should be followed 4095 * either by a call to 4096 * {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)} 4097 * or a call to {@link #removeDetachedView(View, boolean)}. Detachment should only be 4098 * temporary; reattachment or removal should happen within the same drawing cycle as 4099 * detachment. When a view is detached, its parent is null and cannot be retrieved by a 4100 * call to {@link #getChildAt(int)}. 4101 * 4102 * @param child the child to detach 4103 * 4104 * @see #detachViewFromParent(int) 4105 * @see #detachViewsFromParent(int, int) 4106 * @see #detachAllViewsFromParent() 4107 * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams) 4108 * @see #removeDetachedView(View, boolean) 4109 */ 4110 protected void detachViewFromParent(View child) { 4111 removeFromArray(indexOfChild(child)); 4112 } 4113 4114 /** 4115 * Detaches a view from its parent. Detaching a view should be followed 4116 * either by a call to 4117 * {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)} 4118 * or a call to {@link #removeDetachedView(View, boolean)}. Detachment should only be 4119 * temporary; reattachment or removal should happen within the same drawing cycle as 4120 * detachment. When a view is detached, its parent is null and cannot be retrieved by a 4121 * call to {@link #getChildAt(int)}. 4122 * 4123 * @param index the index of the child to detach 4124 * 4125 * @see #detachViewFromParent(View) 4126 * @see #detachAllViewsFromParent() 4127 * @see #detachViewsFromParent(int, int) 4128 * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams) 4129 * @see #removeDetachedView(View, boolean) 4130 */ 4131 protected void detachViewFromParent(int index) { 4132 removeFromArray(index); 4133 } 4134 4135 /** 4136 * Detaches a range of views from their parents. Detaching a view should be followed 4137 * either by a call to 4138 * {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)} 4139 * or a call to {@link #removeDetachedView(View, boolean)}. Detachment should only be 4140 * temporary; reattachment or removal should happen within the same drawing cycle as 4141 * detachment. When a view is detached, its parent is null and cannot be retrieved by a 4142 * call to {@link #getChildAt(int)}. 4143 * 4144 * @param start the first index of the childrend range to detach 4145 * @param count the number of children to detach 4146 * 4147 * @see #detachViewFromParent(View) 4148 * @see #detachViewFromParent(int) 4149 * @see #detachAllViewsFromParent() 4150 * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams) 4151 * @see #removeDetachedView(View, boolean) 4152 */ 4153 protected void detachViewsFromParent(int start, int count) { 4154 removeFromArray(start, count); 4155 } 4156 4157 /** 4158 * Detaches all views from the parent. Detaching a view should be followed 4159 * either by a call to 4160 * {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)} 4161 * or a call to {@link #removeDetachedView(View, boolean)}. Detachment should only be 4162 * temporary; reattachment or removal should happen within the same drawing cycle as 4163 * detachment. When a view is detached, its parent is null and cannot be retrieved by a 4164 * call to {@link #getChildAt(int)}. 4165 * 4166 * @see #detachViewFromParent(View) 4167 * @see #detachViewFromParent(int) 4168 * @see #detachViewsFromParent(int, int) 4169 * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams) 4170 * @see #removeDetachedView(View, boolean) 4171 */ 4172 protected void detachAllViewsFromParent() { 4173 final int count = mChildrenCount; 4174 if (count <= 0) { 4175 return; 4176 } 4177 4178 final View[] children = mChildren; 4179 mChildrenCount = 0; 4180 4181 for (int i = count - 1; i >= 0; i--) { 4182 children[i].mParent = null; 4183 children[i] = null; 4184 } 4185 } 4186 4187 /** 4188 * Don't call or override this method. It is used for the implementation of 4189 * the view hierarchy. 4190 */ 4191 public final void invalidateChild(View child, final Rect dirty) { 4192 ViewParent parent = this; 4193 4194 final AttachInfo attachInfo = mAttachInfo; 4195 if (attachInfo != null) { 4196 // If the child is drawing an animation, we want to copy this flag onto 4197 // ourselves and the parent to make sure the invalidate request goes 4198 // through 4199 final boolean drawAnimation = (child.mPrivateFlags & PFLAG_DRAW_ANIMATION) 4200 == PFLAG_DRAW_ANIMATION; 4201 4202 // Check whether the child that requests the invalidate is fully opaque 4203 // Views being animated or transformed are not considered opaque because we may 4204 // be invalidating their old position and need the parent to paint behind them. 4205 Matrix childMatrix = child.getMatrix(); 4206 final boolean isOpaque = child.isOpaque() && !drawAnimation && 4207 child.getAnimation() == null && childMatrix.isIdentity(); 4208 // Mark the child as dirty, using the appropriate flag 4209 // Make sure we do not set both flags at the same time 4210 int opaqueFlag = isOpaque ? PFLAG_DIRTY_OPAQUE : PFLAG_DIRTY; 4211 4212 if (child.mLayerType != LAYER_TYPE_NONE) { 4213 mPrivateFlags |= PFLAG_INVALIDATED; 4214 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 4215 child.mLocalDirtyRect.union(dirty); 4216 } 4217 4218 final int[] location = attachInfo.mInvalidateChildLocation; 4219 location[CHILD_LEFT_INDEX] = child.mLeft; 4220 location[CHILD_TOP_INDEX] = child.mTop; 4221 if (!childMatrix.isIdentity() || 4222 (mGroupFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) { 4223 RectF boundingRect = attachInfo.mTmpTransformRect; 4224 boundingRect.set(dirty); 4225 Matrix transformMatrix; 4226 if ((mGroupFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) { 4227 Transformation t = attachInfo.mTmpTransformation; 4228 boolean transformed = getChildStaticTransformation(child, t); 4229 if (transformed) { 4230 transformMatrix = attachInfo.mTmpMatrix; 4231 transformMatrix.set(t.getMatrix()); 4232 if (!childMatrix.isIdentity()) { 4233 transformMatrix.preConcat(childMatrix); 4234 } 4235 } else { 4236 transformMatrix = childMatrix; 4237 } 4238 } else { 4239 transformMatrix = childMatrix; 4240 } 4241 transformMatrix.mapRect(boundingRect); 4242 dirty.set((int) (boundingRect.left - 0.5f), 4243 (int) (boundingRect.top - 0.5f), 4244 (int) (boundingRect.right + 0.5f), 4245 (int) (boundingRect.bottom + 0.5f)); 4246 } 4247 4248 do { 4249 View view = null; 4250 if (parent instanceof View) { 4251 view = (View) parent; 4252 } 4253 4254 if (drawAnimation) { 4255 if (view != null) { 4256 view.mPrivateFlags |= PFLAG_DRAW_ANIMATION; 4257 } else if (parent instanceof ViewRootImpl) { 4258 ((ViewRootImpl) parent).mIsAnimating = true; 4259 } 4260 } 4261 4262 // If the parent is dirty opaque or not dirty, mark it dirty with the opaque 4263 // flag coming from the child that initiated the invalidate 4264 if (view != null) { 4265 if ((view.mViewFlags & FADING_EDGE_MASK) != 0 && 4266 view.getSolidColor() == 0) { 4267 opaqueFlag = PFLAG_DIRTY; 4268 } 4269 if ((view.mPrivateFlags & PFLAG_DIRTY_MASK) != PFLAG_DIRTY) { 4270 view.mPrivateFlags = (view.mPrivateFlags & ~PFLAG_DIRTY_MASK) | opaqueFlag; 4271 } 4272 } 4273 4274 parent = parent.invalidateChildInParent(location, dirty); 4275 if (view != null) { 4276 // Account for transform on current parent 4277 Matrix m = view.getMatrix(); 4278 if (!m.isIdentity()) { 4279 RectF boundingRect = attachInfo.mTmpTransformRect; 4280 boundingRect.set(dirty); 4281 m.mapRect(boundingRect); 4282 dirty.set((int) (boundingRect.left - 0.5f), 4283 (int) (boundingRect.top - 0.5f), 4284 (int) (boundingRect.right + 0.5f), 4285 (int) (boundingRect.bottom + 0.5f)); 4286 } 4287 } 4288 } while (parent != null); 4289 } 4290 } 4291 4292 /** 4293 * Don't call or override this method. It is used for the implementation of 4294 * the view hierarchy. 4295 * 4296 * This implementation returns null if this ViewGroup does not have a parent, 4297 * if this ViewGroup is already fully invalidated or if the dirty rectangle 4298 * does not intersect with this ViewGroup's bounds. 4299 */ 4300 public ViewParent invalidateChildInParent(final int[] location, final Rect dirty) { 4301 if ((mPrivateFlags & PFLAG_DRAWN) == PFLAG_DRAWN || 4302 (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID) { 4303 if ((mGroupFlags & (FLAG_OPTIMIZE_INVALIDATE | FLAG_ANIMATION_DONE)) != 4304 FLAG_OPTIMIZE_INVALIDATE) { 4305 dirty.offset(location[CHILD_LEFT_INDEX] - mScrollX, 4306 location[CHILD_TOP_INDEX] - mScrollY); 4307 4308 final int left = mLeft; 4309 final int top = mTop; 4310 4311 if ((mGroupFlags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN) { 4312 if (!dirty.intersect(0, 0, mRight - left, mBottom - top)) { 4313 dirty.setEmpty(); 4314 } 4315 } 4316 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 4317 4318 location[CHILD_LEFT_INDEX] = left; 4319 location[CHILD_TOP_INDEX] = top; 4320 4321 if (mLayerType != LAYER_TYPE_NONE) { 4322 mPrivateFlags |= PFLAG_INVALIDATED; 4323 mLocalDirtyRect.union(dirty); 4324 } 4325 4326 return mParent; 4327 4328 } else { 4329 mPrivateFlags &= ~PFLAG_DRAWN & ~PFLAG_DRAWING_CACHE_VALID; 4330 4331 location[CHILD_LEFT_INDEX] = mLeft; 4332 location[CHILD_TOP_INDEX] = mTop; 4333 if ((mGroupFlags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN) { 4334 dirty.set(0, 0, mRight - mLeft, mBottom - mTop); 4335 } else { 4336 // in case the dirty rect extends outside the bounds of this container 4337 dirty.union(0, 0, mRight - mLeft, mBottom - mTop); 4338 } 4339 4340 if (mLayerType != LAYER_TYPE_NONE) { 4341 mPrivateFlags |= PFLAG_INVALIDATED; 4342 mLocalDirtyRect.union(dirty); 4343 } 4344 4345 return mParent; 4346 } 4347 } 4348 4349 return null; 4350 } 4351 4352 /** 4353 * Quick invalidation method called by View.invalidateViewProperty. This doesn't set the 4354 * DRAWN flags and doesn't handle the Animation logic that the default invalidation methods 4355 * do; all we want to do here is schedule a traversal with the appropriate dirty rect. 4356 * 4357 * @hide 4358 */ 4359 public void invalidateChildFast(View child, final Rect dirty) { 4360 ViewParent parent = this; 4361 4362 final AttachInfo attachInfo = mAttachInfo; 4363 if (attachInfo != null) { 4364 if (child.mLayerType != LAYER_TYPE_NONE) { 4365 child.mLocalDirtyRect.union(dirty); 4366 } 4367 4368 int left = child.mLeft; 4369 int top = child.mTop; 4370 if (!child.getMatrix().isIdentity()) { 4371 child.transformRect(dirty); 4372 } 4373 4374 do { 4375 if (parent instanceof ViewGroup) { 4376 ViewGroup parentVG = (ViewGroup) parent; 4377 if (parentVG.mLayerType != LAYER_TYPE_NONE) { 4378 // Layered parents should be recreated, not just re-issued 4379 parentVG.invalidate(); 4380 parent = null; 4381 } else { 4382 parent = parentVG.invalidateChildInParentFast(left, top, dirty); 4383 left = parentVG.mLeft; 4384 top = parentVG.mTop; 4385 } 4386 } else { 4387 // Reached the top; this calls into the usual invalidate method in 4388 // ViewRootImpl, which schedules a traversal 4389 final int[] location = attachInfo.mInvalidateChildLocation; 4390 location[0] = left; 4391 location[1] = top; 4392 parent = parent.invalidateChildInParent(location, dirty); 4393 } 4394 } while (parent != null); 4395 } 4396 } 4397 4398 /** 4399 * Quick invalidation method that simply transforms the dirty rect into the parent's 4400 * coordinate system, pruning the invalidation if the parent has already been invalidated. 4401 */ 4402 private ViewParent invalidateChildInParentFast(int left, int top, final Rect dirty) { 4403 if ((mPrivateFlags & PFLAG_DRAWN) == PFLAG_DRAWN || 4404 (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID) { 4405 dirty.offset(left - mScrollX, top - mScrollY); 4406 4407 if ((mGroupFlags & FLAG_CLIP_CHILDREN) == 0 || 4408 dirty.intersect(0, 0, mRight - mLeft, mBottom - mTop)) { 4409 4410 if (mLayerType != LAYER_TYPE_NONE) { 4411 mLocalDirtyRect.union(dirty); 4412 } 4413 if (!getMatrix().isIdentity()) { 4414 transformRect(dirty); 4415 } 4416 4417 return mParent; 4418 } 4419 } 4420 4421 return null; 4422 } 4423 4424 /** 4425 * Offset a rectangle that is in a descendant's coordinate 4426 * space into our coordinate space. 4427 * @param descendant A descendant of this view 4428 * @param rect A rectangle defined in descendant's coordinate space. 4429 */ 4430 public final void offsetDescendantRectToMyCoords(View descendant, Rect rect) { 4431 offsetRectBetweenParentAndChild(descendant, rect, true, false); 4432 } 4433 4434 /** 4435 * Offset a rectangle that is in our coordinate space into an ancestor's 4436 * coordinate space. 4437 * @param descendant A descendant of this view 4438 * @param rect A rectangle defined in descendant's coordinate space. 4439 */ 4440 public final void offsetRectIntoDescendantCoords(View descendant, Rect rect) { 4441 offsetRectBetweenParentAndChild(descendant, rect, false, false); 4442 } 4443 4444 /** 4445 * Helper method that offsets a rect either from parent to descendant or 4446 * descendant to parent. 4447 */ 4448 void offsetRectBetweenParentAndChild(View descendant, Rect rect, 4449 boolean offsetFromChildToParent, boolean clipToBounds) { 4450 4451 // already in the same coord system :) 4452 if (descendant == this) { 4453 return; 4454 } 4455 4456 ViewParent theParent = descendant.mParent; 4457 4458 // search and offset up to the parent 4459 while ((theParent != null) 4460 && (theParent instanceof View) 4461 && (theParent != this)) { 4462 4463 if (offsetFromChildToParent) { 4464 rect.offset(descendant.mLeft - descendant.mScrollX, 4465 descendant.mTop - descendant.mScrollY); 4466 if (clipToBounds) { 4467 View p = (View) theParent; 4468 rect.intersect(0, 0, p.mRight - p.mLeft, p.mBottom - p.mTop); 4469 } 4470 } else { 4471 if (clipToBounds) { 4472 View p = (View) theParent; 4473 rect.intersect(0, 0, p.mRight - p.mLeft, p.mBottom - p.mTop); 4474 } 4475 rect.offset(descendant.mScrollX - descendant.mLeft, 4476 descendant.mScrollY - descendant.mTop); 4477 } 4478 4479 descendant = (View) theParent; 4480 theParent = descendant.mParent; 4481 } 4482 4483 // now that we are up to this view, need to offset one more time 4484 // to get into our coordinate space 4485 if (theParent == this) { 4486 if (offsetFromChildToParent) { 4487 rect.offset(descendant.mLeft - descendant.mScrollX, 4488 descendant.mTop - descendant.mScrollY); 4489 } else { 4490 rect.offset(descendant.mScrollX - descendant.mLeft, 4491 descendant.mScrollY - descendant.mTop); 4492 } 4493 } else { 4494 throw new IllegalArgumentException("parameter must be a descendant of this view"); 4495 } 4496 } 4497 4498 /** 4499 * Offset the vertical location of all children of this view by the specified number of pixels. 4500 * 4501 * @param offset the number of pixels to offset 4502 * 4503 * @hide 4504 */ 4505 public void offsetChildrenTopAndBottom(int offset) { 4506 final int count = mChildrenCount; 4507 final View[] children = mChildren; 4508 4509 for (int i = 0; i < count; i++) { 4510 final View v = children[i]; 4511 v.mTop += offset; 4512 v.mBottom += offset; 4513 if (v.mDisplayList != null) { 4514 v.mDisplayList.offsetTopAndBottom(offset); 4515 invalidateViewProperty(false, false); 4516 } 4517 } 4518 } 4519 4520 /** 4521 * {@inheritDoc} 4522 */ 4523 public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) { 4524 // It doesn't make a whole lot of sense to call this on a view that isn't attached, 4525 // but for some simple tests it can be useful. If we don't have attach info this 4526 // will allocate memory. 4527 final RectF rect = mAttachInfo != null ? mAttachInfo.mTmpTransformRect : new RectF(); 4528 rect.set(r); 4529 4530 if (!child.hasIdentityMatrix()) { 4531 child.getMatrix().mapRect(rect); 4532 } 4533 4534 int dx = child.mLeft - mScrollX; 4535 int dy = child.mTop - mScrollY; 4536 4537 rect.offset(dx, dy); 4538 4539 if (offset != null) { 4540 if (!child.hasIdentityMatrix()) { 4541 float[] position = mAttachInfo != null ? mAttachInfo.mTmpTransformLocation 4542 : new float[2]; 4543 position[0] = offset.x; 4544 position[1] = offset.y; 4545 child.getMatrix().mapPoints(position); 4546 offset.x = (int) (position[0] + 0.5f); 4547 offset.y = (int) (position[1] + 0.5f); 4548 } 4549 offset.x += dx; 4550 offset.y += dy; 4551 } 4552 4553 if (rect.intersect(0, 0, mRight - mLeft, mBottom - mTop)) { 4554 if (mParent == null) return true; 4555 r.set((int) (rect.left + 0.5f), (int) (rect.top + 0.5f), 4556 (int) (rect.right + 0.5f), (int) (rect.bottom + 0.5f)); 4557 return mParent.getChildVisibleRect(this, r, offset); 4558 } 4559 4560 return false; 4561 } 4562 4563 /** 4564 * {@inheritDoc} 4565 */ 4566 @Override 4567 public final void layout(int l, int t, int r, int b) { 4568 if (!mSuppressLayout && (mTransition == null || !mTransition.isChangingLayout())) { 4569 if (mTransition != null) { 4570 mTransition.layoutChange(this); 4571 } 4572 super.layout(l, t, r, b); 4573 } else { 4574 // record the fact that we noop'd it; request layout when transition finishes 4575 mLayoutCalledWhileSuppressed = true; 4576 } 4577 } 4578 4579 /** 4580 * {@inheritDoc} 4581 */ 4582 @Override 4583 protected abstract void onLayout(boolean changed, 4584 int l, int t, int r, int b); 4585 4586 /** 4587 * Indicates whether the view group has the ability to animate its children 4588 * after the first layout. 4589 * 4590 * @return true if the children can be animated, false otherwise 4591 */ 4592 protected boolean canAnimate() { 4593 return mLayoutAnimationController != null; 4594 } 4595 4596 /** 4597 * Runs the layout animation. Calling this method triggers a relayout of 4598 * this view group. 4599 */ 4600 public void startLayoutAnimation() { 4601 if (mLayoutAnimationController != null) { 4602 mGroupFlags |= FLAG_RUN_ANIMATION; 4603 requestLayout(); 4604 } 4605 } 4606 4607 /** 4608 * Schedules the layout animation to be played after the next layout pass 4609 * of this view group. This can be used to restart the layout animation 4610 * when the content of the view group changes or when the activity is 4611 * paused and resumed. 4612 */ 4613 public void scheduleLayoutAnimation() { 4614 mGroupFlags |= FLAG_RUN_ANIMATION; 4615 } 4616 4617 /** 4618 * Sets the layout animation controller used to animate the group's 4619 * children after the first layout. 4620 * 4621 * @param controller the animation controller 4622 */ 4623 public void setLayoutAnimation(LayoutAnimationController controller) { 4624 mLayoutAnimationController = controller; 4625 if (mLayoutAnimationController != null) { 4626 mGroupFlags |= FLAG_RUN_ANIMATION; 4627 } 4628 } 4629 4630 /** 4631 * Returns the layout animation controller used to animate the group's 4632 * children. 4633 * 4634 * @return the current animation controller 4635 */ 4636 public LayoutAnimationController getLayoutAnimation() { 4637 return mLayoutAnimationController; 4638 } 4639 4640 /** 4641 * Indicates whether the children's drawing cache is used during a layout 4642 * animation. By default, the drawing cache is enabled but this will prevent 4643 * nested layout animations from working. To nest animations, you must disable 4644 * the cache. 4645 * 4646 * @return true if the animation cache is enabled, false otherwise 4647 * 4648 * @see #setAnimationCacheEnabled(boolean) 4649 * @see View#setDrawingCacheEnabled(boolean) 4650 */ 4651 @ViewDebug.ExportedProperty 4652 public boolean isAnimationCacheEnabled() { 4653 return (mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE; 4654 } 4655 4656 /** 4657 * Enables or disables the children's drawing cache during a layout animation. 4658 * By default, the drawing cache is enabled but this will prevent nested 4659 * layout animations from working. To nest animations, you must disable the 4660 * cache. 4661 * 4662 * @param enabled true to enable the animation cache, false otherwise 4663 * 4664 * @see #isAnimationCacheEnabled() 4665 * @see View#setDrawingCacheEnabled(boolean) 4666 */ 4667 public void setAnimationCacheEnabled(boolean enabled) { 4668 setBooleanFlag(FLAG_ANIMATION_CACHE, enabled); 4669 } 4670 4671 /** 4672 * Indicates whether this ViewGroup will always try to draw its children using their 4673 * drawing cache. By default this property is enabled. 4674 * 4675 * @return true if the animation cache is enabled, false otherwise 4676 * 4677 * @see #setAlwaysDrawnWithCacheEnabled(boolean) 4678 * @see #setChildrenDrawnWithCacheEnabled(boolean) 4679 * @see View#setDrawingCacheEnabled(boolean) 4680 */ 4681 @ViewDebug.ExportedProperty(category = "drawing") 4682 public boolean isAlwaysDrawnWithCacheEnabled() { 4683 return (mGroupFlags & FLAG_ALWAYS_DRAWN_WITH_CACHE) == FLAG_ALWAYS_DRAWN_WITH_CACHE; 4684 } 4685 4686 /** 4687 * Indicates whether this ViewGroup will always try to draw its children using their 4688 * drawing cache. This property can be set to true when the cache rendering is 4689 * slightly different from the children's normal rendering. Renderings can be different, 4690 * for instance, when the cache's quality is set to low. 4691 * 4692 * When this property is disabled, the ViewGroup will use the drawing cache of its 4693 * children only when asked to. It's usually the task of subclasses to tell ViewGroup 4694 * when to start using the drawing cache and when to stop using it. 4695 * 4696 * @param always true to always draw with the drawing cache, false otherwise 4697 * 4698 * @see #isAlwaysDrawnWithCacheEnabled() 4699 * @see #setChildrenDrawnWithCacheEnabled(boolean) 4700 * @see View#setDrawingCacheEnabled(boolean) 4701 * @see View#setDrawingCacheQuality(int) 4702 */ 4703 public void setAlwaysDrawnWithCacheEnabled(boolean always) { 4704 setBooleanFlag(FLAG_ALWAYS_DRAWN_WITH_CACHE, always); 4705 } 4706 4707 /** 4708 * Indicates whether the ViewGroup is currently drawing its children using 4709 * their drawing cache. 4710 * 4711 * @return true if children should be drawn with their cache, false otherwise 4712 * 4713 * @see #setAlwaysDrawnWithCacheEnabled(boolean) 4714 * @see #setChildrenDrawnWithCacheEnabled(boolean) 4715 */ 4716 @ViewDebug.ExportedProperty(category = "drawing") 4717 protected boolean isChildrenDrawnWithCacheEnabled() { 4718 return (mGroupFlags & FLAG_CHILDREN_DRAWN_WITH_CACHE) == FLAG_CHILDREN_DRAWN_WITH_CACHE; 4719 } 4720 4721 /** 4722 * Tells the ViewGroup to draw its children using their drawing cache. This property 4723 * is ignored when {@link #isAlwaysDrawnWithCacheEnabled()} is true. A child's drawing cache 4724 * will be used only if it has been enabled. 4725 * 4726 * Subclasses should call this method to start and stop using the drawing cache when 4727 * they perform performance sensitive operations, like scrolling or animating. 4728 * 4729 * @param enabled true if children should be drawn with their cache, false otherwise 4730 * 4731 * @see #setAlwaysDrawnWithCacheEnabled(boolean) 4732 * @see #isChildrenDrawnWithCacheEnabled() 4733 */ 4734 protected void setChildrenDrawnWithCacheEnabled(boolean enabled) { 4735 setBooleanFlag(FLAG_CHILDREN_DRAWN_WITH_CACHE, enabled); 4736 } 4737 4738 /** 4739 * Indicates whether the ViewGroup is drawing its children in the order defined by 4740 * {@link #getChildDrawingOrder(int, int)}. 4741 * 4742 * @return true if children drawing order is defined by {@link #getChildDrawingOrder(int, int)}, 4743 * false otherwise 4744 * 4745 * @see #setChildrenDrawingOrderEnabled(boolean) 4746 * @see #getChildDrawingOrder(int, int) 4747 */ 4748 @ViewDebug.ExportedProperty(category = "drawing") 4749 protected boolean isChildrenDrawingOrderEnabled() { 4750 return (mGroupFlags & FLAG_USE_CHILD_DRAWING_ORDER) == FLAG_USE_CHILD_DRAWING_ORDER; 4751 } 4752 4753 /** 4754 * Tells the ViewGroup whether to draw its children in the order defined by the method 4755 * {@link #getChildDrawingOrder(int, int)}. 4756 * 4757 * @param enabled true if the order of the children when drawing is determined by 4758 * {@link #getChildDrawingOrder(int, int)}, false otherwise 4759 * 4760 * @see #isChildrenDrawingOrderEnabled() 4761 * @see #getChildDrawingOrder(int, int) 4762 */ 4763 protected void setChildrenDrawingOrderEnabled(boolean enabled) { 4764 setBooleanFlag(FLAG_USE_CHILD_DRAWING_ORDER, enabled); 4765 } 4766 4767 private boolean getBooleanFlag(int flag) { 4768 return (mGroupFlags & flag) == flag; 4769 } 4770 4771 private void setBooleanFlag(int flag, boolean value) { 4772 if (value) { 4773 mGroupFlags |= flag; 4774 } else { 4775 mGroupFlags &= ~flag; 4776 } 4777 } 4778 4779 /** 4780 * Returns an integer indicating what types of drawing caches are kept in memory. 4781 * 4782 * @see #setPersistentDrawingCache(int) 4783 * @see #setAnimationCacheEnabled(boolean) 4784 * 4785 * @return one or a combination of {@link #PERSISTENT_NO_CACHE}, 4786 * {@link #PERSISTENT_ANIMATION_CACHE}, {@link #PERSISTENT_SCROLLING_CACHE} 4787 * and {@link #PERSISTENT_ALL_CACHES} 4788 */ 4789 @ViewDebug.ExportedProperty(category = "drawing", mapping = { 4790 @ViewDebug.IntToString(from = PERSISTENT_NO_CACHE, to = "NONE"), 4791 @ViewDebug.IntToString(from = PERSISTENT_ANIMATION_CACHE, to = "ANIMATION"), 4792 @ViewDebug.IntToString(from = PERSISTENT_SCROLLING_CACHE, to = "SCROLLING"), 4793 @ViewDebug.IntToString(from = PERSISTENT_ALL_CACHES, to = "ALL") 4794 }) 4795 public int getPersistentDrawingCache() { 4796 return mPersistentDrawingCache; 4797 } 4798 4799 /** 4800 * Indicates what types of drawing caches should be kept in memory after 4801 * they have been created. 4802 * 4803 * @see #getPersistentDrawingCache() 4804 * @see #setAnimationCacheEnabled(boolean) 4805 * 4806 * @param drawingCacheToKeep one or a combination of {@link #PERSISTENT_NO_CACHE}, 4807 * {@link #PERSISTENT_ANIMATION_CACHE}, {@link #PERSISTENT_SCROLLING_CACHE} 4808 * and {@link #PERSISTENT_ALL_CACHES} 4809 */ 4810 public void setPersistentDrawingCache(int drawingCacheToKeep) { 4811 mPersistentDrawingCache = drawingCacheToKeep & PERSISTENT_ALL_CACHES; 4812 } 4813 4814 private void setLayoutMode(int layoutMode, boolean explicitly) { 4815 mLayoutMode = layoutMode; 4816 setBooleanFlag(FLAG_LAYOUT_MODE_WAS_EXPLICITLY_SET, explicitly); 4817 } 4818 4819 /** 4820 * Recursively traverse the view hierarchy, resetting the layoutMode of any 4821 * descendants that had inherited a different layoutMode from a previous parent. 4822 * Recursion terminates when a descendant's mode is: 4823 * <ul> 4824 * <li>Undefined</li> 4825 * <li>The same as the root node's</li> 4826 * <li>A mode that had been explicitly set</li> 4827 * <ul/> 4828 * The first two clauses are optimizations. 4829 * @param layoutModeOfRoot 4830 */ 4831 @Override 4832 void invalidateInheritedLayoutMode(int layoutModeOfRoot) { 4833 if (mLayoutMode == LAYOUT_MODE_UNDEFINED || 4834 mLayoutMode == layoutModeOfRoot || 4835 getBooleanFlag(FLAG_LAYOUT_MODE_WAS_EXPLICITLY_SET)) { 4836 return; 4837 } 4838 setLayoutMode(LAYOUT_MODE_UNDEFINED, false); 4839 4840 // apply recursively 4841 for (int i = 0, N = getChildCount(); i < N; i++) { 4842 getChildAt(i).invalidateInheritedLayoutMode(layoutModeOfRoot); 4843 } 4844 } 4845 4846 /** 4847 * Returns the basis of alignment during layout operations on this ViewGroup: 4848 * either {@link #LAYOUT_MODE_CLIP_BOUNDS} or {@link #LAYOUT_MODE_OPTICAL_BOUNDS}. 4849 * <p> 4850 * If no layoutMode was explicitly set, either programmatically or in an XML resource, 4851 * the method returns the layoutMode of the view's parent ViewGroup if such a parent exists, 4852 * otherwise the method returns a default value of {@link #LAYOUT_MODE_CLIP_BOUNDS}. 4853 * 4854 * @return the layout mode to use during layout operations 4855 * 4856 * @see #setLayoutMode(int) 4857 */ 4858 public int getLayoutMode() { 4859 if (mLayoutMode == LAYOUT_MODE_UNDEFINED) { 4860 int inheritedLayoutMode = (mParent instanceof ViewGroup) ? 4861 ((ViewGroup) mParent).getLayoutMode() : LAYOUT_MODE_DEFAULT; 4862 setLayoutMode(inheritedLayoutMode, false); 4863 } 4864 return mLayoutMode; 4865 } 4866 4867 /** 4868 * Sets the basis of alignment during the layout of this ViewGroup. 4869 * Valid values are either {@link #LAYOUT_MODE_CLIP_BOUNDS} or 4870 * {@link #LAYOUT_MODE_OPTICAL_BOUNDS}. 4871 * 4872 * @param layoutMode the layout mode to use during layout operations 4873 * 4874 * @see #getLayoutMode() 4875 */ 4876 public void setLayoutMode(int layoutMode) { 4877 if (mLayoutMode != layoutMode) { 4878 invalidateInheritedLayoutMode(layoutMode); 4879 setLayoutMode(layoutMode, layoutMode != LAYOUT_MODE_UNDEFINED); 4880 requestLayout(); 4881 } 4882 } 4883 4884 /** 4885 * Returns a new set of layout parameters based on the supplied attributes set. 4886 * 4887 * @param attrs the attributes to build the layout parameters from 4888 * 4889 * @return an instance of {@link android.view.ViewGroup.LayoutParams} or one 4890 * of its descendants 4891 */ 4892 public LayoutParams generateLayoutParams(AttributeSet attrs) { 4893 return new LayoutParams(getContext(), attrs); 4894 } 4895 4896 /** 4897 * Returns a safe set of layout parameters based on the supplied layout params. 4898 * When a ViewGroup is passed a View whose layout params do not pass the test of 4899 * {@link #checkLayoutParams(android.view.ViewGroup.LayoutParams)}, this method 4900 * is invoked. This method should return a new set of layout params suitable for 4901 * this ViewGroup, possibly by copying the appropriate attributes from the 4902 * specified set of layout params. 4903 * 4904 * @param p The layout parameters to convert into a suitable set of layout parameters 4905 * for this ViewGroup. 4906 * 4907 * @return an instance of {@link android.view.ViewGroup.LayoutParams} or one 4908 * of its descendants 4909 */ 4910 protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { 4911 return p; 4912 } 4913 4914 /** 4915 * Returns a set of default layout parameters. These parameters are requested 4916 * when the View passed to {@link #addView(View)} has no layout parameters 4917 * already set. If null is returned, an exception is thrown from addView. 4918 * 4919 * @return a set of default layout parameters or null 4920 */ 4921 protected LayoutParams generateDefaultLayoutParams() { 4922 return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); 4923 } 4924 4925 /** 4926 * {@inheritDoc} 4927 */ 4928 @Override 4929 protected void debug(int depth) { 4930 super.debug(depth); 4931 String output; 4932 4933 if (mFocused != null) { 4934 output = debugIndent(depth); 4935 output += "mFocused"; 4936 Log.d(VIEW_LOG_TAG, output); 4937 } 4938 if (mChildrenCount != 0) { 4939 output = debugIndent(depth); 4940 output += "{"; 4941 Log.d(VIEW_LOG_TAG, output); 4942 } 4943 int count = mChildrenCount; 4944 for (int i = 0; i < count; i++) { 4945 View child = mChildren[i]; 4946 child.debug(depth + 1); 4947 } 4948 4949 if (mChildrenCount != 0) { 4950 output = debugIndent(depth); 4951 output += "}"; 4952 Log.d(VIEW_LOG_TAG, output); 4953 } 4954 } 4955 4956 /** 4957 * Returns the position in the group of the specified child view. 4958 * 4959 * @param child the view for which to get the position 4960 * @return a positive integer representing the position of the view in the 4961 * group, or -1 if the view does not exist in the group 4962 */ 4963 public int indexOfChild(View child) { 4964 final int count = mChildrenCount; 4965 final View[] children = mChildren; 4966 for (int i = 0; i < count; i++) { 4967 if (children[i] == child) { 4968 return i; 4969 } 4970 } 4971 return -1; 4972 } 4973 4974 /** 4975 * Returns the number of children in the group. 4976 * 4977 * @return a positive integer representing the number of children in 4978 * the group 4979 */ 4980 public int getChildCount() { 4981 return mChildrenCount; 4982 } 4983 4984 /** 4985 * Returns the view at the specified position in the group. 4986 * 4987 * @param index the position at which to get the view from 4988 * @return the view at the specified position or null if the position 4989 * does not exist within the group 4990 */ 4991 public View getChildAt(int index) { 4992 if (index < 0 || index >= mChildrenCount) { 4993 return null; 4994 } 4995 return mChildren[index]; 4996 } 4997 4998 /** 4999 * Ask all of the children of this view to measure themselves, taking into 5000 * account both the MeasureSpec requirements for this view and its padding. 5001 * We skip children that are in the GONE state The heavy lifting is done in 5002 * getChildMeasureSpec. 5003 * 5004 * @param widthMeasureSpec The width requirements for this view 5005 * @param heightMeasureSpec The height requirements for this view 5006 */ 5007 protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec) { 5008 final int size = mChildrenCount; 5009 final View[] children = mChildren; 5010 for (int i = 0; i < size; ++i) { 5011 final View child = children[i]; 5012 if ((child.mViewFlags & VISIBILITY_MASK) != GONE) { 5013 measureChild(child, widthMeasureSpec, heightMeasureSpec); 5014 } 5015 } 5016 } 5017 5018 /** 5019 * Ask one of the children of this view to measure itself, taking into 5020 * account both the MeasureSpec requirements for this view and its padding. 5021 * The heavy lifting is done in getChildMeasureSpec. 5022 * 5023 * @param child The child to measure 5024 * @param parentWidthMeasureSpec The width requirements for this view 5025 * @param parentHeightMeasureSpec The height requirements for this view 5026 */ 5027 protected void measureChild(View child, int parentWidthMeasureSpec, 5028 int parentHeightMeasureSpec) { 5029 final LayoutParams lp = child.getLayoutParams(); 5030 5031 final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec, 5032 mPaddingLeft + mPaddingRight, lp.width); 5033 final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec, 5034 mPaddingTop + mPaddingBottom, lp.height); 5035 5036 child.measure(childWidthMeasureSpec, childHeightMeasureSpec); 5037 } 5038 5039 /** 5040 * Ask one of the children of this view to measure itself, taking into 5041 * account both the MeasureSpec requirements for this view and its padding 5042 * and margins. The child must have MarginLayoutParams The heavy lifting is 5043 * done in getChildMeasureSpec. 5044 * 5045 * @param child The child to measure 5046 * @param parentWidthMeasureSpec The width requirements for this view 5047 * @param widthUsed Extra space that has been used up by the parent 5048 * horizontally (possibly by other children of the parent) 5049 * @param parentHeightMeasureSpec The height requirements for this view 5050 * @param heightUsed Extra space that has been used up by the parent 5051 * vertically (possibly by other children of the parent) 5052 */ 5053 protected void measureChildWithMargins(View child, 5054 int parentWidthMeasureSpec, int widthUsed, 5055 int parentHeightMeasureSpec, int heightUsed) { 5056 final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams(); 5057 5058 final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec, 5059 mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin 5060 + widthUsed, lp.width); 5061 final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec, 5062 mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin 5063 + heightUsed, lp.height); 5064 5065 child.measure(childWidthMeasureSpec, childHeightMeasureSpec); 5066 } 5067 5068 /** 5069 * Does the hard part of measureChildren: figuring out the MeasureSpec to 5070 * pass to a particular child. This method figures out the right MeasureSpec 5071 * for one dimension (height or width) of one child view. 5072 * 5073 * The goal is to combine information from our MeasureSpec with the 5074 * LayoutParams of the child to get the best possible results. For example, 5075 * if the this view knows its size (because its MeasureSpec has a mode of 5076 * EXACTLY), and the child has indicated in its LayoutParams that it wants 5077 * to be the same size as the parent, the parent should ask the child to 5078 * layout given an exact size. 5079 * 5080 * @param spec The requirements for this view 5081 * @param padding The padding of this view for the current dimension and 5082 * margins, if applicable 5083 * @param childDimension How big the child wants to be in the current 5084 * dimension 5085 * @return a MeasureSpec integer for the child 5086 */ 5087 public static int getChildMeasureSpec(int spec, int padding, int childDimension) { 5088 int specMode = MeasureSpec.getMode(spec); 5089 int specSize = MeasureSpec.getSize(spec); 5090 5091 int size = Math.max(0, specSize - padding); 5092 5093 int resultSize = 0; 5094 int resultMode = 0; 5095 5096 switch (specMode) { 5097 // Parent has imposed an exact size on us 5098 case MeasureSpec.EXACTLY: 5099 if (childDimension >= 0) { 5100 resultSize = childDimension; 5101 resultMode = MeasureSpec.EXACTLY; 5102 } else if (childDimension == LayoutParams.MATCH_PARENT) { 5103 // Child wants to be our size. So be it. 5104 resultSize = size; 5105 resultMode = MeasureSpec.EXACTLY; 5106 } else if (childDimension == LayoutParams.WRAP_CONTENT) { 5107 // Child wants to determine its own size. It can't be 5108 // bigger than us. 5109 resultSize = size; 5110 resultMode = MeasureSpec.AT_MOST; 5111 } 5112 break; 5113 5114 // Parent has imposed a maximum size on us 5115 case MeasureSpec.AT_MOST: 5116 if (childDimension >= 0) { 5117 // Child wants a specific size... so be it 5118 resultSize = childDimension; 5119 resultMode = MeasureSpec.EXACTLY; 5120 } else if (childDimension == LayoutParams.MATCH_PARENT) { 5121 // Child wants to be our size, but our size is not fixed. 5122 // Constrain child to not be bigger than us. 5123 resultSize = size; 5124 resultMode = MeasureSpec.AT_MOST; 5125 } else if (childDimension == LayoutParams.WRAP_CONTENT) { 5126 // Child wants to determine its own size. It can't be 5127 // bigger than us. 5128 resultSize = size; 5129 resultMode = MeasureSpec.AT_MOST; 5130 } 5131 break; 5132 5133 // Parent asked to see how big we want to be 5134 case MeasureSpec.UNSPECIFIED: 5135 if (childDimension >= 0) { 5136 // Child wants a specific size... let him have it 5137 resultSize = childDimension; 5138 resultMode = MeasureSpec.EXACTLY; 5139 } else if (childDimension == LayoutParams.MATCH_PARENT) { 5140 // Child wants to be our size... find out how big it should 5141 // be 5142 resultSize = 0; 5143 resultMode = MeasureSpec.UNSPECIFIED; 5144 } else if (childDimension == LayoutParams.WRAP_CONTENT) { 5145 // Child wants to determine its own size.... find out how 5146 // big it should be 5147 resultSize = 0; 5148 resultMode = MeasureSpec.UNSPECIFIED; 5149 } 5150 break; 5151 } 5152 return MeasureSpec.makeMeasureSpec(resultSize, resultMode); 5153 } 5154 5155 5156 /** 5157 * Removes any pending animations for views that have been removed. Call 5158 * this if you don't want animations for exiting views to stack up. 5159 */ 5160 public void clearDisappearingChildren() { 5161 if (mDisappearingChildren != null) { 5162 mDisappearingChildren.clear(); 5163 invalidate(); 5164 } 5165 } 5166 5167 /** 5168 * Add a view which is removed from mChildren but still needs animation 5169 * 5170 * @param v View to add 5171 */ 5172 private void addDisappearingView(View v) { 5173 ArrayList<View> disappearingChildren = mDisappearingChildren; 5174 5175 if (disappearingChildren == null) { 5176 disappearingChildren = mDisappearingChildren = new ArrayList<View>(); 5177 } 5178 5179 disappearingChildren.add(v); 5180 } 5181 5182 /** 5183 * Cleanup a view when its animation is done. This may mean removing it from 5184 * the list of disappearing views. 5185 * 5186 * @param view The view whose animation has finished 5187 * @param animation The animation, cannot be null 5188 */ 5189 void finishAnimatingView(final View view, Animation animation) { 5190 final ArrayList<View> disappearingChildren = mDisappearingChildren; 5191 if (disappearingChildren != null) { 5192 if (disappearingChildren.contains(view)) { 5193 disappearingChildren.remove(view); 5194 5195 if (view.mAttachInfo != null) { 5196 view.dispatchDetachedFromWindow(); 5197 } 5198 5199 view.clearAnimation(); 5200 mGroupFlags |= FLAG_INVALIDATE_REQUIRED; 5201 } 5202 } 5203 5204 if (animation != null && !animation.getFillAfter()) { 5205 view.clearAnimation(); 5206 } 5207 5208 if ((view.mPrivateFlags & PFLAG_ANIMATION_STARTED) == PFLAG_ANIMATION_STARTED) { 5209 view.onAnimationEnd(); 5210 // Should be performed by onAnimationEnd() but this avoid an infinite loop, 5211 // so we'd rather be safe than sorry 5212 view.mPrivateFlags &= ~PFLAG_ANIMATION_STARTED; 5213 // Draw one more frame after the animation is done 5214 mGroupFlags |= FLAG_INVALIDATE_REQUIRED; 5215 } 5216 } 5217 5218 /** 5219 * Utility function called by View during invalidation to determine whether a view that 5220 * is invisible or gone should still be invalidated because it is being transitioned (and 5221 * therefore still needs to be drawn). 5222 */ 5223 boolean isViewTransitioning(View view) { 5224 return (mTransitioningViews != null && mTransitioningViews.contains(view)); 5225 } 5226 5227 /** 5228 * This method tells the ViewGroup that the given View object, which should have this 5229 * ViewGroup as its parent, 5230 * should be kept around (re-displayed when the ViewGroup draws its children) even if it 5231 * is removed from its parent. This allows animations, such as those used by 5232 * {@link android.app.Fragment} and {@link android.animation.LayoutTransition} to animate 5233 * the removal of views. A call to this method should always be accompanied by a later call 5234 * to {@link #endViewTransition(View)}, such as after an animation on the View has finished, 5235 * so that the View finally gets removed. 5236 * 5237 * @param view The View object to be kept visible even if it gets removed from its parent. 5238 */ 5239 public void startViewTransition(View view) { 5240 if (view.mParent == this) { 5241 if (mTransitioningViews == null) { 5242 mTransitioningViews = new ArrayList<View>(); 5243 } 5244 mTransitioningViews.add(view); 5245 } 5246 } 5247 5248 /** 5249 * This method should always be called following an earlier call to 5250 * {@link #startViewTransition(View)}. The given View is finally removed from its parent 5251 * and will no longer be displayed. Note that this method does not perform the functionality 5252 * of removing a view from its parent; it just discontinues the display of a View that 5253 * has previously been removed. 5254 * 5255 * @return view The View object that has been removed but is being kept around in the visible 5256 * hierarchy by an earlier call to {@link #startViewTransition(View)}. 5257 */ 5258 public void endViewTransition(View view) { 5259 if (mTransitioningViews != null) { 5260 mTransitioningViews.remove(view); 5261 final ArrayList<View> disappearingChildren = mDisappearingChildren; 5262 if (disappearingChildren != null && disappearingChildren.contains(view)) { 5263 disappearingChildren.remove(view); 5264 if (mVisibilityChangingChildren != null && 5265 mVisibilityChangingChildren.contains(view)) { 5266 mVisibilityChangingChildren.remove(view); 5267 } else { 5268 if (view.mAttachInfo != null) { 5269 view.dispatchDetachedFromWindow(); 5270 } 5271 if (view.mParent != null) { 5272 view.mParent = null; 5273 } 5274 } 5275 invalidate(); 5276 } 5277 } 5278 } 5279 5280 private LayoutTransition.TransitionListener mLayoutTransitionListener = 5281 new LayoutTransition.TransitionListener() { 5282 @Override 5283 public void startTransition(LayoutTransition transition, ViewGroup container, 5284 View view, int transitionType) { 5285 // We only care about disappearing items, since we need special logic to keep 5286 // those items visible after they've been 'removed' 5287 if (transitionType == LayoutTransition.DISAPPEARING) { 5288 startViewTransition(view); 5289 } 5290 } 5291 5292 @Override 5293 public void endTransition(LayoutTransition transition, ViewGroup container, 5294 View view, int transitionType) { 5295 if (mLayoutCalledWhileSuppressed && !transition.isChangingLayout()) { 5296 requestLayout(); 5297 mLayoutCalledWhileSuppressed = false; 5298 } 5299 if (transitionType == LayoutTransition.DISAPPEARING && mTransitioningViews != null) { 5300 endViewTransition(view); 5301 } 5302 } 5303 }; 5304 5305 /** 5306 * Tells this ViewGroup to suppress all layout() calls until layout 5307 * suppression is disabled with a later call to suppressLayout(false). 5308 * When layout suppression is disabled, a requestLayout() call is sent 5309 * if layout() was attempted while layout was being suppressed. 5310 * 5311 * @hide 5312 */ 5313 public void suppressLayout(boolean suppress) { 5314 mSuppressLayout = suppress; 5315 if (!suppress) { 5316 if (mLayoutCalledWhileSuppressed) { 5317 requestLayout(); 5318 mLayoutCalledWhileSuppressed = false; 5319 } 5320 } 5321 } 5322 5323 /** 5324 * {@inheritDoc} 5325 */ 5326 @Override 5327 public boolean gatherTransparentRegion(Region region) { 5328 // If no transparent regions requested, we are always opaque. 5329 final boolean meOpaque = (mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) == 0; 5330 if (meOpaque && region == null) { 5331 // The caller doesn't care about the region, so stop now. 5332 return true; 5333 } 5334 super.gatherTransparentRegion(region); 5335 final View[] children = mChildren; 5336 final int count = mChildrenCount; 5337 boolean noneOfTheChildrenAreTransparent = true; 5338 for (int i = 0; i < count; i++) { 5339 final View child = children[i]; 5340 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) { 5341 if (!child.gatherTransparentRegion(region)) { 5342 noneOfTheChildrenAreTransparent = false; 5343 } 5344 } 5345 } 5346 return meOpaque || noneOfTheChildrenAreTransparent; 5347 } 5348 5349 /** 5350 * {@inheritDoc} 5351 */ 5352 public void requestTransparentRegion(View child) { 5353 if (child != null) { 5354 child.mPrivateFlags |= View.PFLAG_REQUEST_TRANSPARENT_REGIONS; 5355 if (mParent != null) { 5356 mParent.requestTransparentRegion(this); 5357 } 5358 } 5359 } 5360 5361 5362 @Override 5363 protected boolean fitSystemWindows(Rect insets) { 5364 boolean done = super.fitSystemWindows(insets); 5365 if (!done) { 5366 final int count = mChildrenCount; 5367 final View[] children = mChildren; 5368 for (int i = 0; i < count; i++) { 5369 done = children[i].fitSystemWindows(insets); 5370 if (done) { 5371 break; 5372 } 5373 } 5374 } 5375 return done; 5376 } 5377 5378 /** 5379 * Returns the animation listener to which layout animation events are 5380 * sent. 5381 * 5382 * @return an {@link android.view.animation.Animation.AnimationListener} 5383 */ 5384 public Animation.AnimationListener getLayoutAnimationListener() { 5385 return mAnimationListener; 5386 } 5387 5388 @Override 5389 protected void drawableStateChanged() { 5390 super.drawableStateChanged(); 5391 5392 if ((mGroupFlags & FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE) != 0) { 5393 if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0) { 5394 throw new IllegalStateException("addStateFromChildren cannot be enabled if a" 5395 + " child has duplicateParentState set to true"); 5396 } 5397 5398 final View[] children = mChildren; 5399 final int count = mChildrenCount; 5400 5401 for (int i = 0; i < count; i++) { 5402 final View child = children[i]; 5403 if ((child.mViewFlags & DUPLICATE_PARENT_STATE) != 0) { 5404 child.refreshDrawableState(); 5405 } 5406 } 5407 } 5408 } 5409 5410 @Override 5411 public void jumpDrawablesToCurrentState() { 5412 super.jumpDrawablesToCurrentState(); 5413 final View[] children = mChildren; 5414 final int count = mChildrenCount; 5415 for (int i = 0; i < count; i++) { 5416 children[i].jumpDrawablesToCurrentState(); 5417 } 5418 } 5419 5420 @Override 5421 protected int[] onCreateDrawableState(int extraSpace) { 5422 if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) == 0) { 5423 return super.onCreateDrawableState(extraSpace); 5424 } 5425 5426 int need = 0; 5427 int n = getChildCount(); 5428 for (int i = 0; i < n; i++) { 5429 int[] childState = getChildAt(i).getDrawableState(); 5430 5431 if (childState != null) { 5432 need += childState.length; 5433 } 5434 } 5435 5436 int[] state = super.onCreateDrawableState(extraSpace + need); 5437 5438 for (int i = 0; i < n; i++) { 5439 int[] childState = getChildAt(i).getDrawableState(); 5440 5441 if (childState != null) { 5442 state = mergeDrawableStates(state, childState); 5443 } 5444 } 5445 5446 return state; 5447 } 5448 5449 /** 5450 * Sets whether this ViewGroup's drawable states also include 5451 * its children's drawable states. This is used, for example, to 5452 * make a group appear to be focused when its child EditText or button 5453 * is focused. 5454 */ 5455 public void setAddStatesFromChildren(boolean addsStates) { 5456 if (addsStates) { 5457 mGroupFlags |= FLAG_ADD_STATES_FROM_CHILDREN; 5458 } else { 5459 mGroupFlags &= ~FLAG_ADD_STATES_FROM_CHILDREN; 5460 } 5461 5462 refreshDrawableState(); 5463 } 5464 5465 /** 5466 * Returns whether this ViewGroup's drawable states also include 5467 * its children's drawable states. This is used, for example, to 5468 * make a group appear to be focused when its child EditText or button 5469 * is focused. 5470 */ 5471 public boolean addStatesFromChildren() { 5472 return (mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0; 5473 } 5474 5475 /** 5476 * If {@link #addStatesFromChildren} is true, refreshes this group's 5477 * drawable state (to include the states from its children). 5478 */ 5479 public void childDrawableStateChanged(View child) { 5480 if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0) { 5481 refreshDrawableState(); 5482 } 5483 } 5484 5485 /** 5486 * Specifies the animation listener to which layout animation events must 5487 * be sent. Only 5488 * {@link android.view.animation.Animation.AnimationListener#onAnimationStart(Animation)} 5489 * and 5490 * {@link android.view.animation.Animation.AnimationListener#onAnimationEnd(Animation)} 5491 * are invoked. 5492 * 5493 * @param animationListener the layout animation listener 5494 */ 5495 public void setLayoutAnimationListener(Animation.AnimationListener animationListener) { 5496 mAnimationListener = animationListener; 5497 } 5498 5499 /** 5500 * This method is called by LayoutTransition when there are 'changing' animations that need 5501 * to start after the layout/setup phase. The request is forwarded to the ViewAncestor, who 5502 * starts all pending transitions prior to the drawing phase in the current traversal. 5503 * 5504 * @param transition The LayoutTransition to be started on the next traversal. 5505 * 5506 * @hide 5507 */ 5508 public void requestTransitionStart(LayoutTransition transition) { 5509 ViewRootImpl viewAncestor = getViewRootImpl(); 5510 if (viewAncestor != null) { 5511 viewAncestor.requestTransitionStart(transition); 5512 } 5513 } 5514 5515 /** 5516 * @hide 5517 */ 5518 @Override 5519 public void resolveRtlPropertiesIfNeeded() { 5520 super.resolveRtlPropertiesIfNeeded(); 5521 int count = getChildCount(); 5522 for (int i = 0; i < count; i++) { 5523 final View child = getChildAt(i); 5524 if (child.isLayoutDirectionInherited()) { 5525 child.resolveRtlPropertiesIfNeeded(); 5526 } 5527 } 5528 } 5529 5530 /** 5531 * @hide 5532 */ 5533 @Override 5534 public boolean resolveLayoutDirection() { 5535 final boolean result = super.resolveLayoutDirection(); 5536 if (result) { 5537 int count = getChildCount(); 5538 for (int i = 0; i < count; i++) { 5539 final View child = getChildAt(i); 5540 if (child.isLayoutDirectionInherited()) { 5541 child.resolveLayoutDirection(); 5542 } 5543 } 5544 } 5545 return result; 5546 } 5547 5548 /** 5549 * @hide 5550 */ 5551 @Override 5552 public boolean resolveTextDirection() { 5553 final boolean result = super.resolveTextDirection(); 5554 if (result) { 5555 int count = getChildCount(); 5556 for (int i = 0; i < count; i++) { 5557 final View child = getChildAt(i); 5558 if (child.isTextDirectionInherited()) { 5559 child.resolveTextDirection(); 5560 } 5561 } 5562 } 5563 return result; 5564 } 5565 5566 /** 5567 * @hide 5568 */ 5569 @Override 5570 public boolean resolveTextAlignment() { 5571 final boolean result = super.resolveTextAlignment(); 5572 if (result) { 5573 int count = getChildCount(); 5574 for (int i = 0; i < count; i++) { 5575 final View child = getChildAt(i); 5576 if (child.isTextAlignmentInherited()) { 5577 child.resolveTextAlignment(); 5578 } 5579 } 5580 } 5581 return result; 5582 } 5583 5584 /** 5585 * @hide 5586 */ 5587 @Override 5588 public void resolvePadding() { 5589 super.resolvePadding(); 5590 int count = getChildCount(); 5591 for (int i = 0; i < count; i++) { 5592 final View child = getChildAt(i); 5593 if (child.isLayoutDirectionInherited()) { 5594 child.resolvePadding(); 5595 } 5596 } 5597 } 5598 5599 /** 5600 * @hide 5601 */ 5602 @Override 5603 protected void resolveDrawables() { 5604 super.resolveDrawables(); 5605 int count = getChildCount(); 5606 for (int i = 0; i < count; i++) { 5607 final View child = getChildAt(i); 5608 if (child.isLayoutDirectionInherited()) { 5609 child.resolveDrawables(); 5610 } 5611 } 5612 } 5613 5614 /** 5615 * @hide 5616 */ 5617 @Override 5618 public void resolveLayoutParams() { 5619 super.resolveLayoutParams(); 5620 int count = getChildCount(); 5621 for (int i = 0; i < count; i++) { 5622 final View child = getChildAt(i); 5623 child.resolveLayoutParams(); 5624 } 5625 } 5626 5627 /** 5628 * @hide 5629 */ 5630 @Override 5631 public void resetResolvedLayoutDirection() { 5632 super.resetResolvedLayoutDirection(); 5633 5634 int count = getChildCount(); 5635 for (int i = 0; i < count; i++) { 5636 final View child = getChildAt(i); 5637 if (child.isLayoutDirectionInherited()) { 5638 child.resetResolvedLayoutDirection(); 5639 } 5640 } 5641 } 5642 5643 /** 5644 * @hide 5645 */ 5646 @Override 5647 public void resetResolvedTextDirection() { 5648 super.resetResolvedTextDirection(); 5649 5650 int count = getChildCount(); 5651 for (int i = 0; i < count; i++) { 5652 final View child = getChildAt(i); 5653 if (child.isTextDirectionInherited()) { 5654 child.resetResolvedTextDirection(); 5655 } 5656 } 5657 } 5658 5659 /** 5660 * @hide 5661 */ 5662 @Override 5663 public void resetResolvedTextAlignment() { 5664 super.resetResolvedTextAlignment(); 5665 5666 int count = getChildCount(); 5667 for (int i = 0; i < count; i++) { 5668 final View child = getChildAt(i); 5669 if (child.isTextAlignmentInherited()) { 5670 child.resetResolvedTextAlignment(); 5671 } 5672 } 5673 } 5674 5675 /** 5676 * @hide 5677 */ 5678 @Override 5679 public void resetResolvedPadding() { 5680 super.resetResolvedPadding(); 5681 5682 int count = getChildCount(); 5683 for (int i = 0; i < count; i++) { 5684 final View child = getChildAt(i); 5685 if (child.isLayoutDirectionInherited()) { 5686 child.resetResolvedPadding(); 5687 } 5688 } 5689 } 5690 5691 /** 5692 * @hide 5693 */ 5694 @Override 5695 protected void resetResolvedDrawables() { 5696 super.resetResolvedDrawables(); 5697 5698 int count = getChildCount(); 5699 for (int i = 0; i < count; i++) { 5700 final View child = getChildAt(i); 5701 if (child.isLayoutDirectionInherited()) { 5702 child.resetResolvedDrawables(); 5703 } 5704 } 5705 } 5706 5707 /** 5708 * Return true if the pressed state should be delayed for children or descendants of this 5709 * ViewGroup. Generally, this should be done for containers that can scroll, such as a List. 5710 * This prevents the pressed state from appearing when the user is actually trying to scroll 5711 * the content. 5712 * 5713 * The default implementation returns true for compatibility reasons. Subclasses that do 5714 * not scroll should generally override this method and return false. 5715 */ 5716 public boolean shouldDelayChildPressedState() { 5717 return true; 5718 } 5719 5720 /** @hide */ 5721 protected void onSetLayoutParams(View child, LayoutParams layoutParams) { 5722 } 5723 5724 /** 5725 * LayoutParams are used by views to tell their parents how they want to be 5726 * laid out. See 5727 * {@link android.R.styleable#ViewGroup_Layout ViewGroup Layout Attributes} 5728 * for a list of all child view attributes that this class supports. 5729 * 5730 * <p> 5731 * The base LayoutParams class just describes how big the view wants to be 5732 * for both width and height. For each dimension, it can specify one of: 5733 * <ul> 5734 * <li>FILL_PARENT (renamed MATCH_PARENT in API Level 8 and higher), which 5735 * means that the view wants to be as big as its parent (minus padding) 5736 * <li> WRAP_CONTENT, which means that the view wants to be just big enough 5737 * to enclose its content (plus padding) 5738 * <li> an exact number 5739 * </ul> 5740 * There are subclasses of LayoutParams for different subclasses of 5741 * ViewGroup. For example, AbsoluteLayout has its own subclass of 5742 * LayoutParams which adds an X and Y value.</p> 5743 * 5744 * <div class="special reference"> 5745 * <h3>Developer Guides</h3> 5746 * <p>For more information about creating user interface layouts, read the 5747 * <a href="{@docRoot}guide/topics/ui/declaring-layout.html">XML Layouts</a> developer 5748 * guide.</p></div> 5749 * 5750 * @attr ref android.R.styleable#ViewGroup_Layout_layout_height 5751 * @attr ref android.R.styleable#ViewGroup_Layout_layout_width 5752 */ 5753 public static class LayoutParams { 5754 /** 5755 * Special value for the height or width requested by a View. 5756 * FILL_PARENT means that the view wants to be as big as its parent, 5757 * minus the parent's padding, if any. This value is deprecated 5758 * starting in API Level 8 and replaced by {@link #MATCH_PARENT}. 5759 */ 5760 @SuppressWarnings({"UnusedDeclaration"}) 5761 @Deprecated 5762 public static final int FILL_PARENT = -1; 5763 5764 /** 5765 * Special value for the height or width requested by a View. 5766 * MATCH_PARENT means that the view wants to be as big as its parent, 5767 * minus the parent's padding, if any. Introduced in API Level 8. 5768 */ 5769 public static final int MATCH_PARENT = -1; 5770 5771 /** 5772 * Special value for the height or width requested by a View. 5773 * WRAP_CONTENT means that the view wants to be just large enough to fit 5774 * its own internal content, taking its own padding into account. 5775 */ 5776 public static final int WRAP_CONTENT = -2; 5777 5778 /** 5779 * Information about how wide the view wants to be. Can be one of the 5780 * constants FILL_PARENT (replaced by MATCH_PARENT , 5781 * in API Level 8) or WRAP_CONTENT. or an exact size. 5782 */ 5783 @ViewDebug.ExportedProperty(category = "layout", mapping = { 5784 @ViewDebug.IntToString(from = MATCH_PARENT, to = "MATCH_PARENT"), 5785 @ViewDebug.IntToString(from = WRAP_CONTENT, to = "WRAP_CONTENT") 5786 }) 5787 public int width; 5788 5789 /** 5790 * Information about how tall the view wants to be. Can be one of the 5791 * constants FILL_PARENT (replaced by MATCH_PARENT , 5792 * in API Level 8) or WRAP_CONTENT. or an exact size. 5793 */ 5794 @ViewDebug.ExportedProperty(category = "layout", mapping = { 5795 @ViewDebug.IntToString(from = MATCH_PARENT, to = "MATCH_PARENT"), 5796 @ViewDebug.IntToString(from = WRAP_CONTENT, to = "WRAP_CONTENT") 5797 }) 5798 public int height; 5799 5800 /** 5801 * Used to animate layouts. 5802 */ 5803 public LayoutAnimationController.AnimationParameters layoutAnimationParameters; 5804 5805 /** 5806 * Creates a new set of layout parameters. The values are extracted from 5807 * the supplied attributes set and context. The XML attributes mapped 5808 * to this set of layout parameters are: 5809 * 5810 * <ul> 5811 * <li><code>layout_width</code>: the width, either an exact value, 5812 * {@link #WRAP_CONTENT}, or {@link #FILL_PARENT} (replaced by 5813 * {@link #MATCH_PARENT} in API Level 8)</li> 5814 * <li><code>layout_height</code>: the height, either an exact value, 5815 * {@link #WRAP_CONTENT}, or {@link #FILL_PARENT} (replaced by 5816 * {@link #MATCH_PARENT} in API Level 8)</li> 5817 * </ul> 5818 * 5819 * @param c the application environment 5820 * @param attrs the set of attributes from which to extract the layout 5821 * parameters' values 5822 */ 5823 public LayoutParams(Context c, AttributeSet attrs) { 5824 TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ViewGroup_Layout); 5825 setBaseAttributes(a, 5826 R.styleable.ViewGroup_Layout_layout_width, 5827 R.styleable.ViewGroup_Layout_layout_height); 5828 a.recycle(); 5829 } 5830 5831 /** 5832 * Creates a new set of layout parameters with the specified width 5833 * and height. 5834 * 5835 * @param width the width, either {@link #WRAP_CONTENT}, 5836 * {@link #FILL_PARENT} (replaced by {@link #MATCH_PARENT} in 5837 * API Level 8), or a fixed size in pixels 5838 * @param height the height, either {@link #WRAP_CONTENT}, 5839 * {@link #FILL_PARENT} (replaced by {@link #MATCH_PARENT} in 5840 * API Level 8), or a fixed size in pixels 5841 */ 5842 public LayoutParams(int width, int height) { 5843 this.width = width; 5844 this.height = height; 5845 } 5846 5847 /** 5848 * Copy constructor. Clones the width and height values of the source. 5849 * 5850 * @param source The layout params to copy from. 5851 */ 5852 public LayoutParams(LayoutParams source) { 5853 this.width = source.width; 5854 this.height = source.height; 5855 } 5856 5857 /** 5858 * Used internally by MarginLayoutParams. 5859 * @hide 5860 */ 5861 LayoutParams() { 5862 } 5863 5864 /** 5865 * Extracts the layout parameters from the supplied attributes. 5866 * 5867 * @param a the style attributes to extract the parameters from 5868 * @param widthAttr the identifier of the width attribute 5869 * @param heightAttr the identifier of the height attribute 5870 */ 5871 protected void setBaseAttributes(TypedArray a, int widthAttr, int heightAttr) { 5872 width = a.getLayoutDimension(widthAttr, "layout_width"); 5873 height = a.getLayoutDimension(heightAttr, "layout_height"); 5874 } 5875 5876 /** 5877 * Resolve layout parameters depending on the layout direction. Subclasses that care about 5878 * layoutDirection changes should override this method. The default implementation does 5879 * nothing. 5880 * 5881 * @param layoutDirection the direction of the layout 5882 * 5883 * {@link View#LAYOUT_DIRECTION_LTR} 5884 * {@link View#LAYOUT_DIRECTION_RTL} 5885 */ 5886 public void resolveLayoutDirection(int layoutDirection) { 5887 } 5888 5889 /** 5890 * Returns a String representation of this set of layout parameters. 5891 * 5892 * @param output the String to prepend to the internal representation 5893 * @return a String with the following format: output + 5894 * "ViewGroup.LayoutParams={ width=WIDTH, height=HEIGHT }" 5895 * 5896 * @hide 5897 */ 5898 public String debug(String output) { 5899 return output + "ViewGroup.LayoutParams={ width=" 5900 + sizeToString(width) + ", height=" + sizeToString(height) + " }"; 5901 } 5902 5903 /** 5904 * Use {@code canvas} to draw suitable debugging annotations for these LayoutParameters. 5905 * 5906 * @param view the view that contains these layout parameters 5907 * @param canvas the canvas on which to draw 5908 * 5909 * @hide 5910 */ 5911 public void onDebugDraw(View view, Canvas canvas, Paint paint) { 5912 } 5913 5914 /** 5915 * Converts the specified size to a readable String. 5916 * 5917 * @param size the size to convert 5918 * @return a String instance representing the supplied size 5919 * 5920 * @hide 5921 */ 5922 protected static String sizeToString(int size) { 5923 if (size == WRAP_CONTENT) { 5924 return "wrap-content"; 5925 } 5926 if (size == MATCH_PARENT) { 5927 return "match-parent"; 5928 } 5929 return String.valueOf(size); 5930 } 5931 } 5932 5933 /** 5934 * Per-child layout information for layouts that support margins. 5935 * See 5936 * {@link android.R.styleable#ViewGroup_MarginLayout ViewGroup Margin Layout Attributes} 5937 * for a list of all child view attributes that this class supports. 5938 */ 5939 public static class MarginLayoutParams extends ViewGroup.LayoutParams { 5940 /** 5941 * The left margin in pixels of the child. 5942 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value 5943 * to this field. 5944 */ 5945 @ViewDebug.ExportedProperty(category = "layout") 5946 public int leftMargin; 5947 5948 /** 5949 * The top margin in pixels of the child. 5950 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value 5951 * to this field. 5952 */ 5953 @ViewDebug.ExportedProperty(category = "layout") 5954 public int topMargin; 5955 5956 /** 5957 * The right margin in pixels of the child. 5958 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value 5959 * to this field. 5960 */ 5961 @ViewDebug.ExportedProperty(category = "layout") 5962 public int rightMargin; 5963 5964 /** 5965 * The bottom margin in pixels of the child. 5966 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value 5967 * to this field. 5968 */ 5969 @ViewDebug.ExportedProperty(category = "layout") 5970 public int bottomMargin; 5971 5972 /** 5973 * The start margin in pixels of the child. 5974 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value 5975 * to this field. 5976 */ 5977 @ViewDebug.ExportedProperty(category = "layout") 5978 private int startMargin = DEFAULT_MARGIN_RELATIVE; 5979 5980 /** 5981 * The end margin in pixels of the child. 5982 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value 5983 * to this field. 5984 */ 5985 @ViewDebug.ExportedProperty(category = "layout") 5986 private int endMargin = DEFAULT_MARGIN_RELATIVE; 5987 5988 /** 5989 * The default start and end margin. 5990 * @hide 5991 */ 5992 public static final int DEFAULT_MARGIN_RELATIVE = Integer.MIN_VALUE; 5993 5994 /** 5995 * Bit 0: layout direction 5996 * Bit 1: layout direction 5997 * Bit 2: left margin undefined 5998 * Bit 3: right margin undefined 5999 * Bit 4: is RTL compatibility mode 6000 * Bit 5: need resolution 6001 * 6002 * Bit 6 to 7 not used 6003 * 6004 * @hide 6005 */ 6006 @ViewDebug.ExportedProperty(category = "layout", flagMapping = { 6007 @ViewDebug.FlagToString(mask = LAYOUT_DIRECTION_MASK, 6008 equals = LAYOUT_DIRECTION_MASK, name = "LAYOUT_DIRECTION"), 6009 @ViewDebug.FlagToString(mask = LEFT_MARGIN_UNDEFINED_MASK, 6010 equals = LEFT_MARGIN_UNDEFINED_MASK, name = "LEFT_MARGIN_UNDEFINED_MASK"), 6011 @ViewDebug.FlagToString(mask = RIGHT_MARGIN_UNDEFINED_MASK, 6012 equals = RIGHT_MARGIN_UNDEFINED_MASK, name = "RIGHT_MARGIN_UNDEFINED_MASK"), 6013 @ViewDebug.FlagToString(mask = RTL_COMPATIBILITY_MODE_MASK, 6014 equals = RTL_COMPATIBILITY_MODE_MASK, name = "RTL_COMPATIBILITY_MODE_MASK"), 6015 @ViewDebug.FlagToString(mask = NEED_RESOLUTION_MASK, 6016 equals = NEED_RESOLUTION_MASK, name = "NEED_RESOLUTION_MASK") 6017 }) 6018 byte mMarginFlags; 6019 6020 private static final int LAYOUT_DIRECTION_MASK = 0x00000003; 6021 private static final int LEFT_MARGIN_UNDEFINED_MASK = 0x00000004; 6022 private static final int RIGHT_MARGIN_UNDEFINED_MASK = 0x00000008; 6023 private static final int RTL_COMPATIBILITY_MODE_MASK = 0x00000010; 6024 private static final int NEED_RESOLUTION_MASK = 0x00000020; 6025 6026 private static final int DEFAULT_MARGIN_RESOLVED = 0; 6027 private static final int UNDEFINED_MARGIN = DEFAULT_MARGIN_RELATIVE; 6028 6029 /** 6030 * Creates a new set of layout parameters. The values are extracted from 6031 * the supplied attributes set and context. 6032 * 6033 * @param c the application environment 6034 * @param attrs the set of attributes from which to extract the layout 6035 * parameters' values 6036 */ 6037 public MarginLayoutParams(Context c, AttributeSet attrs) { 6038 super(); 6039 6040 TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ViewGroup_MarginLayout); 6041 setBaseAttributes(a, 6042 R.styleable.ViewGroup_MarginLayout_layout_width, 6043 R.styleable.ViewGroup_MarginLayout_layout_height); 6044 6045 int margin = a.getDimensionPixelSize( 6046 com.android.internal.R.styleable.ViewGroup_MarginLayout_layout_margin, -1); 6047 if (margin >= 0) { 6048 leftMargin = margin; 6049 topMargin = margin; 6050 rightMargin= margin; 6051 bottomMargin = margin; 6052 } else { 6053 leftMargin = a.getDimensionPixelSize( 6054 R.styleable.ViewGroup_MarginLayout_layout_marginLeft, 6055 UNDEFINED_MARGIN); 6056 if (leftMargin == UNDEFINED_MARGIN) { 6057 mMarginFlags |= LEFT_MARGIN_UNDEFINED_MASK; 6058 leftMargin = DEFAULT_MARGIN_RESOLVED; 6059 } 6060 rightMargin = a.getDimensionPixelSize( 6061 R.styleable.ViewGroup_MarginLayout_layout_marginRight, 6062 UNDEFINED_MARGIN); 6063 if (rightMargin == UNDEFINED_MARGIN) { 6064 mMarginFlags |= RIGHT_MARGIN_UNDEFINED_MASK; 6065 rightMargin = DEFAULT_MARGIN_RESOLVED; 6066 } 6067 6068 topMargin = a.getDimensionPixelSize( 6069 R.styleable.ViewGroup_MarginLayout_layout_marginTop, 6070 DEFAULT_MARGIN_RESOLVED); 6071 bottomMargin = a.getDimensionPixelSize( 6072 R.styleable.ViewGroup_MarginLayout_layout_marginBottom, 6073 DEFAULT_MARGIN_RESOLVED); 6074 6075 startMargin = a.getDimensionPixelSize( 6076 R.styleable.ViewGroup_MarginLayout_layout_marginStart, 6077 DEFAULT_MARGIN_RELATIVE); 6078 endMargin = a.getDimensionPixelSize( 6079 R.styleable.ViewGroup_MarginLayout_layout_marginEnd, 6080 DEFAULT_MARGIN_RELATIVE); 6081 6082 if (isMarginRelative()) { 6083 mMarginFlags |= NEED_RESOLUTION_MASK; 6084 } 6085 } 6086 6087 final boolean hasRtlSupport = c.getApplicationInfo().hasRtlSupport(); 6088 final int targetSdkVersion = c.getApplicationInfo().targetSdkVersion; 6089 if (targetSdkVersion < JELLY_BEAN_MR1 || !hasRtlSupport) { 6090 mMarginFlags |= RTL_COMPATIBILITY_MODE_MASK; 6091 } 6092 6093 // Layout direction is LTR by default 6094 mMarginFlags |= LAYOUT_DIRECTION_LTR; 6095 6096 a.recycle(); 6097 } 6098 6099 /** 6100 * {@inheritDoc} 6101 */ 6102 public MarginLayoutParams(int width, int height) { 6103 super(width, height); 6104 6105 mMarginFlags |= LEFT_MARGIN_UNDEFINED_MASK; 6106 mMarginFlags |= RIGHT_MARGIN_UNDEFINED_MASK; 6107 6108 mMarginFlags &= ~NEED_RESOLUTION_MASK; 6109 mMarginFlags &= ~RTL_COMPATIBILITY_MODE_MASK; 6110 } 6111 6112 /** 6113 * Copy constructor. Clones the width, height and margin values of the source. 6114 * 6115 * @param source The layout params to copy from. 6116 */ 6117 public MarginLayoutParams(MarginLayoutParams source) { 6118 this.width = source.width; 6119 this.height = source.height; 6120 6121 this.leftMargin = source.leftMargin; 6122 this.topMargin = source.topMargin; 6123 this.rightMargin = source.rightMargin; 6124 this.bottomMargin = source.bottomMargin; 6125 this.startMargin = source.startMargin; 6126 this.endMargin = source.endMargin; 6127 6128 this.mMarginFlags = source.mMarginFlags; 6129 } 6130 6131 /** 6132 * {@inheritDoc} 6133 */ 6134 public MarginLayoutParams(LayoutParams source) { 6135 super(source); 6136 6137 mMarginFlags |= LEFT_MARGIN_UNDEFINED_MASK; 6138 mMarginFlags |= RIGHT_MARGIN_UNDEFINED_MASK; 6139 6140 mMarginFlags &= ~NEED_RESOLUTION_MASK; 6141 mMarginFlags &= ~RTL_COMPATIBILITY_MODE_MASK; 6142 } 6143 6144 /** 6145 * Sets the margins, in pixels. A call to {@link android.view.View#requestLayout()} needs 6146 * to be done so that the new margins are taken into account. Left and right margins may be 6147 * overriden by {@link android.view.View#requestLayout()} depending on layout direction. 6148 * 6149 * @param left the left margin size 6150 * @param top the top margin size 6151 * @param right the right margin size 6152 * @param bottom the bottom margin size 6153 * 6154 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginLeft 6155 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginTop 6156 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginRight 6157 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginBottom 6158 */ 6159 public void setMargins(int left, int top, int right, int bottom) { 6160 leftMargin = left; 6161 topMargin = top; 6162 rightMargin = right; 6163 bottomMargin = bottom; 6164 mMarginFlags &= ~LEFT_MARGIN_UNDEFINED_MASK; 6165 mMarginFlags &= ~RIGHT_MARGIN_UNDEFINED_MASK; 6166 if (isMarginRelative()) { 6167 mMarginFlags |= NEED_RESOLUTION_MASK; 6168 } else { 6169 mMarginFlags &= ~NEED_RESOLUTION_MASK; 6170 } 6171 } 6172 6173 /** 6174 * Sets the relative margins, in pixels. A call to {@link android.view.View#requestLayout()} 6175 * needs to be done so that the new relative margins are taken into account. Left and right 6176 * margins may be overriden by {@link android.view.View#requestLayout()} depending on layout 6177 * direction. 6178 * 6179 * @param start the start margin size 6180 * @param top the top margin size 6181 * @param end the right margin size 6182 * @param bottom the bottom margin size 6183 * 6184 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart 6185 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginTop 6186 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd 6187 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginBottom 6188 * 6189 * @hide 6190 */ 6191 public void setMarginsRelative(int start, int top, int end, int bottom) { 6192 startMargin = start; 6193 topMargin = top; 6194 endMargin = end; 6195 bottomMargin = bottom; 6196 mMarginFlags |= NEED_RESOLUTION_MASK; 6197 } 6198 6199 /** 6200 * Sets the relative start margin. 6201 * 6202 * @param start the start margin size 6203 * 6204 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart 6205 */ 6206 public void setMarginStart(int start) { 6207 startMargin = start; 6208 mMarginFlags |= NEED_RESOLUTION_MASK; 6209 } 6210 6211 /** 6212 * Returns the start margin in pixels. 6213 * 6214 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart 6215 * 6216 * @return the start margin in pixels. 6217 */ 6218 public int getMarginStart() { 6219 if (startMargin != DEFAULT_MARGIN_RELATIVE) return startMargin; 6220 if ((mMarginFlags & NEED_RESOLUTION_MASK) == NEED_RESOLUTION_MASK) { 6221 doResolveMargins(); 6222 } 6223 switch(mMarginFlags & LAYOUT_DIRECTION_MASK) { 6224 case View.LAYOUT_DIRECTION_RTL: 6225 return rightMargin; 6226 case View.LAYOUT_DIRECTION_LTR: 6227 default: 6228 return leftMargin; 6229 } 6230 } 6231 6232 /** 6233 * Sets the relative end margin. 6234 * 6235 * @param end the end margin size 6236 * 6237 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd 6238 */ 6239 public void setMarginEnd(int end) { 6240 endMargin = end; 6241 mMarginFlags |= NEED_RESOLUTION_MASK; 6242 } 6243 6244 /** 6245 * Returns the end margin in pixels. 6246 * 6247 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd 6248 * 6249 * @return the end margin in pixels. 6250 */ 6251 public int getMarginEnd() { 6252 if (endMargin != DEFAULT_MARGIN_RELATIVE) return endMargin; 6253 if ((mMarginFlags & NEED_RESOLUTION_MASK) == NEED_RESOLUTION_MASK) { 6254 doResolveMargins(); 6255 } 6256 switch(mMarginFlags & LAYOUT_DIRECTION_MASK) { 6257 case View.LAYOUT_DIRECTION_RTL: 6258 return leftMargin; 6259 case View.LAYOUT_DIRECTION_LTR: 6260 default: 6261 return rightMargin; 6262 } 6263 } 6264 6265 /** 6266 * Check if margins are relative. 6267 * 6268 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart 6269 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd 6270 * 6271 * @return true if either marginStart or marginEnd has been set. 6272 */ 6273 public boolean isMarginRelative() { 6274 return (startMargin != DEFAULT_MARGIN_RELATIVE || endMargin != DEFAULT_MARGIN_RELATIVE); 6275 } 6276 6277 /** 6278 * Set the layout direction 6279 * @param layoutDirection the layout direction. 6280 * Should be either {@link View#LAYOUT_DIRECTION_LTR} 6281 * or {@link View#LAYOUT_DIRECTION_RTL}. 6282 */ 6283 public void setLayoutDirection(int layoutDirection) { 6284 if (layoutDirection != View.LAYOUT_DIRECTION_LTR && 6285 layoutDirection != View.LAYOUT_DIRECTION_RTL) return; 6286 if (layoutDirection != (mMarginFlags & LAYOUT_DIRECTION_MASK)) { 6287 mMarginFlags &= ~LAYOUT_DIRECTION_MASK; 6288 mMarginFlags |= (layoutDirection & LAYOUT_DIRECTION_MASK); 6289 if (isMarginRelative()) { 6290 mMarginFlags |= NEED_RESOLUTION_MASK; 6291 } else { 6292 mMarginFlags &= ~NEED_RESOLUTION_MASK; 6293 } 6294 } 6295 } 6296 6297 /** 6298 * Retuns the layout direction. Can be either {@link View#LAYOUT_DIRECTION_LTR} or 6299 * {@link View#LAYOUT_DIRECTION_RTL}. 6300 * 6301 * @return the layout direction. 6302 */ 6303 public int getLayoutDirection() { 6304 return (mMarginFlags & LAYOUT_DIRECTION_MASK); 6305 } 6306 6307 /** 6308 * This will be called by {@link android.view.View#requestLayout()}. Left and Right margins 6309 * may be overridden depending on layout direction. 6310 */ 6311 @Override 6312 public void resolveLayoutDirection(int layoutDirection) { 6313 setLayoutDirection(layoutDirection); 6314 6315 // No relative margin or pre JB-MR1 case or no need to resolve, just dont do anything 6316 // Will use the left and right margins if no relative margin is defined. 6317 if (!isMarginRelative() || 6318 (mMarginFlags & NEED_RESOLUTION_MASK) != NEED_RESOLUTION_MASK) return; 6319 6320 // Proceed with resolution 6321 doResolveMargins(); 6322 } 6323 6324 private void doResolveMargins() { 6325 if ((mMarginFlags & RTL_COMPATIBILITY_MODE_MASK) == RTL_COMPATIBILITY_MODE_MASK) { 6326 // if left or right margins are not defined and if we have some start or end margin 6327 // defined then use those start and end margins. 6328 if ((mMarginFlags & LEFT_MARGIN_UNDEFINED_MASK) == LEFT_MARGIN_UNDEFINED_MASK 6329 && startMargin > DEFAULT_MARGIN_RELATIVE) { 6330 leftMargin = startMargin; 6331 } 6332 if ((mMarginFlags & RIGHT_MARGIN_UNDEFINED_MASK) == RIGHT_MARGIN_UNDEFINED_MASK 6333 && endMargin > DEFAULT_MARGIN_RELATIVE) { 6334 rightMargin = endMargin; 6335 } 6336 } else { 6337 // We have some relative margins (either the start one or the end one or both). So use 6338 // them and override what has been defined for left and right margins. If either start 6339 // or end margin is not defined, just set it to default "0". 6340 switch(mMarginFlags & LAYOUT_DIRECTION_MASK) { 6341 case View.LAYOUT_DIRECTION_RTL: 6342 leftMargin = (endMargin > DEFAULT_MARGIN_RELATIVE) ? 6343 endMargin : DEFAULT_MARGIN_RESOLVED; 6344 rightMargin = (startMargin > DEFAULT_MARGIN_RELATIVE) ? 6345 startMargin : DEFAULT_MARGIN_RESOLVED; 6346 break; 6347 case View.LAYOUT_DIRECTION_LTR: 6348 default: 6349 leftMargin = (startMargin > DEFAULT_MARGIN_RELATIVE) ? 6350 startMargin : DEFAULT_MARGIN_RESOLVED; 6351 rightMargin = (endMargin > DEFAULT_MARGIN_RELATIVE) ? 6352 endMargin : DEFAULT_MARGIN_RESOLVED; 6353 break; 6354 } 6355 } 6356 mMarginFlags &= ~NEED_RESOLUTION_MASK; 6357 } 6358 6359 /** 6360 * @hide 6361 */ 6362 public boolean isLayoutRtl() { 6363 return ((mMarginFlags & LAYOUT_DIRECTION_MASK) == View.LAYOUT_DIRECTION_RTL); 6364 } 6365 6366 /** 6367 * @hide 6368 */ 6369 @Override 6370 public void onDebugDraw(View view, Canvas canvas, Paint paint) { 6371 Insets oi = isLayoutModeOptical(view.mParent) ? view.getOpticalInsets() : Insets.NONE; 6372 6373 fillDifference(canvas, 6374 view.getLeft() + oi.left, 6375 view.getTop() + oi.top, 6376 view.getRight() - oi.right, 6377 view.getBottom() - oi.bottom, 6378 leftMargin, 6379 topMargin, 6380 rightMargin, 6381 bottomMargin, 6382 paint); 6383 } 6384 } 6385 6386 /* Describes a touched view and the ids of the pointers that it has captured. 6387 * 6388 * This code assumes that pointer ids are always in the range 0..31 such that 6389 * it can use a bitfield to track which pointer ids are present. 6390 * As it happens, the lower layers of the input dispatch pipeline also use the 6391 * same trick so the assumption should be safe here... 6392 */ 6393 private static final class TouchTarget { 6394 private static final int MAX_RECYCLED = 32; 6395 private static final Object sRecycleLock = new Object(); 6396 private static TouchTarget sRecycleBin; 6397 private static int sRecycledCount; 6398 6399 public static final int ALL_POINTER_IDS = -1; // all ones 6400 6401 // The touched child view. 6402 public View child; 6403 6404 // The combined bit mask of pointer ids for all pointers captured by the target. 6405 public int pointerIdBits; 6406 6407 // The next target in the target list. 6408 public TouchTarget next; 6409 6410 private TouchTarget() { 6411 } 6412 6413 public static TouchTarget obtain(View child, int pointerIdBits) { 6414 final TouchTarget target; 6415 synchronized (sRecycleLock) { 6416 if (sRecycleBin == null) { 6417 target = new TouchTarget(); 6418 } else { 6419 target = sRecycleBin; 6420 sRecycleBin = target.next; 6421 sRecycledCount--; 6422 target.next = null; 6423 } 6424 } 6425 target.child = child; 6426 target.pointerIdBits = pointerIdBits; 6427 return target; 6428 } 6429 6430 public void recycle() { 6431 synchronized (sRecycleLock) { 6432 if (sRecycledCount < MAX_RECYCLED) { 6433 next = sRecycleBin; 6434 sRecycleBin = this; 6435 sRecycledCount += 1; 6436 } else { 6437 next = null; 6438 } 6439 child = null; 6440 } 6441 } 6442 } 6443 6444 /* Describes a hovered view. */ 6445 private static final class HoverTarget { 6446 private static final int MAX_RECYCLED = 32; 6447 private static final Object sRecycleLock = new Object(); 6448 private static HoverTarget sRecycleBin; 6449 private static int sRecycledCount; 6450 6451 // The hovered child view. 6452 public View child; 6453 6454 // The next target in the target list. 6455 public HoverTarget next; 6456 6457 private HoverTarget() { 6458 } 6459 6460 public static HoverTarget obtain(View child) { 6461 final HoverTarget target; 6462 synchronized (sRecycleLock) { 6463 if (sRecycleBin == null) { 6464 target = new HoverTarget(); 6465 } else { 6466 target = sRecycleBin; 6467 sRecycleBin = target.next; 6468 sRecycledCount--; 6469 target.next = null; 6470 } 6471 } 6472 target.child = child; 6473 return target; 6474 } 6475 6476 public void recycle() { 6477 synchronized (sRecycleLock) { 6478 if (sRecycledCount < MAX_RECYCLED) { 6479 next = sRecycleBin; 6480 sRecycleBin = this; 6481 sRecycledCount += 1; 6482 } else { 6483 next = null; 6484 } 6485 child = null; 6486 } 6487 } 6488 } 6489 6490 /** 6491 * Pooled class that orderes the children of a ViewGroup from start 6492 * to end based on how they are laid out and the layout direction. 6493 */ 6494 static class ChildListForAccessibility { 6495 6496 private static final int MAX_POOL_SIZE = 32; 6497 6498 private static final SynchronizedPool<ChildListForAccessibility> sPool = 6499 new SynchronizedPool<ChildListForAccessibility>(MAX_POOL_SIZE); 6500 6501 private final ArrayList<View> mChildren = new ArrayList<View>(); 6502 6503 private final ArrayList<ViewLocationHolder> mHolders = new ArrayList<ViewLocationHolder>(); 6504 6505 public static ChildListForAccessibility obtain(ViewGroup parent, boolean sort) { 6506 ChildListForAccessibility list = sPool.acquire(); 6507 if (list == null) { 6508 list = new ChildListForAccessibility(); 6509 } 6510 list.init(parent, sort); 6511 return list; 6512 } 6513 6514 public void recycle() { 6515 clear(); 6516 sPool.release(this); 6517 } 6518 6519 public int getChildCount() { 6520 return mChildren.size(); 6521 } 6522 6523 public View getChildAt(int index) { 6524 return mChildren.get(index); 6525 } 6526 6527 public int getChildIndex(View child) { 6528 return mChildren.indexOf(child); 6529 } 6530 6531 private void init(ViewGroup parent, boolean sort) { 6532 ArrayList<View> children = mChildren; 6533 final int childCount = parent.getChildCount(); 6534 for (int i = 0; i < childCount; i++) { 6535 View child = parent.getChildAt(i); 6536 children.add(child); 6537 } 6538 if (sort) { 6539 ArrayList<ViewLocationHolder> holders = mHolders; 6540 for (int i = 0; i < childCount; i++) { 6541 View child = children.get(i); 6542 ViewLocationHolder holder = ViewLocationHolder.obtain(parent, child); 6543 holders.add(holder); 6544 } 6545 Collections.sort(holders); 6546 for (int i = 0; i < childCount; i++) { 6547 ViewLocationHolder holder = holders.get(i); 6548 children.set(i, holder.mView); 6549 holder.recycle(); 6550 } 6551 holders.clear(); 6552 } 6553 } 6554 6555 private void clear() { 6556 mChildren.clear(); 6557 } 6558 } 6559 6560 /** 6561 * Pooled class that holds a View and its location with respect to 6562 * a specified root. This enables sorting of views based on their 6563 * coordinates without recomputing the position relative to the root 6564 * on every comparison. 6565 */ 6566 static class ViewLocationHolder implements Comparable<ViewLocationHolder> { 6567 6568 private static final int MAX_POOL_SIZE = 32; 6569 6570 private static final SynchronizedPool<ViewLocationHolder> sPool = 6571 new SynchronizedPool<ViewLocationHolder>(MAX_POOL_SIZE); 6572 6573 private final Rect mLocation = new Rect(); 6574 6575 public View mView; 6576 6577 private int mLayoutDirection; 6578 6579 public static ViewLocationHolder obtain(ViewGroup root, View view) { 6580 ViewLocationHolder holder = sPool.acquire(); 6581 if (holder == null) { 6582 holder = new ViewLocationHolder(); 6583 } 6584 holder.init(root, view); 6585 return holder; 6586 } 6587 6588 public void recycle() { 6589 clear(); 6590 sPool.release(this); 6591 } 6592 6593 @Override 6594 public int compareTo(ViewLocationHolder another) { 6595 // This instance is greater than an invalid argument. 6596 if (another == null) { 6597 return 1; 6598 } 6599 if (getClass() != another.getClass()) { 6600 return 1; 6601 } 6602 // First is above second. 6603 if (mLocation.bottom - another.mLocation.top <= 0) { 6604 return -1; 6605 } 6606 // First is below second. 6607 if (mLocation.top - another.mLocation.bottom >= 0) { 6608 return 1; 6609 } 6610 // LTR 6611 if (mLayoutDirection == LAYOUT_DIRECTION_LTR) { 6612 final int leftDifference = mLocation.left - another.mLocation.left; 6613 // First more to the left than second. 6614 if (leftDifference != 0) { 6615 return leftDifference; 6616 } 6617 } else { // RTL 6618 final int rightDifference = mLocation.right - another.mLocation.right; 6619 // First more to the right than second. 6620 if (rightDifference != 0) { 6621 return -rightDifference; 6622 } 6623 } 6624 // Break tie by top. 6625 final int topDiference = mLocation.top - another.mLocation.top; 6626 if (topDiference != 0) { 6627 return topDiference; 6628 } 6629 // Break tie by height. 6630 final int heightDiference = mLocation.height() - another.mLocation.height(); 6631 if (heightDiference != 0) { 6632 return -heightDiference; 6633 } 6634 // Break tie by width. 6635 final int widthDiference = mLocation.width() - another.mLocation.width(); 6636 if (widthDiference != 0) { 6637 return -widthDiference; 6638 } 6639 // Just break the tie somehow. The accessibliity ids are unique 6640 // and stable, hence this is deterministic tie breaking. 6641 return mView.getAccessibilityViewId() - another.mView.getAccessibilityViewId(); 6642 } 6643 6644 private void init(ViewGroup root, View view) { 6645 Rect viewLocation = mLocation; 6646 view.getDrawingRect(viewLocation); 6647 root.offsetDescendantRectToMyCoords(view, viewLocation); 6648 mView = view; 6649 mLayoutDirection = root.getLayoutDirection(); 6650 } 6651 6652 private void clear() { 6653 mView = null; 6654 mLocation.set(0, 0, 0, 0); 6655 } 6656 } 6657 6658 private static Paint getDebugPaint() { 6659 if (sDebugPaint == null) { 6660 sDebugPaint = new Paint(); 6661 sDebugPaint.setAntiAlias(false); 6662 } 6663 return sDebugPaint; 6664 } 6665 6666 private void drawRect(Canvas canvas, Paint paint, int x1, int y1, int x2, int y2) { 6667 if (sDebugLines== null) { 6668 sDebugLines = new float[16]; 6669 } 6670 6671 sDebugLines[0] = x1; 6672 sDebugLines[1] = y1; 6673 sDebugLines[2] = x2; 6674 sDebugLines[3] = y1; 6675 6676 sDebugLines[4] = x2; 6677 sDebugLines[5] = y1; 6678 sDebugLines[6] = x2; 6679 sDebugLines[7] = y2; 6680 6681 sDebugLines[8] = x2; 6682 sDebugLines[9] = y2; 6683 sDebugLines[10] = x1; 6684 sDebugLines[11] = y2; 6685 6686 sDebugLines[12] = x1; 6687 sDebugLines[13] = y2; 6688 sDebugLines[14] = x1; 6689 sDebugLines[15] = y1; 6690 6691 canvas.drawLines(sDebugLines, paint); 6692 } 6693} 6694