blob: e03e83d5932b40222a536b61e070a510902e7d36 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.widget;
18
Romain Guy6876b4f2013-06-03 14:25:56 -070019import android.util.ArrayMap;
Fabrice Di Meglio9e3b0022011-06-06 16:30:29 -070020import com.android.internal.R;
21
Romain Guybc5d8762012-01-06 16:40:49 -080022import java.util.ArrayDeque;
Fabrice Di Meglio9e3b0022011-06-06 16:30:29 -070023import java.util.ArrayList;
24import java.util.Comparator;
Fabrice Di Meglio9e3b0022011-06-06 16:30:29 -070025import java.util.SortedSet;
26import java.util.TreeSet;
27
svetoslavganov75986cf2009-05-14 22:28:01 -070028import android.content.Context;
Fabrice Di Meglio6a036402011-05-23 14:43:23 -070029import android.content.res.TypedArray;
svetoslavganov75986cf2009-05-14 22:28:01 -070030import android.graphics.Rect;
Adam Powell7da4b732012-12-07 15:28:33 -080031import android.os.Build;
svetoslavganov75986cf2009-05-14 22:28:01 -070032import android.util.AttributeSet;
Romain Guy6876b4f2013-06-03 14:25:56 -070033import android.util.Pools.SynchronizedPool;
Fabrice Di Meglio6a036402011-05-23 14:43:23 -070034import android.util.SparseArray;
svetoslavganov75986cf2009-05-14 22:28:01 -070035import android.view.Gravity;
36import android.view.View;
37import android.view.ViewDebug;
38import android.view.ViewGroup;
39import android.view.accessibility.AccessibilityEvent;
Svetoslav Ganov8a78fd42012-01-17 14:36:46 -080040import android.view.accessibility.AccessibilityNodeInfo;
svetoslavganov75986cf2009-05-14 22:28:01 -070041import android.widget.RemoteViews.RemoteView;
Fabrice Di Meglio6a036402011-05-23 14:43:23 -070042
Fabrice Di Meglioc44d8802013-02-19 17:42:13 -080043import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044
45/**
46 * A Layout where the positions of the children can be described in relation to each other or to the
Romain Guy520c4202010-01-04 10:56:38 -080047 * parent.
Romain Guya1f3e4a2009-06-04 15:10:46 -070048 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049 * <p>
50 * Note that you cannot have a circular dependency between the size of the RelativeLayout and the
51 * position of its children. For example, you cannot have a RelativeLayout whose height is set to
52 * {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT WRAP_CONTENT} and a child set to
53 * {@link #ALIGN_PARENT_BOTTOM}.
54 * </p>
Romain Guya1f3e4a2009-06-04 15:10:46 -070055 *
Adam Powell2c8cc972012-12-07 18:04:51 -080056 * <p><strong>Note:</strong> In platform version 17 and lower, RelativeLayout was affected by
57 * a measurement bug that could cause child views to be measured with incorrect
58 * {@link android.view.View.MeasureSpec MeasureSpec} values. (See
59 * {@link android.view.View.MeasureSpec#makeMeasureSpec(int, int) MeasureSpec.makeMeasureSpec}
60 * for more details.) This was triggered when a RelativeLayout container was placed in
61 * a scrolling container, such as a ScrollView or HorizontalScrollView. If a custom view
62 * not equipped to properly measure with the MeasureSpec mode
63 * {@link android.view.View.MeasureSpec#UNSPECIFIED UNSPECIFIED} was placed in a RelativeLayout,
64 * this would silently work anyway as RelativeLayout would pass a very large
65 * {@link android.view.View.MeasureSpec#AT_MOST AT_MOST} MeasureSpec instead.</p>
66 *
67 * <p>This behavior has been preserved for apps that set <code>android:targetSdkVersion="17"</code>
68 * or older in their manifest's <code>uses-sdk</code> tag for compatibility. Apps targeting SDK
69 * version 18 or newer will receive the correct behavior</p>
70 *
Scott Main4c359b72012-07-24 15:51:27 -070071 * <p>See the <a href="{@docRoot}guide/topics/ui/layout/relative.html">Relative
72 * Layout</a> guide.</p>
Scott Main41ec6532010-08-19 16:57:07 -070073 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080074 * <p>
75 * Also see {@link android.widget.RelativeLayout.LayoutParams RelativeLayout.LayoutParams} for
76 * layout attributes
77 * </p>
Romain Guya1f3e4a2009-06-04 15:10:46 -070078 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080079 * @attr ref android.R.styleable#RelativeLayout_gravity
80 * @attr ref android.R.styleable#RelativeLayout_ignoreGravity
81 */
82@RemoteView
83public class RelativeLayout extends ViewGroup {
84 public static final int TRUE = -1;
85
86 /**
87 * Rule that aligns a child's right edge with another child's left edge.
88 */
89 public static final int LEFT_OF = 0;
90 /**
91 * Rule that aligns a child's left edge with another child's right edge.
92 */
93 public static final int RIGHT_OF = 1;
94 /**
95 * Rule that aligns a child's bottom edge with another child's top edge.
96 */
97 public static final int ABOVE = 2;
98 /**
99 * Rule that aligns a child's top edge with another child's bottom edge.
100 */
101 public static final int BELOW = 3;
102
103 /**
104 * Rule that aligns a child's baseline with another child's baseline.
105 */
106 public static final int ALIGN_BASELINE = 4;
107 /**
108 * Rule that aligns a child's left edge with another child's left edge.
109 */
110 public static final int ALIGN_LEFT = 5;
111 /**
112 * Rule that aligns a child's top edge with another child's top edge.
113 */
114 public static final int ALIGN_TOP = 6;
115 /**
116 * Rule that aligns a child's right edge with another child's right edge.
117 */
118 public static final int ALIGN_RIGHT = 7;
119 /**
120 * Rule that aligns a child's bottom edge with another child's bottom edge.
121 */
122 public static final int ALIGN_BOTTOM = 8;
123
124 /**
125 * Rule that aligns the child's left edge with its RelativeLayout
126 * parent's left edge.
127 */
128 public static final int ALIGN_PARENT_LEFT = 9;
129 /**
130 * Rule that aligns the child's top edge with its RelativeLayout
131 * parent's top edge.
132 */
133 public static final int ALIGN_PARENT_TOP = 10;
134 /**
135 * Rule that aligns the child's right edge with its RelativeLayout
136 * parent's right edge.
137 */
138 public static final int ALIGN_PARENT_RIGHT = 11;
139 /**
140 * Rule that aligns the child's bottom edge with its RelativeLayout
141 * parent's bottom edge.
142 */
143 public static final int ALIGN_PARENT_BOTTOM = 12;
144
145 /**
146 * Rule that centers the child with respect to the bounds of its
147 * RelativeLayout parent.
148 */
149 public static final int CENTER_IN_PARENT = 13;
150 /**
151 * Rule that centers the child horizontally with respect to the
152 * bounds of its RelativeLayout parent.
153 */
154 public static final int CENTER_HORIZONTAL = 14;
155 /**
156 * Rule that centers the child vertically with respect to the
157 * bounds of its RelativeLayout parent.
158 */
159 public static final int CENTER_VERTICAL = 15;
Fabrice Di Megliof443f982012-07-13 20:24:03 -0700160 /**
161 * Rule that aligns a child's end edge with another child's start edge.
162 */
163 public static final int START_OF = 16;
164 /**
165 * Rule that aligns a child's start edge with another child's end edge.
166 */
167 public static final int END_OF = 17;
168 /**
169 * Rule that aligns a child's start edge with another child's start edge.
170 */
171 public static final int ALIGN_START = 18;
172 /**
173 * Rule that aligns a child's end edge with another child's end edge.
174 */
175 public static final int ALIGN_END = 19;
176 /**
177 * Rule that aligns the child's start edge with its RelativeLayout
178 * parent's start edge.
179 */
180 public static final int ALIGN_PARENT_START = 20;
181 /**
182 * Rule that aligns the child's end edge with its RelativeLayout
183 * parent's end edge.
184 */
185 public static final int ALIGN_PARENT_END = 21;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800186
Fabrice Di Megliof443f982012-07-13 20:24:03 -0700187 private static final int VERB_COUNT = 22;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800188
Romain Guybc5d8762012-01-06 16:40:49 -0800189
190 private static final int[] RULES_VERTICAL = {
191 ABOVE, BELOW, ALIGN_BASELINE, ALIGN_TOP, ALIGN_BOTTOM
192 };
193
194 private static final int[] RULES_HORIZONTAL = {
Fabrice Di Megliof443f982012-07-13 20:24:03 -0700195 LEFT_OF, RIGHT_OF, ALIGN_LEFT, ALIGN_RIGHT, START_OF, END_OF, ALIGN_START, ALIGN_END
Romain Guybc5d8762012-01-06 16:40:49 -0800196 };
197
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800198 private View mBaselineView = null;
199 private boolean mHasBaselineAlignedChild;
200
Fabrice Di Megliof443f982012-07-13 20:24:03 -0700201 private int mGravity = Gravity.START | Gravity.TOP;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800202 private final Rect mContentBounds = new Rect();
203 private final Rect mSelfBounds = new Rect();
204 private int mIgnoreGravity;
205
Romain Guy725015a2009-06-23 14:27:34 -0700206 private SortedSet<View> mTopToBottomLeftToRightSet = null;
207
208 private boolean mDirtyHierarchy;
Romain Guy6876b4f2013-06-03 14:25:56 -0700209 private View[] mSortedHorizontalChildren;
210 private View[] mSortedVerticalChildren;
Romain Guy725015a2009-06-23 14:27:34 -0700211 private final DependencyGraph mGraph = new DependencyGraph();
svetoslavganov75986cf2009-05-14 22:28:01 -0700212
Adam Powell7da4b732012-12-07 15:28:33 -0800213 // Compatibility hack. Old versions of the platform had problems
214 // with MeasureSpec value overflow and RelativeLayout was one source of them.
215 // Some apps came to rely on them. :(
216 private boolean mAllowBrokenMeasureSpecs = false;
Romain Guy76d59a32013-04-08 10:51:35 -0700217 // Compatibility hack. Old versions of the platform would not take
218 // margins and padding into account when generating the height measure spec
219 // for children during the horizontal measure pass.
220 private boolean mMeasureVerticalWithPaddingMargin = false;
Adam Powell7da4b732012-12-07 15:28:33 -0800221
Fabrice Di Megliod5ffc792013-02-19 15:59:21 -0800222 // A default width used for RTL measure pass
Philip Milneca2e9e12013-04-22 12:44:29 -0700223 /**
224 * Value reduced so as not to interfere with View's measurement spec. flags. See:
225 * {@link View#MEASURED_SIZE_MASK}.
226 * {@link View#MEASURED_STATE_TOO_SMALL}.
227 **/
Philip Milne3c647d22013-04-23 14:31:23 -0700228 private static final int DEFAULT_WIDTH = 0x00010000;
Fabrice Di Meglio306fe5c2013-01-23 18:46:25 -0800229
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800230 public RelativeLayout(Context context) {
231 super(context);
Romain Guy76d59a32013-04-08 10:51:35 -0700232 queryCompatibilityModes(context);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800233 }
234
235 public RelativeLayout(Context context, AttributeSet attrs) {
236 super(context, attrs);
237 initFromAttributes(context, attrs);
Romain Guy76d59a32013-04-08 10:51:35 -0700238 queryCompatibilityModes(context);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800239 }
240
241 public RelativeLayout(Context context, AttributeSet attrs, int defStyle) {
242 super(context, attrs, defStyle);
243 initFromAttributes(context, attrs);
Romain Guy76d59a32013-04-08 10:51:35 -0700244 queryCompatibilityModes(context);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800245 }
246
247 private void initFromAttributes(Context context, AttributeSet attrs) {
248 TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RelativeLayout);
249 mIgnoreGravity = a.getResourceId(R.styleable.RelativeLayout_ignoreGravity, View.NO_ID);
250 mGravity = a.getInt(R.styleable.RelativeLayout_gravity, mGravity);
251 a.recycle();
252 }
253
Romain Guy76d59a32013-04-08 10:51:35 -0700254 private void queryCompatibilityModes(Context context) {
255 int version = context.getApplicationInfo().targetSdkVersion;
256 mAllowBrokenMeasureSpecs = version <= Build.VERSION_CODES.JELLY_BEAN_MR1;
257 mMeasureVerticalWithPaddingMargin = version >= Build.VERSION_CODES.JELLY_BEAN_MR2;
258 }
259
Patrick Dubroye0a799a2011-05-04 16:19:22 -0700260 @Override
261 public boolean shouldDelayChildPressedState() {
262 return false;
263 }
264
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800265 /**
266 * Defines which View is ignored when the gravity is applied. This setting has no
Fabrice Di Megliof443f982012-07-13 20:24:03 -0700267 * effect if the gravity is <code>Gravity.START | Gravity.TOP</code>.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800268 *
269 * @param viewId The id of the View to be ignored by gravity, or 0 if no View
270 * should be ignored.
271 *
272 * @see #setGravity(int)
273 *
274 * @attr ref android.R.styleable#RelativeLayout_ignoreGravity
275 */
276 @android.view.RemotableViewMethod
277 public void setIgnoreGravity(int viewId) {
278 mIgnoreGravity = viewId;
279 }
280
281 /**
Philip Milne1018fb42012-03-13 12:00:04 -0700282 * Describes how the child views are positioned.
283 *
284 * @return the gravity.
285 *
286 * @see #setGravity(int)
287 * @see android.view.Gravity
288 *
289 * @attr ref android.R.styleable#RelativeLayout_gravity
290 */
291 public int getGravity() {
292 return mGravity;
293 }
294
295 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800296 * Describes how the child views are positioned. Defaults to
Fabrice Di Megliof443f982012-07-13 20:24:03 -0700297 * <code>Gravity.START | Gravity.TOP</code>.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800298 *
Adam Powell1fec24e2011-09-15 14:19:30 -0700299 * <p>Note that since RelativeLayout considers the positioning of each child
300 * relative to one another to be significant, setting gravity will affect
301 * the positioning of all children as a single unit within the parent.
302 * This happens after children have been relatively positioned.</p>
303 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800304 * @param gravity See {@link android.view.Gravity}
305 *
306 * @see #setHorizontalGravity(int)
307 * @see #setVerticalGravity(int)
308 *
309 * @attr ref android.R.styleable#RelativeLayout_gravity
310 */
311 @android.view.RemotableViewMethod
312 public void setGravity(int gravity) {
313 if (mGravity != gravity) {
Fabrice Di Meglio6a036402011-05-23 14:43:23 -0700314 if ((gravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) {
Fabrice Di Meglio9e3b0022011-06-06 16:30:29 -0700315 gravity |= Gravity.START;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800316 }
317
318 if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) {
319 gravity |= Gravity.TOP;
320 }
321
322 mGravity = gravity;
323 requestLayout();
324 }
325 }
326
327 @android.view.RemotableViewMethod
328 public void setHorizontalGravity(int horizontalGravity) {
Fabrice Di Meglio6a036402011-05-23 14:43:23 -0700329 final int gravity = horizontalGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK;
330 if ((mGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) != gravity) {
331 mGravity = (mGravity & ~Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) | gravity;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800332 requestLayout();
333 }
334 }
335
336 @android.view.RemotableViewMethod
337 public void setVerticalGravity(int verticalGravity) {
338 final int gravity = verticalGravity & Gravity.VERTICAL_GRAVITY_MASK;
339 if ((mGravity & Gravity.VERTICAL_GRAVITY_MASK) != gravity) {
340 mGravity = (mGravity & ~Gravity.VERTICAL_GRAVITY_MASK) | gravity;
341 requestLayout();
342 }
343 }
344
345 @Override
346 public int getBaseline() {
347 return mBaselineView != null ? mBaselineView.getBaseline() : super.getBaseline();
348 }
349
350 @Override
Romain Guy725015a2009-06-23 14:27:34 -0700351 public void requestLayout() {
352 super.requestLayout();
353 mDirtyHierarchy = true;
354 }
355
356 private void sortChildren() {
Romain Guy6876b4f2013-06-03 14:25:56 -0700357 final int count = getChildCount();
358 if (mSortedVerticalChildren == null || mSortedVerticalChildren.length != count) {
359 mSortedVerticalChildren = new View[count];
360 }
361
362 if (mSortedHorizontalChildren == null || mSortedHorizontalChildren.length != count) {
363 mSortedHorizontalChildren = new View[count];
364 }
Romain Guy725015a2009-06-23 14:27:34 -0700365
366 final DependencyGraph graph = mGraph;
367 graph.clear();
368
369 for (int i = 0; i < count; i++) {
Romain Guy6876b4f2013-06-03 14:25:56 -0700370 graph.add(getChildAt(i));
Romain Guy725015a2009-06-23 14:27:34 -0700371 }
372
Romain Guybc5d8762012-01-06 16:40:49 -0800373 graph.getSortedViews(mSortedVerticalChildren, RULES_VERTICAL);
374 graph.getSortedViews(mSortedHorizontalChildren, RULES_HORIZONTAL);
Romain Guy725015a2009-06-23 14:27:34 -0700375 }
376
377 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800378 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Romain Guy725015a2009-06-23 14:27:34 -0700379 if (mDirtyHierarchy) {
380 mDirtyHierarchy = false;
381 sortChildren();
382 }
383
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800384 int myWidth = -1;
385 int myHeight = -1;
386
387 int width = 0;
388 int height = 0;
389
Adam Powell132a7422012-09-30 12:39:56 -0700390 final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
391 final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
392 final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
393 final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800394
395 // Record our dimensions if they are known;
396 if (widthMode != MeasureSpec.UNSPECIFIED) {
397 myWidth = widthSize;
398 }
399
400 if (heightMode != MeasureSpec.UNSPECIFIED) {
401 myHeight = heightSize;
402 }
403
404 if (widthMode == MeasureSpec.EXACTLY) {
405 width = myWidth;
406 }
407
408 if (heightMode == MeasureSpec.EXACTLY) {
409 height = myHeight;
410 }
411
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800412 mHasBaselineAlignedChild = false;
413
414 View ignore = null;
Fabrice Di Meglio6a036402011-05-23 14:43:23 -0700415 int gravity = mGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK;
Fabrice Di Megliof443f982012-07-13 20:24:03 -0700416 final boolean horizontalGravity = gravity != Gravity.START && gravity != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800417 gravity = mGravity & Gravity.VERTICAL_GRAVITY_MASK;
418 final boolean verticalGravity = gravity != Gravity.TOP && gravity != 0;
419
420 int left = Integer.MAX_VALUE;
421 int top = Integer.MAX_VALUE;
422 int right = Integer.MIN_VALUE;
423 int bottom = Integer.MIN_VALUE;
424
Romain Guyf7dabb02009-06-25 14:47:14 -0700425 boolean offsetHorizontalAxis = false;
426 boolean offsetVerticalAxis = false;
427
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800428 if ((horizontalGravity || verticalGravity) && mIgnoreGravity != View.NO_ID) {
429 ignore = findViewById(mIgnoreGravity);
430 }
431
Romain Guyf7dabb02009-06-25 14:47:14 -0700432 final boolean isWrapContentWidth = widthMode != MeasureSpec.EXACTLY;
433 final boolean isWrapContentHeight = heightMode != MeasureSpec.EXACTLY;
434
Fabrice Di Meglio306fe5c2013-01-23 18:46:25 -0800435 // We need to know our size for doing the correct computation of children positioning in RTL
436 // mode but there is no practical way to get it instead of running the code below.
Fabrice Di Megliod5ffc792013-02-19 15:59:21 -0800437 // So, instead of running the code twice, we just set the width to a "default display width"
Fabrice Di Meglio306fe5c2013-01-23 18:46:25 -0800438 // before the computation and then, as a last pass, we will update their real position with
Fabrice Di Megliod5ffc792013-02-19 15:59:21 -0800439 // an offset equals to "DEFAULT_WIDTH - width".
Fabrice Di Meglio306fe5c2013-01-23 18:46:25 -0800440 final int layoutDirection = getLayoutDirection();
441 if (isLayoutRtl() && myWidth == -1) {
Fabrice Di Megliod5ffc792013-02-19 15:59:21 -0800442 myWidth = DEFAULT_WIDTH;
Fabrice Di Meglio306fe5c2013-01-23 18:46:25 -0800443 }
444
Romain Guye24ef602009-06-25 13:01:55 -0700445 View[] views = mSortedHorizontalChildren;
Romain Guy725015a2009-06-23 14:27:34 -0700446 int count = views.length;
Fabrice Di Meglio13705ed2012-11-26 20:05:31 -0800447
Romain Guy725015a2009-06-23 14:27:34 -0700448 for (int i = 0; i < count; i++) {
449 View child = views[i];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800450 if (child.getVisibility() != GONE) {
451 LayoutParams params = (LayoutParams) child.getLayoutParams();
Fabrice Di Meglio54726132013-01-18 18:36:45 -0800452 int[] rules = params.getRules(layoutDirection);
Romain Guy95607032009-06-24 14:37:03 -0700453
Fabrice Di Meglio54726132013-01-18 18:36:45 -0800454 applyHorizontalSizeRules(params, myWidth, rules);
Romain Guyf782e602009-06-25 15:26:49 -0700455 measureChildHorizontal(child, params, myWidth, myHeight);
Fabrice Di Meglio54726132013-01-18 18:36:45 -0800456
Romain Guyf7dabb02009-06-25 14:47:14 -0700457 if (positionChildHorizontal(child, params, myWidth, isWrapContentWidth)) {
458 offsetHorizontalAxis = true;
459 }
Romain Guy725015a2009-06-23 14:27:34 -0700460 }
461 }
462
Romain Guye24ef602009-06-25 13:01:55 -0700463 views = mSortedVerticalChildren;
Romain Guy725015a2009-06-23 14:27:34 -0700464 count = views.length;
Fabrice Di Meglio2bd961a2013-08-27 19:46:43 -0700465 final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion;
Romain Guyf7dabb02009-06-25 14:47:14 -0700466
Romain Guy725015a2009-06-23 14:27:34 -0700467 for (int i = 0; i < count; i++) {
468 View child = views[i];
469 if (child.getVisibility() != GONE) {
470 LayoutParams params = (LayoutParams) child.getLayoutParams();
Romain Guy95607032009-06-24 14:37:03 -0700471
472 applyVerticalSizeRules(params, myHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800473 measureChild(child, params, myWidth, myHeight);
Romain Guyf7dabb02009-06-25 14:47:14 -0700474 if (positionChildVertical(child, params, myHeight, isWrapContentHeight)) {
475 offsetVerticalAxis = true;
476 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800477
Romain Guyf7dabb02009-06-25 14:47:14 -0700478 if (isWrapContentWidth) {
Fabrice Di Meglio306fe5c2013-01-23 18:46:25 -0800479 if (isLayoutRtl()) {
Chet Haasee8222dd2013-09-05 07:44:18 -0700480 if (targetSdkVersion < Build.VERSION_CODES.KITKAT) {
Fabrice Di Meglio2bd961a2013-08-27 19:46:43 -0700481 width = Math.max(width, myWidth - params.mLeft);
482 } else {
483 width = Math.max(width, myWidth - params.mLeft - params.leftMargin);
484 }
Fabrice Di Meglio306fe5c2013-01-23 18:46:25 -0800485 } else {
Chet Haasee8222dd2013-09-05 07:44:18 -0700486 if (targetSdkVersion < Build.VERSION_CODES.KITKAT) {
Fabrice Di Meglio2bd961a2013-08-27 19:46:43 -0700487 width = Math.max(width, params.mRight);
488 } else {
489 width = Math.max(width, params.mRight + params.rightMargin);
490 }
Fabrice Di Meglio306fe5c2013-01-23 18:46:25 -0800491 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800492 }
Romain Guyf7dabb02009-06-25 14:47:14 -0700493
494 if (isWrapContentHeight) {
Chet Haasee8222dd2013-09-05 07:44:18 -0700495 if (targetSdkVersion < Build.VERSION_CODES.KITKAT) {
Fabrice Di Meglio2bd961a2013-08-27 19:46:43 -0700496 height = Math.max(height, params.mBottom);
497 } else {
498 height = Math.max(height, params.mBottom + params.bottomMargin);
499 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800500 }
501
502 if (child != ignore || verticalGravity) {
503 left = Math.min(left, params.mLeft - params.leftMargin);
504 top = Math.min(top, params.mTop - params.topMargin);
505 }
506
507 if (child != ignore || horizontalGravity) {
508 right = Math.max(right, params.mRight + params.rightMargin);
509 bottom = Math.max(bottom, params.mBottom + params.bottomMargin);
510 }
511 }
512 }
513
514 if (mHasBaselineAlignedChild) {
Romain Guy725015a2009-06-23 14:27:34 -0700515 for (int i = 0; i < count; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800516 View child = getChildAt(i);
517 if (child.getVisibility() != GONE) {
518 LayoutParams params = (LayoutParams) child.getLayoutParams();
519 alignBaseline(child, params);
520
521 if (child != ignore || verticalGravity) {
Romain Guy725015a2009-06-23 14:27:34 -0700522 left = Math.min(left, params.mLeft - params.leftMargin);
523 top = Math.min(top, params.mTop - params.topMargin);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800524 }
525
526 if (child != ignore || horizontalGravity) {
527 right = Math.max(right, params.mRight + params.rightMargin);
528 bottom = Math.max(bottom, params.mBottom + params.bottomMargin);
529 }
530 }
531 }
532 }
533
Romain Guyf7dabb02009-06-25 14:47:14 -0700534 if (isWrapContentWidth) {
Romain Guya1f3e4a2009-06-04 15:10:46 -0700535 // Width already has left padding in it since it was calculated by looking at
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800536 // the right of each child view
537 width += mPaddingRight;
538
Adam Powell758d5a42013-09-13 09:22:30 -0700539 if (mLayoutParams != null && mLayoutParams.width >= 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800540 width = Math.max(width, mLayoutParams.width);
541 }
542
543 width = Math.max(width, getSuggestedMinimumWidth());
544 width = resolveSize(width, widthMeasureSpec);
Romain Guyf7dabb02009-06-25 14:47:14 -0700545
546 if (offsetHorizontalAxis) {
Romain Guyd10a5762009-07-28 11:18:14 -0700547 for (int i = 0; i < count; i++) {
Romain Guyf7dabb02009-06-25 14:47:14 -0700548 View child = getChildAt(i);
549 if (child.getVisibility() != GONE) {
550 LayoutParams params = (LayoutParams) child.getLayoutParams();
Fabrice Di Megliof443f982012-07-13 20:24:03 -0700551 final int[] rules = params.getRules(layoutDirection);
Romain Guyf7dabb02009-06-25 14:47:14 -0700552 if (rules[CENTER_IN_PARENT] != 0 || rules[CENTER_HORIZONTAL] != 0) {
553 centerHorizontal(child, params, width);
Romain Guy42460ac2010-01-11 16:46:33 -0800554 } else if (rules[ALIGN_PARENT_RIGHT] != 0) {
555 final int childWidth = child.getMeasuredWidth();
556 params.mLeft = width - mPaddingRight - childWidth;
557 params.mRight = params.mLeft + childWidth;
Romain Guyf7dabb02009-06-25 14:47:14 -0700558 }
559 }
560 }
561 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800562 }
Romain Guyf7dabb02009-06-25 14:47:14 -0700563
564 if (isWrapContentHeight) {
Romain Guya1f3e4a2009-06-04 15:10:46 -0700565 // Height already has top padding in it since it was calculated by looking at
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800566 // the bottom of each child view
567 height += mPaddingBottom;
568
Adam Powell758d5a42013-09-13 09:22:30 -0700569 if (mLayoutParams != null && mLayoutParams.height >= 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800570 height = Math.max(height, mLayoutParams.height);
571 }
572
573 height = Math.max(height, getSuggestedMinimumHeight());
574 height = resolveSize(height, heightMeasureSpec);
Romain Guyf7dabb02009-06-25 14:47:14 -0700575
576 if (offsetVerticalAxis) {
577 for (int i = 0; i < count; i++) {
578 View child = getChildAt(i);
579 if (child.getVisibility() != GONE) {
580 LayoutParams params = (LayoutParams) child.getLayoutParams();
Fabrice Di Megliof443f982012-07-13 20:24:03 -0700581 final int[] rules = params.getRules(layoutDirection);
Romain Guyf7dabb02009-06-25 14:47:14 -0700582 if (rules[CENTER_IN_PARENT] != 0 || rules[CENTER_VERTICAL] != 0) {
583 centerVertical(child, params, height);
Romain Guy42460ac2010-01-11 16:46:33 -0800584 } else if (rules[ALIGN_PARENT_BOTTOM] != 0) {
585 final int childHeight = child.getMeasuredHeight();
586 params.mTop = height - mPaddingBottom - childHeight;
587 params.mBottom = params.mTop + childHeight;
Romain Guyf7dabb02009-06-25 14:47:14 -0700588 }
589 }
590 }
591 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800592 }
593
594 if (horizontalGravity || verticalGravity) {
595 final Rect selfBounds = mSelfBounds;
596 selfBounds.set(mPaddingLeft, mPaddingTop, width - mPaddingRight,
597 height - mPaddingBottom);
598
599 final Rect contentBounds = mContentBounds;
Fabrice Di Meglio6a036402011-05-23 14:43:23 -0700600 Gravity.apply(mGravity, right - left, bottom - top, selfBounds, contentBounds,
Fabrice Di Meglioc0053222011-06-13 12:16:51 -0700601 layoutDirection);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800602
603 final int horizontalOffset = contentBounds.left - left;
604 final int verticalOffset = contentBounds.top - top;
605 if (horizontalOffset != 0 || verticalOffset != 0) {
Romain Guy725015a2009-06-23 14:27:34 -0700606 for (int i = 0; i < count; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800607 View child = getChildAt(i);
608 if (child.getVisibility() != GONE && child != ignore) {
609 LayoutParams params = (LayoutParams) child.getLayoutParams();
Romain Guyd10a5762009-07-28 11:18:14 -0700610 if (horizontalGravity) {
611 params.mLeft += horizontalOffset;
612 params.mRight += horizontalOffset;
613 }
614 if (verticalGravity) {
615 params.mTop += verticalOffset;
616 params.mBottom += verticalOffset;
617 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800618 }
619 }
620 }
621 }
622
Fabrice Di Meglio306fe5c2013-01-23 18:46:25 -0800623 if (isLayoutRtl()) {
624 final int offsetWidth = myWidth - width;
625 for (int i = 0; i < count; i++) {
626 View child = getChildAt(i);
627 if (child.getVisibility() != GONE) {
628 LayoutParams params = (LayoutParams) child.getLayoutParams();
629 params.mLeft -= offsetWidth;
630 params.mRight -= offsetWidth;
631 }
632 }
633
634 }
635
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800636 setMeasuredDimension(width, height);
637 }
638
639 private void alignBaseline(View child, LayoutParams params) {
Fabrice Di Meglioe56ffdc2012-09-23 14:51:16 -0700640 final int layoutDirection = getLayoutDirection();
Fabrice Di Megliof443f982012-07-13 20:24:03 -0700641 int[] rules = params.getRules(layoutDirection);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800642 int anchorBaseline = getRelatedViewBaseline(rules, ALIGN_BASELINE);
643
644 if (anchorBaseline != -1) {
645 LayoutParams anchorParams = getRelatedViewParams(rules, ALIGN_BASELINE);
646 if (anchorParams != null) {
647 int offset = anchorParams.mTop + anchorBaseline;
648 int baseline = child.getBaseline();
649 if (baseline != -1) {
650 offset -= baseline;
651 }
652 int height = params.mBottom - params.mTop;
653 params.mTop = offset;
654 params.mBottom = params.mTop + height;
655 }
656 }
657
658 if (mBaselineView == null) {
659 mBaselineView = child;
660 } else {
661 LayoutParams lp = (LayoutParams) mBaselineView.getLayoutParams();
662 if (params.mTop < lp.mTop || (params.mTop == lp.mTop && params.mLeft < lp.mLeft)) {
663 mBaselineView = child;
664 }
665 }
666 }
667
668 /**
669 * Measure a child. The child should have left, top, right and bottom information
670 * stored in its LayoutParams. If any of these values is -1 it means that the view
671 * can extend up to the corresponding edge.
672 *
673 * @param child Child to measure
674 * @param params LayoutParams associated with child
675 * @param myWidth Width of the the RelativeLayout
676 * @param myHeight Height of the RelativeLayout
677 */
Romain Guy725015a2009-06-23 14:27:34 -0700678 private void measureChild(View child, LayoutParams params, int myWidth, int myHeight) {
Romain Guye8fb03c2013-04-25 11:40:45 -0700679 int childWidthMeasureSpec = getChildMeasureSpec(params.mLeft,
680 params.mRight, params.width,
681 params.leftMargin, params.rightMargin,
682 mPaddingLeft, mPaddingRight,
683 myWidth);
Romain Guy1b7c7912013-04-25 14:55:28 -0700684 int childHeightMeasureSpec = getChildMeasureSpec(params.mTop,
685 params.mBottom, params.height,
686 params.topMargin, params.bottomMargin,
687 mPaddingTop, mPaddingBottom,
688 myHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800689 child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
690 }
691
Romain Guyf782e602009-06-25 15:26:49 -0700692 private void measureChildHorizontal(View child, LayoutParams params, int myWidth, int myHeight) {
Romain Guy95607032009-06-24 14:37:03 -0700693 int childWidthMeasureSpec = getChildMeasureSpec(params.mLeft,
694 params.mRight, params.width,
695 params.leftMargin, params.rightMargin,
696 mPaddingLeft, mPaddingRight,
697 myWidth);
Romain Guy76d59a32013-04-08 10:51:35 -0700698 int maxHeight = myHeight;
699 if (mMeasureVerticalWithPaddingMargin) {
700 maxHeight = Math.max(0, myHeight - mPaddingTop - mPaddingBottom -
701 params.topMargin - params.bottomMargin);
702 }
Romain Guyf782e602009-06-25 15:26:49 -0700703 int childHeightMeasureSpec;
Adam Powell7da4b732012-12-07 15:28:33 -0800704 if (myHeight < 0 && !mAllowBrokenMeasureSpecs) {
Romain Guyf16c7a92013-02-11 17:43:59 -0800705 if (params.height >= 0) {
706 childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
707 params.height, MeasureSpec.EXACTLY);
708 } else {
709 // Negative values in a mySize/myWidth/myWidth value in RelativeLayout measurement
710 // is code for, "we got an unspecified mode in the RelativeLayout's measurespec."
711 // Carry it forward.
712 childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
713 }
Adam Powell132a7422012-09-30 12:39:56 -0700714 } else if (params.width == LayoutParams.MATCH_PARENT) {
Romain Guy76d59a32013-04-08 10:51:35 -0700715 childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(maxHeight, MeasureSpec.EXACTLY);
Romain Guyf782e602009-06-25 15:26:49 -0700716 } else {
Romain Guy76d59a32013-04-08 10:51:35 -0700717 childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(maxHeight, MeasureSpec.AT_MOST);
Romain Guyf782e602009-06-25 15:26:49 -0700718 }
Romain Guy725015a2009-06-23 14:27:34 -0700719 child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
720 }
721
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800722 /**
723 * Get a measure spec that accounts for all of the constraints on this view.
Fabrice Di Megliof443f982012-07-13 20:24:03 -0700724 * This includes size constraints imposed by the RelativeLayout as well as
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800725 * the View's desired dimension.
726 *
727 * @param childStart The left or top field of the child's layout params
728 * @param childEnd The right or bottom field of the child's layout params
729 * @param childSize The child's desired size (the width or height field of
730 * the child's layout params)
731 * @param startMargin The left or top margin
732 * @param endMargin The right or bottom margin
733 * @param startPadding mPaddingLeft or mPaddingTop
734 * @param endPadding mPaddingRight or mPaddingBottom
735 * @param mySize The width or height of this view (the RelativeLayout)
736 * @return MeasureSpec for the child
737 */
738 private int getChildMeasureSpec(int childStart, int childEnd,
739 int childSize, int startMargin, int endMargin, int startPadding,
740 int endPadding, int mySize) {
Adam Powell7da4b732012-12-07 15:28:33 -0800741 if (mySize < 0 && !mAllowBrokenMeasureSpecs) {
Romain Guyf16c7a92013-02-11 17:43:59 -0800742 if (childSize >= 0) {
743 return MeasureSpec.makeMeasureSpec(childSize, MeasureSpec.EXACTLY);
744 }
Adam Powell132a7422012-09-30 12:39:56 -0700745 // Negative values in a mySize/myWidth/myWidth value in RelativeLayout measurement
746 // is code for, "we got an unspecified mode in the RelativeLayout's measurespec."
747 // Carry it forward.
748 return MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
749 }
750
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800751 int childSpecMode = 0;
752 int childSpecSize = 0;
753
754 // Figure out start and end bounds.
755 int tempStart = childStart;
756 int tempEnd = childEnd;
757
758 // If the view did not express a layout constraint for an edge, use
759 // view's margins and our padding
760 if (tempStart < 0) {
761 tempStart = startPadding + startMargin;
762 }
763 if (tempEnd < 0) {
764 tempEnd = mySize - endPadding - endMargin;
765 }
766
767 // Figure out maximum size available to this view
768 int maxAvailable = tempEnd - tempStart;
769
770 if (childStart >= 0 && childEnd >= 0) {
771 // Constraints fixed both edges, so child must be an exact size
772 childSpecMode = MeasureSpec.EXACTLY;
773 childSpecSize = maxAvailable;
774 } else {
775 if (childSize >= 0) {
776 // Child wanted an exact size. Give as much as possible
777 childSpecMode = MeasureSpec.EXACTLY;
778
779 if (maxAvailable >= 0) {
780 // We have a maxmum size in this dimension.
781 childSpecSize = Math.min(maxAvailable, childSize);
782 } else {
783 // We can grow in this dimension.
784 childSpecSize = childSize;
785 }
Romain Guy980a9382010-01-08 15:06:28 -0800786 } else if (childSize == LayoutParams.MATCH_PARENT) {
Fabrice Di Megliof443f982012-07-13 20:24:03 -0700787 // Child wanted to be as big as possible. Give all available
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800788 // space
789 childSpecMode = MeasureSpec.EXACTLY;
790 childSpecSize = maxAvailable;
791 } else if (childSize == LayoutParams.WRAP_CONTENT) {
792 // Child wants to wrap content. Use AT_MOST
793 // to communicate available space if we know
794 // our max size
795 if (maxAvailable >= 0) {
Fabrice Di Megliof443f982012-07-13 20:24:03 -0700796 // We have a maximum size in this dimension.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800797 childSpecMode = MeasureSpec.AT_MOST;
798 childSpecSize = maxAvailable;
799 } else {
800 // We can grow in this dimension. Child can be as big as it
801 // wants
802 childSpecMode = MeasureSpec.UNSPECIFIED;
803 childSpecSize = 0;
804 }
805 }
806 }
807
808 return MeasureSpec.makeMeasureSpec(childSpecSize, childSpecMode);
809 }
810
Romain Guyf7dabb02009-06-25 14:47:14 -0700811 private boolean positionChildHorizontal(View child, LayoutParams params, int myWidth,
812 boolean wrapContent) {
813
Fabrice Di Meglioe56ffdc2012-09-23 14:51:16 -0700814 final int layoutDirection = getLayoutDirection();
Fabrice Di Megliof443f982012-07-13 20:24:03 -0700815 int[] rules = params.getRules(layoutDirection);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800816
817 if (params.mLeft < 0 && params.mRight >= 0) {
818 // Right is fixed, but left varies
819 params.mLeft = params.mRight - child.getMeasuredWidth();
820 } else if (params.mLeft >= 0 && params.mRight < 0) {
821 // Left is fixed, but right varies
822 params.mRight = params.mLeft + child.getMeasuredWidth();
823 } else if (params.mLeft < 0 && params.mRight < 0) {
824 // Both left and right vary
Romain Guyf7dabb02009-06-25 14:47:14 -0700825 if (rules[CENTER_IN_PARENT] != 0 || rules[CENTER_HORIZONTAL] != 0) {
826 if (!wrapContent) {
827 centerHorizontal(child, params, myWidth);
828 } else {
829 params.mLeft = mPaddingLeft + params.leftMargin;
830 params.mRight = params.mLeft + child.getMeasuredWidth();
831 }
832 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800833 } else {
Fabrice Di Megliof443f982012-07-13 20:24:03 -0700834 // This is the default case. For RTL we start from the right and for LTR we start
835 // from the left. This will give LEFT/TOP for LTR and RIGHT/TOP for RTL.
836 if (isLayoutRtl()) {
837 params.mRight = myWidth - mPaddingRight- params.rightMargin;
838 params.mLeft = params.mRight - child.getMeasuredWidth();
839 } else {
840 params.mLeft = mPaddingLeft + params.leftMargin;
841 params.mRight = params.mLeft + child.getMeasuredWidth();
842 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800843 }
844 }
Fabrice Di Megliof443f982012-07-13 20:24:03 -0700845 return rules[ALIGN_PARENT_END] != 0;
Romain Guy725015a2009-06-23 14:27:34 -0700846 }
847
Romain Guyf7dabb02009-06-25 14:47:14 -0700848 private boolean positionChildVertical(View child, LayoutParams params, int myHeight,
849 boolean wrapContent) {
850
Romain Guy725015a2009-06-23 14:27:34 -0700851 int[] rules = params.getRules();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800852
853 if (params.mTop < 0 && params.mBottom >= 0) {
854 // Bottom is fixed, but top varies
855 params.mTop = params.mBottom - child.getMeasuredHeight();
856 } else if (params.mTop >= 0 && params.mBottom < 0) {
857 // Top is fixed, but bottom varies
858 params.mBottom = params.mTop + child.getMeasuredHeight();
859 } else if (params.mTop < 0 && params.mBottom < 0) {
860 // Both top and bottom vary
Romain Guyf7dabb02009-06-25 14:47:14 -0700861 if (rules[CENTER_IN_PARENT] != 0 || rules[CENTER_VERTICAL] != 0) {
862 if (!wrapContent) {
863 centerVertical(child, params, myHeight);
864 } else {
865 params.mTop = mPaddingTop + params.topMargin;
866 params.mBottom = params.mTop + child.getMeasuredHeight();
867 }
868 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800869 } else {
870 params.mTop = mPaddingTop + params.topMargin;
871 params.mBottom = params.mTop + child.getMeasuredHeight();
872 }
873 }
Romain Guy42460ac2010-01-11 16:46:33 -0800874 return rules[ALIGN_PARENT_BOTTOM] != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800875 }
876
Fabrice Di Meglio54726132013-01-18 18:36:45 -0800877 private void applyHorizontalSizeRules(LayoutParams childParams, int myWidth, int[] rules) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800878 RelativeLayout.LayoutParams anchorParams;
879
880 // -1 indicated a "soft requirement" in that direction. For example:
881 // left=10, right=-1 means the view must start at 10, but can go as far as it wants to the right
882 // left =-1, right=10 means the view must end at 10, but can go as far as it wants to the left
883 // left=10, right=20 means the left and right ends are both fixed
884 childParams.mLeft = -1;
885 childParams.mRight = -1;
886
887 anchorParams = getRelatedViewParams(rules, LEFT_OF);
888 if (anchorParams != null) {
889 childParams.mRight = anchorParams.mLeft - (anchorParams.leftMargin +
890 childParams.rightMargin);
891 } else if (childParams.alignWithParent && rules[LEFT_OF] != 0) {
892 if (myWidth >= 0) {
893 childParams.mRight = myWidth - mPaddingRight - childParams.rightMargin;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800894 }
895 }
896
897 anchorParams = getRelatedViewParams(rules, RIGHT_OF);
898 if (anchorParams != null) {
899 childParams.mLeft = anchorParams.mRight + (anchorParams.rightMargin +
900 childParams.leftMargin);
901 } else if (childParams.alignWithParent && rules[RIGHT_OF] != 0) {
902 childParams.mLeft = mPaddingLeft + childParams.leftMargin;
903 }
904
905 anchorParams = getRelatedViewParams(rules, ALIGN_LEFT);
906 if (anchorParams != null) {
907 childParams.mLeft = anchorParams.mLeft + childParams.leftMargin;
908 } else if (childParams.alignWithParent && rules[ALIGN_LEFT] != 0) {
909 childParams.mLeft = mPaddingLeft + childParams.leftMargin;
910 }
911
912 anchorParams = getRelatedViewParams(rules, ALIGN_RIGHT);
913 if (anchorParams != null) {
914 childParams.mRight = anchorParams.mRight - childParams.rightMargin;
915 } else if (childParams.alignWithParent && rules[ALIGN_RIGHT] != 0) {
916 if (myWidth >= 0) {
917 childParams.mRight = myWidth - mPaddingRight - childParams.rightMargin;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800918 }
919 }
920
Romain Guy1b7c7912013-04-25 14:55:28 -0700921 if (0 != rules[ALIGN_PARENT_LEFT]) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800922 childParams.mLeft = mPaddingLeft + childParams.leftMargin;
923 }
924
Romain Guy1b7c7912013-04-25 14:55:28 -0700925 if (0 != rules[ALIGN_PARENT_RIGHT]) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800926 if (myWidth >= 0) {
927 childParams.mRight = myWidth - mPaddingRight - childParams.rightMargin;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800928 }
929 }
Romain Guy725015a2009-06-23 14:27:34 -0700930 }
931
932 private void applyVerticalSizeRules(LayoutParams childParams, int myHeight) {
933 int[] rules = childParams.getRules();
934 RelativeLayout.LayoutParams anchorParams;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800935
936 childParams.mTop = -1;
937 childParams.mBottom = -1;
938
939 anchorParams = getRelatedViewParams(rules, ABOVE);
940 if (anchorParams != null) {
941 childParams.mBottom = anchorParams.mTop - (anchorParams.topMargin +
942 childParams.bottomMargin);
943 } else if (childParams.alignWithParent && rules[ABOVE] != 0) {
944 if (myHeight >= 0) {
945 childParams.mBottom = myHeight - mPaddingBottom - childParams.bottomMargin;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800946 }
947 }
948
949 anchorParams = getRelatedViewParams(rules, BELOW);
950 if (anchorParams != null) {
951 childParams.mTop = anchorParams.mBottom + (anchorParams.bottomMargin +
952 childParams.topMargin);
953 } else if (childParams.alignWithParent && rules[BELOW] != 0) {
954 childParams.mTop = mPaddingTop + childParams.topMargin;
955 }
956
957 anchorParams = getRelatedViewParams(rules, ALIGN_TOP);
958 if (anchorParams != null) {
959 childParams.mTop = anchorParams.mTop + childParams.topMargin;
960 } else if (childParams.alignWithParent && rules[ALIGN_TOP] != 0) {
961 childParams.mTop = mPaddingTop + childParams.topMargin;
962 }
963
964 anchorParams = getRelatedViewParams(rules, ALIGN_BOTTOM);
965 if (anchorParams != null) {
966 childParams.mBottom = anchorParams.mBottom - childParams.bottomMargin;
967 } else if (childParams.alignWithParent && rules[ALIGN_BOTTOM] != 0) {
968 if (myHeight >= 0) {
969 childParams.mBottom = myHeight - mPaddingBottom - childParams.bottomMargin;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800970 }
971 }
972
Romain Guy1b7c7912013-04-25 14:55:28 -0700973 if (0 != rules[ALIGN_PARENT_TOP]) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800974 childParams.mTop = mPaddingTop + childParams.topMargin;
975 }
976
Romain Guy1b7c7912013-04-25 14:55:28 -0700977 if (0 != rules[ALIGN_PARENT_BOTTOM]) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800978 if (myHeight >= 0) {
979 childParams.mBottom = myHeight - mPaddingBottom - childParams.bottomMargin;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800980 }
981 }
982
983 if (rules[ALIGN_BASELINE] != 0) {
984 mHasBaselineAlignedChild = true;
985 }
986 }
987
988 private View getRelatedView(int[] rules, int relation) {
989 int id = rules[relation];
990 if (id != 0) {
Romain Guy1ab621e2009-06-25 13:31:57 -0700991 DependencyGraph.Node node = mGraph.mKeyNodes.get(id);
Romain Guya0fd1d72009-06-24 14:25:43 -0700992 if (node == null) return null;
993 View v = node.view;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800994
995 // Find the first non-GONE view up the chain
996 while (v.getVisibility() == View.GONE) {
Fabrice Di Meglio13705ed2012-11-26 20:05:31 -0800997 rules = ((LayoutParams) v.getLayoutParams()).getRules(v.getLayoutDirection());
Romain Guy1ab621e2009-06-25 13:31:57 -0700998 node = mGraph.mKeyNodes.get((rules[relation]));
Romain Guya0fd1d72009-06-24 14:25:43 -0700999 if (node == null) return null;
1000 v = node.view;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001001 }
1002
1003 return v;
1004 }
1005
1006 return null;
1007 }
1008
1009 private LayoutParams getRelatedViewParams(int[] rules, int relation) {
1010 View v = getRelatedView(rules, relation);
1011 if (v != null) {
1012 ViewGroup.LayoutParams params = v.getLayoutParams();
1013 if (params instanceof LayoutParams) {
1014 return (LayoutParams) v.getLayoutParams();
1015 }
1016 }
1017 return null;
1018 }
1019
1020 private int getRelatedViewBaseline(int[] rules, int relation) {
1021 View v = getRelatedView(rules, relation);
1022 if (v != null) {
1023 return v.getBaseline();
1024 }
1025 return -1;
1026 }
1027
Romain Guyf16c7a92013-02-11 17:43:59 -08001028 private static void centerHorizontal(View child, LayoutParams params, int myWidth) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001029 int childWidth = child.getMeasuredWidth();
1030 int left = (myWidth - childWidth) / 2;
1031
1032 params.mLeft = left;
1033 params.mRight = left + childWidth;
1034 }
1035
Romain Guyf16c7a92013-02-11 17:43:59 -08001036 private static void centerVertical(View child, LayoutParams params, int myHeight) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001037 int childHeight = child.getMeasuredHeight();
1038 int top = (myHeight - childHeight) / 2;
1039
1040 params.mTop = top;
1041 params.mBottom = top + childHeight;
1042 }
1043
1044 @Override
1045 protected void onLayout(boolean changed, int l, int t, int r, int b) {
1046 // The layout has actually already been performed and the positions
1047 // cached. Apply the cached values to the children.
Fabrice Di Meglio13705ed2012-11-26 20:05:31 -08001048 final int count = getChildCount();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001049
1050 for (int i = 0; i < count; i++) {
1051 View child = getChildAt(i);
1052 if (child.getVisibility() != GONE) {
1053 RelativeLayout.LayoutParams st =
1054 (RelativeLayout.LayoutParams) child.getLayoutParams();
1055 child.layout(st.mLeft, st.mTop, st.mRight, st.mBottom);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001056 }
1057 }
1058 }
1059
1060 @Override
1061 public LayoutParams generateLayoutParams(AttributeSet attrs) {
1062 return new RelativeLayout.LayoutParams(getContext(), attrs);
1063 }
1064
1065 /**
1066 * Returns a set of layout parameters with a width of
1067 * {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT},
1068 * a height of {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT} and no spanning.
1069 */
1070 @Override
1071 protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
1072 return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
1073 }
1074
1075 // Override to allow type-checking of LayoutParams.
1076 @Override
1077 protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
1078 return p instanceof RelativeLayout.LayoutParams;
1079 }
1080
1081 @Override
1082 protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
1083 return new LayoutParams(p);
1084 }
1085
svetoslavganov75986cf2009-05-14 22:28:01 -07001086 @Override
1087 public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
1088 if (mTopToBottomLeftToRightSet == null) {
1089 mTopToBottomLeftToRightSet = new TreeSet<View>(new TopToBottomLeftToRightComparator());
1090 }
1091
1092 // sort children top-to-bottom and left-to-right
1093 for (int i = 0, count = getChildCount(); i < count; i++) {
1094 mTopToBottomLeftToRightSet.add(getChildAt(i));
1095 }
1096
1097 for (View view : mTopToBottomLeftToRightSet) {
Svetoslav Ganov0b0a41d2011-09-07 18:06:03 -07001098 if (view.getVisibility() == View.VISIBLE
1099 && view.dispatchPopulateAccessibilityEvent(event)) {
svetoslavganov75986cf2009-05-14 22:28:01 -07001100 mTopToBottomLeftToRightSet.clear();
1101 return true;
1102 }
1103 }
1104
1105 mTopToBottomLeftToRightSet.clear();
1106 return false;
1107 }
1108
Svetoslav Ganov8a78fd42012-01-17 14:36:46 -08001109 @Override
1110 public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
1111 super.onInitializeAccessibilityEvent(event);
1112 event.setClassName(RelativeLayout.class.getName());
1113 }
1114
1115 @Override
1116 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
1117 super.onInitializeAccessibilityNodeInfo(info);
1118 info.setClassName(RelativeLayout.class.getName());
1119 }
1120
svetoslavganov75986cf2009-05-14 22:28:01 -07001121 /**
1122 * Compares two views in left-to-right and top-to-bottom fashion.
1123 */
1124 private class TopToBottomLeftToRightComparator implements Comparator<View> {
1125 public int compare(View first, View second) {
1126 // top - bottom
1127 int topDifference = first.getTop() - second.getTop();
1128 if (topDifference != 0) {
1129 return topDifference;
1130 }
1131 // left - right
1132 int leftDifference = first.getLeft() - second.getLeft();
1133 if (leftDifference != 0) {
1134 return leftDifference;
1135 }
1136 // break tie by height
1137 int heightDiference = first.getHeight() - second.getHeight();
1138 if (heightDiference != 0) {
1139 return heightDiference;
1140 }
1141 // break tie by width
1142 int widthDiference = first.getWidth() - second.getWidth();
1143 if (widthDiference != 0) {
1144 return widthDiference;
1145 }
1146 return 0;
1147 }
1148 }
1149
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001150 /**
1151 * Per-child layout information associated with RelativeLayout.
1152 *
1153 * @attr ref android.R.styleable#RelativeLayout_Layout_layout_alignWithParentIfMissing
1154 * @attr ref android.R.styleable#RelativeLayout_Layout_layout_toLeftOf
1155 * @attr ref android.R.styleable#RelativeLayout_Layout_layout_toRightOf
1156 * @attr ref android.R.styleable#RelativeLayout_Layout_layout_above
1157 * @attr ref android.R.styleable#RelativeLayout_Layout_layout_below
1158 * @attr ref android.R.styleable#RelativeLayout_Layout_layout_alignBaseline
1159 * @attr ref android.R.styleable#RelativeLayout_Layout_layout_alignLeft
1160 * @attr ref android.R.styleable#RelativeLayout_Layout_layout_alignTop
1161 * @attr ref android.R.styleable#RelativeLayout_Layout_layout_alignRight
1162 * @attr ref android.R.styleable#RelativeLayout_Layout_layout_alignBottom
1163 * @attr ref android.R.styleable#RelativeLayout_Layout_layout_alignParentLeft
1164 * @attr ref android.R.styleable#RelativeLayout_Layout_layout_alignParentTop
1165 * @attr ref android.R.styleable#RelativeLayout_Layout_layout_alignParentRight
1166 * @attr ref android.R.styleable#RelativeLayout_Layout_layout_alignParentBottom
1167 * @attr ref android.R.styleable#RelativeLayout_Layout_layout_centerInParent
1168 * @attr ref android.R.styleable#RelativeLayout_Layout_layout_centerHorizontal
1169 * @attr ref android.R.styleable#RelativeLayout_Layout_layout_centerVertical
Fabrice Di Megliof443f982012-07-13 20:24:03 -07001170 * @attr ref android.R.styleable#RelativeLayout_Layout_layout_toStartOf
1171 * @attr ref android.R.styleable#RelativeLayout_Layout_layout_toEndOf
1172 * @attr ref android.R.styleable#RelativeLayout_Layout_layout_alignStart
1173 * @attr ref android.R.styleable#RelativeLayout_Layout_layout_alignEnd
1174 * @attr ref android.R.styleable#RelativeLayout_Layout_layout_alignParentStart
1175 * @attr ref android.R.styleable#RelativeLayout_Layout_layout_alignParentEnd
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001176 */
1177 public static class LayoutParams extends ViewGroup.MarginLayoutParams {
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07001178 @ViewDebug.ExportedProperty(category = "layout", resolveId = true, indexMapping = {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001179 @ViewDebug.IntToString(from = ABOVE, to = "above"),
1180 @ViewDebug.IntToString(from = ALIGN_BASELINE, to = "alignBaseline"),
1181 @ViewDebug.IntToString(from = ALIGN_BOTTOM, to = "alignBottom"),
1182 @ViewDebug.IntToString(from = ALIGN_LEFT, to = "alignLeft"),
1183 @ViewDebug.IntToString(from = ALIGN_PARENT_BOTTOM, to = "alignParentBottom"),
1184 @ViewDebug.IntToString(from = ALIGN_PARENT_LEFT, to = "alignParentLeft"),
1185 @ViewDebug.IntToString(from = ALIGN_PARENT_RIGHT, to = "alignParentRight"),
1186 @ViewDebug.IntToString(from = ALIGN_PARENT_TOP, to = "alignParentTop"),
1187 @ViewDebug.IntToString(from = ALIGN_RIGHT, to = "alignRight"),
1188 @ViewDebug.IntToString(from = ALIGN_TOP, to = "alignTop"),
1189 @ViewDebug.IntToString(from = BELOW, to = "below"),
1190 @ViewDebug.IntToString(from = CENTER_HORIZONTAL, to = "centerHorizontal"),
1191 @ViewDebug.IntToString(from = CENTER_IN_PARENT, to = "center"),
1192 @ViewDebug.IntToString(from = CENTER_VERTICAL, to = "centerVertical"),
1193 @ViewDebug.IntToString(from = LEFT_OF, to = "leftOf"),
Fabrice Di Megliof443f982012-07-13 20:24:03 -07001194 @ViewDebug.IntToString(from = RIGHT_OF, to = "rightOf"),
1195 @ViewDebug.IntToString(from = ALIGN_START, to = "alignStart"),
1196 @ViewDebug.IntToString(from = ALIGN_END, to = "alignEnd"),
1197 @ViewDebug.IntToString(from = ALIGN_PARENT_START, to = "alignParentStart"),
1198 @ViewDebug.IntToString(from = ALIGN_PARENT_END, to = "alignParentEnd"),
1199 @ViewDebug.IntToString(from = START_OF, to = "startOf"),
1200 @ViewDebug.IntToString(from = END_OF, to = "endOf")
The Android Open Source Project10592532009-03-18 17:39:46 -07001201 }, mapping = {
1202 @ViewDebug.IntToString(from = TRUE, to = "true"),
Romain Guya1f3e4a2009-06-04 15:10:46 -07001203 @ViewDebug.IntToString(from = 0, to = "false/NO_ID")
The Android Open Source Project10592532009-03-18 17:39:46 -07001204 })
Fabrice Di Megliof443f982012-07-13 20:24:03 -07001205
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001206 private int[] mRules = new int[VERB_COUNT];
Fabrice Di Megliof443f982012-07-13 20:24:03 -07001207 private int[] mInitialRules = new int[VERB_COUNT];
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001208
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001209 private int mLeft, mTop, mRight, mBottom;
1210
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07001211 private int mStart = DEFAULT_MARGIN_RELATIVE;
1212 private int mEnd = DEFAULT_MARGIN_RELATIVE;
Fabrice Di Megliof443f982012-07-13 20:24:03 -07001213
1214 private boolean mRulesChanged = false;
Fabrice Di Meglioc44d8802013-02-19 17:42:13 -08001215 private boolean mIsRtlCompatibilityMode = false;
Fabrice Di Megliof443f982012-07-13 20:24:03 -07001216
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001217 /**
1218 * When true, uses the parent as the anchor if the anchor doesn't exist or if
1219 * the anchor's visibility is GONE.
1220 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07001221 @ViewDebug.ExportedProperty(category = "layout")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001222 public boolean alignWithParent;
1223
1224 public LayoutParams(Context c, AttributeSet attrs) {
1225 super(c, attrs);
1226
1227 TypedArray a = c.obtainStyledAttributes(attrs,
1228 com.android.internal.R.styleable.RelativeLayout_Layout);
1229
Fabrice Di Meglioc44d8802013-02-19 17:42:13 -08001230 final int targetSdkVersion = c.getApplicationInfo().targetSdkVersion;
1231 mIsRtlCompatibilityMode = (targetSdkVersion < JELLY_BEAN_MR1 ||
1232 !c.getApplicationInfo().hasRtlSupport());
1233
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001234 final int[] rules = mRules;
Romain Guyf16c7a92013-02-11 17:43:59 -08001235 //noinspection MismatchedReadAndWriteOfArray
Fabrice Di Megliof443f982012-07-13 20:24:03 -07001236 final int[] initialRules = mInitialRules;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001237
1238 final int N = a.getIndexCount();
1239 for (int i = 0; i < N; i++) {
1240 int attr = a.getIndex(i);
1241 switch (attr) {
1242 case com.android.internal.R.styleable.RelativeLayout_Layout_layout_alignWithParentIfMissing:
1243 alignWithParent = a.getBoolean(attr, false);
1244 break;
1245 case com.android.internal.R.styleable.RelativeLayout_Layout_layout_toLeftOf:
1246 rules[LEFT_OF] = a.getResourceId(attr, 0);
1247 break;
1248 case com.android.internal.R.styleable.RelativeLayout_Layout_layout_toRightOf:
1249 rules[RIGHT_OF] = a.getResourceId(attr, 0);
1250 break;
1251 case com.android.internal.R.styleable.RelativeLayout_Layout_layout_above:
1252 rules[ABOVE] = a.getResourceId(attr, 0);
1253 break;
1254 case com.android.internal.R.styleable.RelativeLayout_Layout_layout_below:
1255 rules[BELOW] = a.getResourceId(attr, 0);
1256 break;
1257 case com.android.internal.R.styleable.RelativeLayout_Layout_layout_alignBaseline:
1258 rules[ALIGN_BASELINE] = a.getResourceId(attr, 0);
1259 break;
1260 case com.android.internal.R.styleable.RelativeLayout_Layout_layout_alignLeft:
1261 rules[ALIGN_LEFT] = a.getResourceId(attr, 0);
1262 break;
1263 case com.android.internal.R.styleable.RelativeLayout_Layout_layout_alignTop:
1264 rules[ALIGN_TOP] = a.getResourceId(attr, 0);
1265 break;
1266 case com.android.internal.R.styleable.RelativeLayout_Layout_layout_alignRight:
1267 rules[ALIGN_RIGHT] = a.getResourceId(attr, 0);
1268 break;
1269 case com.android.internal.R.styleable.RelativeLayout_Layout_layout_alignBottom:
1270 rules[ALIGN_BOTTOM] = a.getResourceId(attr, 0);
1271 break;
1272 case com.android.internal.R.styleable.RelativeLayout_Layout_layout_alignParentLeft:
1273 rules[ALIGN_PARENT_LEFT] = a.getBoolean(attr, false) ? TRUE : 0;
1274 break;
1275 case com.android.internal.R.styleable.RelativeLayout_Layout_layout_alignParentTop:
1276 rules[ALIGN_PARENT_TOP] = a.getBoolean(attr, false) ? TRUE : 0;
1277 break;
1278 case com.android.internal.R.styleable.RelativeLayout_Layout_layout_alignParentRight:
1279 rules[ALIGN_PARENT_RIGHT] = a.getBoolean(attr, false) ? TRUE : 0;
1280 break;
1281 case com.android.internal.R.styleable.RelativeLayout_Layout_layout_alignParentBottom:
1282 rules[ALIGN_PARENT_BOTTOM] = a.getBoolean(attr, false) ? TRUE : 0;
1283 break;
1284 case com.android.internal.R.styleable.RelativeLayout_Layout_layout_centerInParent:
1285 rules[CENTER_IN_PARENT] = a.getBoolean(attr, false) ? TRUE : 0;
1286 break;
1287 case com.android.internal.R.styleable.RelativeLayout_Layout_layout_centerHorizontal:
1288 rules[CENTER_HORIZONTAL] = a.getBoolean(attr, false) ? TRUE : 0;
1289 break;
1290 case com.android.internal.R.styleable.RelativeLayout_Layout_layout_centerVertical:
1291 rules[CENTER_VERTICAL] = a.getBoolean(attr, false) ? TRUE : 0;
1292 break;
Fabrice Di Megliof443f982012-07-13 20:24:03 -07001293 case com.android.internal.R.styleable.RelativeLayout_Layout_layout_toStartOf:
1294 rules[START_OF] = a.getResourceId(attr, 0);
1295 break;
1296 case com.android.internal.R.styleable.RelativeLayout_Layout_layout_toEndOf:
1297 rules[END_OF] = a.getResourceId(attr, 0);
1298 break;
1299 case com.android.internal.R.styleable.RelativeLayout_Layout_layout_alignStart:
1300 rules[ALIGN_START] = a.getResourceId(attr, 0);
1301 break;
1302 case com.android.internal.R.styleable.RelativeLayout_Layout_layout_alignEnd:
1303 rules[ALIGN_END] = a.getResourceId(attr, 0);
1304 break;
1305 case com.android.internal.R.styleable.RelativeLayout_Layout_layout_alignParentStart:
1306 rules[ALIGN_PARENT_START] = a.getBoolean(attr, false) ? TRUE : 0;
1307 break;
1308 case com.android.internal.R.styleable.RelativeLayout_Layout_layout_alignParentEnd:
1309 rules[ALIGN_PARENT_END] = a.getBoolean(attr, false) ? TRUE : 0;
1310 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001311 }
1312 }
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07001313 mRulesChanged = true;
Romain Guyf16c7a92013-02-11 17:43:59 -08001314 System.arraycopy(rules, LEFT_OF, initialRules, LEFT_OF, VERB_COUNT);
Fabrice Di Megliof443f982012-07-13 20:24:03 -07001315
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001316 a.recycle();
1317 }
1318
1319 public LayoutParams(int w, int h) {
1320 super(w, h);
1321 }
1322
1323 /**
1324 * {@inheritDoc}
1325 */
1326 public LayoutParams(ViewGroup.LayoutParams source) {
1327 super(source);
1328 }
1329
1330 /**
1331 * {@inheritDoc}
1332 */
1333 public LayoutParams(ViewGroup.MarginLayoutParams source) {
1334 super(source);
1335 }
1336
Alan Viverette0a0e1552013-08-07 13:24:09 -07001337 /**
1338 * Copy constructor. Clones the width, height, margin values, and rules
1339 * of the source.
1340 *
1341 * @param source The layout params to copy from.
1342 */
1343 public LayoutParams(LayoutParams source) {
1344 super(source);
1345
1346 this.mIsRtlCompatibilityMode = source.mIsRtlCompatibilityMode;
1347 this.mRulesChanged = source.mRulesChanged;
1348 this.alignWithParent = source.alignWithParent;
1349
1350 System.arraycopy(source.mRules, LEFT_OF, this.mRules, LEFT_OF, VERB_COUNT);
1351 System.arraycopy(
1352 source.mInitialRules, LEFT_OF, this.mInitialRules, LEFT_OF, VERB_COUNT);
1353 }
1354
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001355 @Override
1356 public String debug(String output) {
1357 return output + "ViewGroup.LayoutParams={ width=" + sizeToString(width) +
1358 ", height=" + sizeToString(height) + " }";
1359 }
1360
1361 /**
1362 * Adds a layout rule to be interpreted by the RelativeLayout. This
1363 * method should only be used for constraints that don't refer to another sibling
1364 * (e.g., CENTER_IN_PARENT) or take a boolean value ({@link RelativeLayout#TRUE}
Fabrice Di Megliof443f982012-07-13 20:24:03 -07001365 * for true or 0 for false). To specify a verb that takes a subject, use
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001366 * {@link #addRule(int, int)} instead.
1367 *
1368 * @param verb One of the verbs defined by
1369 * {@link android.widget.RelativeLayout RelativeLayout}, such as
1370 * ALIGN_WITH_PARENT_LEFT.
1371 * @see #addRule(int, int)
1372 */
1373 public void addRule(int verb) {
1374 mRules[verb] = TRUE;
Fabrice Di Megliof443f982012-07-13 20:24:03 -07001375 mInitialRules[verb] = TRUE;
1376 mRulesChanged = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001377 }
1378
1379 /**
1380 * Adds a layout rule to be interpreted by the RelativeLayout. Use this for
1381 * verbs that take a target, such as a sibling (ALIGN_RIGHT) or a boolean
1382 * value (VISIBLE).
1383 *
1384 * @param verb One of the verbs defined by
1385 * {@link android.widget.RelativeLayout RelativeLayout}, such as
1386 * ALIGN_WITH_PARENT_LEFT.
1387 * @param anchor The id of another view to use as an anchor,
1388 * or a boolean value(represented as {@link RelativeLayout#TRUE})
1389 * for true or 0 for false). For verbs that don't refer to another sibling
1390 * (for example, ALIGN_WITH_PARENT_BOTTOM) just use -1.
1391 * @see #addRule(int)
1392 */
1393 public void addRule(int verb, int anchor) {
1394 mRules[verb] = anchor;
Fabrice Di Megliof443f982012-07-13 20:24:03 -07001395 mInitialRules[verb] = anchor;
1396 mRulesChanged = true;
1397 }
1398
Fabrice Di Meglioa4c10302012-07-26 12:27:56 -07001399 /**
1400 * Removes a layout rule to be interpreted by the RelativeLayout.
1401 *
1402 * @param verb One of the verbs defined by
1403 * {@link android.widget.RelativeLayout RelativeLayout}, such as
1404 * ALIGN_WITH_PARENT_LEFT.
1405 * @see #addRule(int)
1406 * @see #addRule(int, int)
1407 */
1408 public void removeRule(int verb) {
1409 mRules[verb] = 0;
1410 mInitialRules[verb] = 0;
1411 mRulesChanged = true;
1412 }
1413
Fabrice Di Megliof443f982012-07-13 20:24:03 -07001414 private boolean hasRelativeRules() {
1415 return (mInitialRules[START_OF] != 0 || mInitialRules[END_OF] != 0 ||
1416 mInitialRules[ALIGN_START] != 0 || mInitialRules[ALIGN_END] != 0 ||
1417 mInitialRules[ALIGN_PARENT_START] != 0 || mInitialRules[ALIGN_PARENT_END] != 0);
1418 }
1419
Fabrice Di Meglioc44d8802013-02-19 17:42:13 -08001420 // The way we are resolving rules depends on the layout direction and if we are pre JB MR1
1421 // or not.
1422 //
1423 // If we are pre JB MR1 (said as "RTL compatibility mode"), "left"/"right" rules are having
1424 // predominance over any "start/end" rules that could have been defined. A special case:
1425 // if no "left"/"right" rule has been defined and "start"/"end" rules are defined then we
1426 // resolve those "start"/"end" rules to "left"/"right" respectively.
1427 //
1428 // If we are JB MR1+, then "start"/"end" rules are having predominance over "left"/"right"
1429 // rules. If no "start"/"end" rule is defined then we use "left"/"right" rules.
1430 //
1431 // In all cases, the result of the resolution should clear the "start"/"end" rules to leave
1432 // only the "left"/"right" rules at the end.
Fabrice Di Megliof443f982012-07-13 20:24:03 -07001433 private void resolveRules(int layoutDirection) {
1434 final boolean isLayoutRtl = (layoutDirection == View.LAYOUT_DIRECTION_RTL);
Fabrice Di Meglioc44d8802013-02-19 17:42:13 -08001435
Fabrice Di Megliof443f982012-07-13 20:24:03 -07001436 // Reset to initial state
Romain Guyf16c7a92013-02-11 17:43:59 -08001437 System.arraycopy(mInitialRules, LEFT_OF, mRules, LEFT_OF, VERB_COUNT);
Fabrice Di Meglioc44d8802013-02-19 17:42:13 -08001438
1439 // Apply rules depending on direction and if we are in RTL compatibility mode
1440 if (mIsRtlCompatibilityMode) {
1441 if (mRules[ALIGN_START] != 0) {
1442 if (mRules[ALIGN_LEFT] == 0) {
1443 // "left" rule is not defined but "start" rule is: use the "start" rule as
1444 // the "left" rule
1445 mRules[ALIGN_LEFT] = mRules[ALIGN_START];
1446 }
1447 mRules[ALIGN_START] = 0;
1448 }
1449
1450 if (mRules[ALIGN_END] != 0) {
1451 if (mRules[ALIGN_RIGHT] == 0) {
1452 // "right" rule is not defined but "end" rule is: use the "end" rule as the
1453 // "right" rule
1454 mRules[ALIGN_RIGHT] = mRules[ALIGN_END];
1455 }
1456 mRules[ALIGN_END] = 0;
1457 }
1458
1459 if (mRules[START_OF] != 0) {
1460 if (mRules[LEFT_OF] == 0) {
1461 // "left" rule is not defined but "start" rule is: use the "start" rule as
1462 // the "left" rule
1463 mRules[LEFT_OF] = mRules[START_OF];
1464 }
1465 mRules[START_OF] = 0;
1466 }
1467
1468 if (mRules[END_OF] != 0) {
1469 if (mRules[RIGHT_OF] == 0) {
1470 // "right" rule is not defined but "end" rule is: use the "end" rule as the
1471 // "right" rule
1472 mRules[RIGHT_OF] = mRules[END_OF];
1473 }
1474 mRules[END_OF] = 0;
1475 }
1476
1477 if (mRules[ALIGN_PARENT_START] != 0) {
1478 if (mRules[ALIGN_PARENT_LEFT] == 0) {
1479 // "left" rule is not defined but "start" rule is: use the "start" rule as
1480 // the "left" rule
1481 mRules[ALIGN_PARENT_LEFT] = mRules[ALIGN_PARENT_START];
1482 }
1483 mRules[ALIGN_PARENT_START] = 0;
1484 }
1485
1486 if (mRules[ALIGN_PARENT_RIGHT] == 0) {
1487 if (mRules[ALIGN_PARENT_RIGHT] == 0) {
1488 // "right" rule is not defined but "end" rule is: use the "end" rule as the
1489 // "right" rule
1490 mRules[ALIGN_PARENT_RIGHT] = mRules[ALIGN_PARENT_END];
1491 }
1492 mRules[ALIGN_PARENT_END] = 0;
1493 }
1494 } else {
1495 // JB MR1+ case
1496 if ((mRules[ALIGN_START] != 0 || mRules[ALIGN_END] != 0) &&
1497 (mRules[ALIGN_LEFT] != 0 || mRules[ALIGN_RIGHT] != 0)) {
1498 // "start"/"end" rules take precedence over "left"/"right" rules
1499 mRules[ALIGN_LEFT] = 0;
1500 mRules[ALIGN_RIGHT] = 0;
1501 }
1502 if (mRules[ALIGN_START] != 0) {
1503 // "start" rule resolved to "left" or "right" depending on the direction
1504 mRules[isLayoutRtl ? ALIGN_RIGHT : ALIGN_LEFT] = mRules[ALIGN_START];
1505 mRules[ALIGN_START] = 0;
1506 }
1507 if (mRules[ALIGN_END] != 0) {
1508 // "end" rule resolved to "left" or "right" depending on the direction
1509 mRules[isLayoutRtl ? ALIGN_LEFT : ALIGN_RIGHT] = mRules[ALIGN_END];
1510 mRules[ALIGN_END] = 0;
1511 }
1512
1513 if ((mRules[START_OF] != 0 || mRules[END_OF] != 0) &&
1514 (mRules[LEFT_OF] != 0 || mRules[RIGHT_OF] != 0)) {
1515 // "start"/"end" rules take precedence over "left"/"right" rules
1516 mRules[LEFT_OF] = 0;
1517 mRules[RIGHT_OF] = 0;
1518 }
1519 if (mRules[START_OF] != 0) {
1520 // "start" rule resolved to "left" or "right" depending on the direction
1521 mRules[isLayoutRtl ? RIGHT_OF : LEFT_OF] = mRules[START_OF];
1522 mRules[START_OF] = 0;
1523 }
1524 if (mRules[END_OF] != 0) {
1525 // "end" rule resolved to "left" or "right" depending on the direction
1526 mRules[isLayoutRtl ? LEFT_OF : RIGHT_OF] = mRules[END_OF];
1527 mRules[END_OF] = 0;
1528 }
1529
1530 if ((mRules[ALIGN_PARENT_START] != 0 || mRules[ALIGN_PARENT_END] != 0) &&
1531 (mRules[ALIGN_PARENT_LEFT] != 0 || mRules[ALIGN_PARENT_RIGHT] != 0)) {
1532 // "start"/"end" rules take precedence over "left"/"right" rules
1533 mRules[ALIGN_PARENT_LEFT] = 0;
1534 mRules[ALIGN_PARENT_RIGHT] = 0;
1535 }
1536 if (mRules[ALIGN_PARENT_START] != 0) {
1537 // "start" rule resolved to "left" or "right" depending on the direction
1538 mRules[isLayoutRtl ? ALIGN_PARENT_RIGHT : ALIGN_PARENT_LEFT] = mRules[ALIGN_PARENT_START];
1539 mRules[ALIGN_PARENT_START] = 0;
1540 }
1541 if (mRules[ALIGN_PARENT_END] != 0) {
1542 // "end" rule resolved to "left" or "right" depending on the direction
1543 mRules[isLayoutRtl ? ALIGN_PARENT_LEFT : ALIGN_PARENT_RIGHT] = mRules[ALIGN_PARENT_END];
1544 mRules[ALIGN_PARENT_END] = 0;
1545 }
Fabrice Di Megliof443f982012-07-13 20:24:03 -07001546 }
1547 mRulesChanged = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001548 }
1549
1550 /**
1551 * Retrieves a complete list of all supported rules, where the index is the rule
1552 * verb, and the element value is the value specified, or "false" if it was never
Fabrice Di Megliof443f982012-07-13 20:24:03 -07001553 * set. If there are relative rules defined (*_START / *_END), they will be resolved
1554 * depending on the layout direction.
1555 *
1556 * @param layoutDirection the direction of the layout.
1557 * Should be either {@link View#LAYOUT_DIRECTION_LTR}
1558 * or {@link View#LAYOUT_DIRECTION_RTL}
1559 * @return the supported rules
1560 * @see #addRule(int, int)
1561 *
1562 * @hide
1563 */
1564 public int[] getRules(int layoutDirection) {
1565 if (hasRelativeRules() &&
1566 (mRulesChanged || layoutDirection != getLayoutDirection())) {
1567 resolveRules(layoutDirection);
1568 if (layoutDirection != getLayoutDirection()) {
1569 setLayoutDirection(layoutDirection);
1570 }
1571 }
1572 return mRules;
1573 }
1574
1575 /**
1576 * Retrieves a complete list of all supported rules, where the index is the rule
1577 * verb, and the element value is the value specified, or "false" if it was never
1578 * set. There will be no resolution of relative rules done.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001579 *
1580 * @return the supported rules
1581 * @see #addRule(int, int)
1582 */
1583 public int[] getRules() {
1584 return mRules;
1585 }
Fabrice Di Megliof443f982012-07-13 20:24:03 -07001586
1587 @Override
Fabrice Di Meglio2918ab62012-10-10 16:39:25 -07001588 public void resolveLayoutDirection(int layoutDirection) {
Fabrice Di Megliof443f982012-07-13 20:24:03 -07001589 final boolean isLayoutRtl = isLayoutRtl();
1590 if (isLayoutRtl) {
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07001591 if (mStart != DEFAULT_MARGIN_RELATIVE) mRight = mStart;
1592 if (mEnd != DEFAULT_MARGIN_RELATIVE) mLeft = mEnd;
Fabrice Di Megliof443f982012-07-13 20:24:03 -07001593 } else {
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07001594 if (mStart != DEFAULT_MARGIN_RELATIVE) mLeft = mStart;
1595 if (mEnd != DEFAULT_MARGIN_RELATIVE) mRight = mEnd;
Fabrice Di Megliof443f982012-07-13 20:24:03 -07001596 }
1597
1598 if (hasRelativeRules() && layoutDirection != getLayoutDirection()) {
1599 resolveRules(layoutDirection);
1600 }
1601 // This will set the layout direction
Fabrice Di Meglio2918ab62012-10-10 16:39:25 -07001602 super.resolveLayoutDirection(layoutDirection);
Fabrice Di Megliof443f982012-07-13 20:24:03 -07001603 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001604 }
Romain Guy725015a2009-06-23 14:27:34 -07001605
1606 private static class DependencyGraph {
1607 /**
Romain Guy1ab621e2009-06-25 13:31:57 -07001608 * List of all views in the graph.
1609 */
1610 private ArrayList<Node> mNodes = new ArrayList<Node>();
1611
1612 /**
Romain Guy725015a2009-06-23 14:27:34 -07001613 * List of nodes in the graph. Each node is identified by its
1614 * view id (see View#getId()).
1615 */
Romain Guy1ab621e2009-06-25 13:31:57 -07001616 private SparseArray<Node> mKeyNodes = new SparseArray<Node>();
Romain Guy725015a2009-06-23 14:27:34 -07001617
1618 /**
1619 * Temporary data structure used to build the list of roots
1620 * for this graph.
1621 */
Romain Guybc5d8762012-01-06 16:40:49 -08001622 private ArrayDeque<Node> mRoots = new ArrayDeque<Node>();
Romain Guy725015a2009-06-23 14:27:34 -07001623
1624 /**
1625 * Clears the graph.
1626 */
1627 void clear() {
Romain Guy1ab621e2009-06-25 13:31:57 -07001628 final ArrayList<Node> nodes = mNodes;
Romain Guy725015a2009-06-23 14:27:34 -07001629 final int count = nodes.size();
1630
1631 for (int i = 0; i < count; i++) {
Romain Guy1ab621e2009-06-25 13:31:57 -07001632 nodes.get(i).release();
Romain Guy725015a2009-06-23 14:27:34 -07001633 }
1634 nodes.clear();
1635
Romain Guy1ab621e2009-06-25 13:31:57 -07001636 mKeyNodes.clear();
Romain Guy725015a2009-06-23 14:27:34 -07001637 mRoots.clear();
1638 }
1639
1640 /**
1641 * Adds a view to the graph.
1642 *
1643 * @param view The view to be added as a node to the graph.
1644 */
1645 void add(View view) {
Romain Guy1ab621e2009-06-25 13:31:57 -07001646 final int id = view.getId();
1647 final Node node = Node.acquire(view);
1648
1649 if (id != View.NO_ID) {
1650 mKeyNodes.put(id, node);
1651 }
1652
1653 mNodes.add(node);
Romain Guy725015a2009-06-23 14:27:34 -07001654 }
1655
1656 /**
1657 * Builds a sorted list of views. The sorting order depends on the dependencies
1658 * between the view. For instance, if view C needs view A to be processed first
1659 * and view A needs view B to be processed first, the dependency graph
1660 * is: B -> A -> C. The sorted array will contain views B, A and C in this order.
1661 *
1662 * @param sorted The sorted list of views. The length of this array must
1663 * be equal to getChildCount().
1664 * @param rules The list of rules to take into account.
1665 */
1666 void getSortedViews(View[] sorted, int... rules) {
Romain Guybc5d8762012-01-06 16:40:49 -08001667 final ArrayDeque<Node> roots = findRoots(rules);
Romain Guy725015a2009-06-23 14:27:34 -07001668 int index = 0;
1669
Romain Guybc5d8762012-01-06 16:40:49 -08001670 Node node;
1671 while ((node = roots.pollLast()) != null) {
Romain Guy725015a2009-06-23 14:27:34 -07001672 final View view = node.view;
1673 final int key = view.getId();
1674
1675 sorted[index++] = view;
1676
Romain Guy6876b4f2013-06-03 14:25:56 -07001677 final ArrayMap<Node, DependencyGraph> dependents = node.dependents;
1678 final int count = dependents.size();
1679 for (int i = 0; i < count; i++) {
1680 final Node dependent = dependents.keyAt(i);
Romain Guy725015a2009-06-23 14:27:34 -07001681 final SparseArray<Node> dependencies = dependent.dependencies;
1682
1683 dependencies.remove(key);
1684 if (dependencies.size() == 0) {
1685 roots.add(dependent);
1686 }
1687 }
1688 }
1689
1690 if (index < sorted.length) {
1691 throw new IllegalStateException("Circular dependencies cannot exist"
1692 + " in RelativeLayout");
1693 }
1694 }
1695
1696 /**
1697 * Finds the roots of the graph. A root is a node with no dependency and
1698 * with [0..n] dependents.
1699 *
1700 * @param rulesFilter The list of rules to consider when building the
1701 * dependencies
1702 *
1703 * @return A list of node, each being a root of the graph
1704 */
Romain Guybc5d8762012-01-06 16:40:49 -08001705 private ArrayDeque<Node> findRoots(int[] rulesFilter) {
Romain Guy1ab621e2009-06-25 13:31:57 -07001706 final SparseArray<Node> keyNodes = mKeyNodes;
1707 final ArrayList<Node> nodes = mNodes;
Romain Guy725015a2009-06-23 14:27:34 -07001708 final int count = nodes.size();
1709
1710 // Find roots can be invoked several times, so make sure to clear
1711 // all dependents and dependencies before running the algorithm
1712 for (int i = 0; i < count; i++) {
Romain Guy1ab621e2009-06-25 13:31:57 -07001713 final Node node = nodes.get(i);
Romain Guy725015a2009-06-23 14:27:34 -07001714 node.dependents.clear();
1715 node.dependencies.clear();
1716 }
1717
1718 // Builds up the dependents and dependencies for each node of the graph
1719 for (int i = 0; i < count; i++) {
Romain Guy1ab621e2009-06-25 13:31:57 -07001720 final Node node = nodes.get(i);
Romain Guy725015a2009-06-23 14:27:34 -07001721
1722 final LayoutParams layoutParams = (LayoutParams) node.view.getLayoutParams();
1723 final int[] rules = layoutParams.mRules;
1724 final int rulesCount = rulesFilter.length;
1725
1726 // Look only the the rules passed in parameter, this way we build only the
1727 // dependencies for a specific set of rules
1728 for (int j = 0; j < rulesCount; j++) {
1729 final int rule = rules[rulesFilter[j]];
1730 if (rule > 0) {
1731 // The node this node depends on
Romain Guy1ab621e2009-06-25 13:31:57 -07001732 final Node dependency = keyNodes.get(rule);
Romain Guyda3003e2009-07-19 19:47:42 -07001733 // Skip unknowns and self dependencies
1734 if (dependency == null || dependency == node) {
Romain Guyb8f8de82009-06-25 12:03:56 -07001735 continue;
1736 }
Romain Guy725015a2009-06-23 14:27:34 -07001737 // Add the current node as a dependent
Romain Guybc5d8762012-01-06 16:40:49 -08001738 dependency.dependents.put(node, this);
Romain Guy725015a2009-06-23 14:27:34 -07001739 // Add a dependency to the current node
1740 node.dependencies.put(rule, dependency);
1741 }
1742 }
1743 }
1744
Romain Guybc5d8762012-01-06 16:40:49 -08001745 final ArrayDeque<Node> roots = mRoots;
Romain Guy725015a2009-06-23 14:27:34 -07001746 roots.clear();
1747
1748 // Finds all the roots in the graph: all nodes with no dependencies
1749 for (int i = 0; i < count; i++) {
Romain Guy1ab621e2009-06-25 13:31:57 -07001750 final Node node = nodes.get(i);
Romain Guybc5d8762012-01-06 16:40:49 -08001751 if (node.dependencies.size() == 0) roots.addLast(node);
Romain Guy725015a2009-06-23 14:27:34 -07001752 }
1753
1754 return roots;
1755 }
1756
1757 /**
Romain Guy725015a2009-06-23 14:27:34 -07001758 * A node in the dependency graph. A node is a view, its list of dependencies
1759 * and its list of dependents.
1760 *
1761 * A node with no dependent is considered a root of the graph.
1762 */
Svetoslav Ganovabae2a12012-11-27 16:59:37 -08001763 static class Node {
Romain Guy725015a2009-06-23 14:27:34 -07001764 /**
1765 * The view representing this node in the layout.
1766 */
1767 View view;
1768
1769 /**
1770 * The list of dependents for this node; a dependent is a node
1771 * that needs this node to be processed first.
1772 */
Romain Guy6876b4f2013-06-03 14:25:56 -07001773 final ArrayMap<Node, DependencyGraph> dependents =
1774 new ArrayMap<Node, DependencyGraph>();
Romain Guy725015a2009-06-23 14:27:34 -07001775
1776 /**
1777 * The list of dependencies for this node.
1778 */
1779 final SparseArray<Node> dependencies = new SparseArray<Node>();
1780
1781 /*
1782 * START POOL IMPLEMENTATION
1783 */
Romain Guybaac4632009-06-29 14:28:29 -07001784 // The pool is static, so all nodes instances are shared across
1785 // activities, that's why we give it a rather high limit
1786 private static final int POOL_LIMIT = 100;
Romain Guy6876b4f2013-06-03 14:25:56 -07001787 private static final SynchronizedPool<Node> sPool =
1788 new SynchronizedPool<Node>(POOL_LIMIT);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001789
Romain Guy725015a2009-06-23 14:27:34 -07001790 static Node acquire(View view) {
Svetoslav Ganovabae2a12012-11-27 16:59:37 -08001791 Node node = sPool.acquire();
1792 if (node == null) {
1793 node = new Node();
1794 }
Romain Guy725015a2009-06-23 14:27:34 -07001795 node.view = view;
Romain Guy725015a2009-06-23 14:27:34 -07001796 return node;
1797 }
1798
1799 void release() {
1800 view = null;
1801 dependents.clear();
1802 dependencies.clear();
1803
1804 sPool.release(this);
1805 }
1806 /*
1807 * END POOL IMPLEMENTATION
1808 */
1809 }
1810 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001811}