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