blob: bebe67f3b765f2455135d68f76bb9f843a86dd71 [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) {
Alan Viveretted6479ec2013-09-10 17:03:02 -0700231 this(context, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800232 }
233
234 public RelativeLayout(Context context, AttributeSet attrs) {
Alan Viveretted6479ec2013-09-10 17:03:02 -0700235 this(context, attrs, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800236 }
237
Alan Viverette617feb92013-09-09 18:09:13 -0700238 public RelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
Alan Viveretted6479ec2013-09-10 17:03:02 -0700239 this(context, attrs, defStyleAttr, 0);
Alan Viverette617feb92013-09-09 18:09:13 -0700240 }
241
242 public RelativeLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
243 super(context, attrs, defStyleAttr, defStyleRes);
Alan Viveretted6479ec2013-09-10 17:03:02 -0700244 initFromAttributes(context, attrs, defStyleAttr, defStyleRes);
Romain Guy76d59a32013-04-08 10:51:35 -0700245 queryCompatibilityModes(context);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800246 }
247
Alan Viveretted6479ec2013-09-10 17:03:02 -0700248 private void initFromAttributes(
249 Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
250 final TypedArray a = context.obtainStyledAttributes(
251 attrs, R.styleable.RelativeLayout, defStyleAttr, defStyleRes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800252 mIgnoreGravity = a.getResourceId(R.styleable.RelativeLayout_ignoreGravity, View.NO_ID);
253 mGravity = a.getInt(R.styleable.RelativeLayout_gravity, mGravity);
254 a.recycle();
255 }
256
Romain Guy76d59a32013-04-08 10:51:35 -0700257 private void queryCompatibilityModes(Context context) {
258 int version = context.getApplicationInfo().targetSdkVersion;
259 mAllowBrokenMeasureSpecs = version <= Build.VERSION_CODES.JELLY_BEAN_MR1;
260 mMeasureVerticalWithPaddingMargin = version >= Build.VERSION_CODES.JELLY_BEAN_MR2;
261 }
262
Patrick Dubroye0a799a2011-05-04 16:19:22 -0700263 @Override
264 public boolean shouldDelayChildPressedState() {
265 return false;
266 }
267
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800268 /**
269 * Defines which View is ignored when the gravity is applied. This setting has no
Fabrice Di Megliof443f982012-07-13 20:24:03 -0700270 * effect if the gravity is <code>Gravity.START | Gravity.TOP</code>.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800271 *
272 * @param viewId The id of the View to be ignored by gravity, or 0 if no View
273 * should be ignored.
274 *
275 * @see #setGravity(int)
276 *
277 * @attr ref android.R.styleable#RelativeLayout_ignoreGravity
278 */
279 @android.view.RemotableViewMethod
280 public void setIgnoreGravity(int viewId) {
281 mIgnoreGravity = viewId;
282 }
283
284 /**
Philip Milne1018fb42012-03-13 12:00:04 -0700285 * Describes how the child views are positioned.
286 *
287 * @return the gravity.
288 *
289 * @see #setGravity(int)
290 * @see android.view.Gravity
291 *
292 * @attr ref android.R.styleable#RelativeLayout_gravity
293 */
294 public int getGravity() {
295 return mGravity;
296 }
297
298 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800299 * Describes how the child views are positioned. Defaults to
Fabrice Di Megliof443f982012-07-13 20:24:03 -0700300 * <code>Gravity.START | Gravity.TOP</code>.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800301 *
Adam Powell1fec24e2011-09-15 14:19:30 -0700302 * <p>Note that since RelativeLayout considers the positioning of each child
303 * relative to one another to be significant, setting gravity will affect
304 * the positioning of all children as a single unit within the parent.
305 * This happens after children have been relatively positioned.</p>
306 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800307 * @param gravity See {@link android.view.Gravity}
308 *
309 * @see #setHorizontalGravity(int)
310 * @see #setVerticalGravity(int)
311 *
312 * @attr ref android.R.styleable#RelativeLayout_gravity
313 */
314 @android.view.RemotableViewMethod
315 public void setGravity(int gravity) {
316 if (mGravity != gravity) {
Fabrice Di Meglio6a036402011-05-23 14:43:23 -0700317 if ((gravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) {
Fabrice Di Meglio9e3b0022011-06-06 16:30:29 -0700318 gravity |= Gravity.START;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800319 }
320
321 if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) {
322 gravity |= Gravity.TOP;
323 }
324
325 mGravity = gravity;
326 requestLayout();
327 }
328 }
329
330 @android.view.RemotableViewMethod
331 public void setHorizontalGravity(int horizontalGravity) {
Fabrice Di Meglio6a036402011-05-23 14:43:23 -0700332 final int gravity = horizontalGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK;
333 if ((mGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) != gravity) {
334 mGravity = (mGravity & ~Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) | gravity;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800335 requestLayout();
336 }
337 }
338
339 @android.view.RemotableViewMethod
340 public void setVerticalGravity(int verticalGravity) {
341 final int gravity = verticalGravity & Gravity.VERTICAL_GRAVITY_MASK;
342 if ((mGravity & Gravity.VERTICAL_GRAVITY_MASK) != gravity) {
343 mGravity = (mGravity & ~Gravity.VERTICAL_GRAVITY_MASK) | gravity;
344 requestLayout();
345 }
346 }
347
348 @Override
349 public int getBaseline() {
350 return mBaselineView != null ? mBaselineView.getBaseline() : super.getBaseline();
351 }
352
353 @Override
Romain Guy725015a2009-06-23 14:27:34 -0700354 public void requestLayout() {
355 super.requestLayout();
356 mDirtyHierarchy = true;
357 }
358
359 private void sortChildren() {
Romain Guy6876b4f2013-06-03 14:25:56 -0700360 final int count = getChildCount();
361 if (mSortedVerticalChildren == null || mSortedVerticalChildren.length != count) {
362 mSortedVerticalChildren = new View[count];
363 }
364
365 if (mSortedHorizontalChildren == null || mSortedHorizontalChildren.length != count) {
366 mSortedHorizontalChildren = new View[count];
367 }
Romain Guy725015a2009-06-23 14:27:34 -0700368
369 final DependencyGraph graph = mGraph;
370 graph.clear();
371
372 for (int i = 0; i < count; i++) {
Romain Guy6876b4f2013-06-03 14:25:56 -0700373 graph.add(getChildAt(i));
Romain Guy725015a2009-06-23 14:27:34 -0700374 }
375
Romain Guybc5d8762012-01-06 16:40:49 -0800376 graph.getSortedViews(mSortedVerticalChildren, RULES_VERTICAL);
377 graph.getSortedViews(mSortedHorizontalChildren, RULES_HORIZONTAL);
Romain Guy725015a2009-06-23 14:27:34 -0700378 }
379
380 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800381 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Romain Guy725015a2009-06-23 14:27:34 -0700382 if (mDirtyHierarchy) {
383 mDirtyHierarchy = false;
384 sortChildren();
385 }
386
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800387 int myWidth = -1;
388 int myHeight = -1;
389
390 int width = 0;
391 int height = 0;
392
Adam Powell132a7422012-09-30 12:39:56 -0700393 final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
394 final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
395 final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
396 final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800397
398 // Record our dimensions if they are known;
399 if (widthMode != MeasureSpec.UNSPECIFIED) {
400 myWidth = widthSize;
401 }
402
403 if (heightMode != MeasureSpec.UNSPECIFIED) {
404 myHeight = heightSize;
405 }
406
407 if (widthMode == MeasureSpec.EXACTLY) {
408 width = myWidth;
409 }
410
411 if (heightMode == MeasureSpec.EXACTLY) {
412 height = myHeight;
413 }
414
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800415 mHasBaselineAlignedChild = false;
416
417 View ignore = null;
Fabrice Di Meglio6a036402011-05-23 14:43:23 -0700418 int gravity = mGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK;
Fabrice Di Megliof443f982012-07-13 20:24:03 -0700419 final boolean horizontalGravity = gravity != Gravity.START && gravity != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800420 gravity = mGravity & Gravity.VERTICAL_GRAVITY_MASK;
421 final boolean verticalGravity = gravity != Gravity.TOP && gravity != 0;
422
423 int left = Integer.MAX_VALUE;
424 int top = Integer.MAX_VALUE;
425 int right = Integer.MIN_VALUE;
426 int bottom = Integer.MIN_VALUE;
427
Romain Guyf7dabb02009-06-25 14:47:14 -0700428 boolean offsetHorizontalAxis = false;
429 boolean offsetVerticalAxis = false;
430
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800431 if ((horizontalGravity || verticalGravity) && mIgnoreGravity != View.NO_ID) {
432 ignore = findViewById(mIgnoreGravity);
433 }
434
Romain Guyf7dabb02009-06-25 14:47:14 -0700435 final boolean isWrapContentWidth = widthMode != MeasureSpec.EXACTLY;
436 final boolean isWrapContentHeight = heightMode != MeasureSpec.EXACTLY;
437
Fabrice Di Meglio306fe5c2013-01-23 18:46:25 -0800438 // We need to know our size for doing the correct computation of children positioning in RTL
439 // mode but there is no practical way to get it instead of running the code below.
Fabrice Di Megliod5ffc792013-02-19 15:59:21 -0800440 // 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 -0800441 // before the computation and then, as a last pass, we will update their real position with
Fabrice Di Megliod5ffc792013-02-19 15:59:21 -0800442 // an offset equals to "DEFAULT_WIDTH - width".
Fabrice Di Meglio306fe5c2013-01-23 18:46:25 -0800443 final int layoutDirection = getLayoutDirection();
444 if (isLayoutRtl() && myWidth == -1) {
Fabrice Di Megliod5ffc792013-02-19 15:59:21 -0800445 myWidth = DEFAULT_WIDTH;
Fabrice Di Meglio306fe5c2013-01-23 18:46:25 -0800446 }
447
Romain Guye24ef602009-06-25 13:01:55 -0700448 View[] views = mSortedHorizontalChildren;
Romain Guy725015a2009-06-23 14:27:34 -0700449 int count = views.length;
Fabrice Di Meglio13705ed2012-11-26 20:05:31 -0800450
Romain Guy725015a2009-06-23 14:27:34 -0700451 for (int i = 0; i < count; i++) {
452 View child = views[i];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800453 if (child.getVisibility() != GONE) {
454 LayoutParams params = (LayoutParams) child.getLayoutParams();
Fabrice Di Meglio54726132013-01-18 18:36:45 -0800455 int[] rules = params.getRules(layoutDirection);
Romain Guy95607032009-06-24 14:37:03 -0700456
Fabrice Di Meglio54726132013-01-18 18:36:45 -0800457 applyHorizontalSizeRules(params, myWidth, rules);
Romain Guyf782e602009-06-25 15:26:49 -0700458 measureChildHorizontal(child, params, myWidth, myHeight);
Fabrice Di Meglio54726132013-01-18 18:36:45 -0800459
Romain Guyf7dabb02009-06-25 14:47:14 -0700460 if (positionChildHorizontal(child, params, myWidth, isWrapContentWidth)) {
461 offsetHorizontalAxis = true;
462 }
Romain Guy725015a2009-06-23 14:27:34 -0700463 }
464 }
465
Romain Guye24ef602009-06-25 13:01:55 -0700466 views = mSortedVerticalChildren;
Romain Guy725015a2009-06-23 14:27:34 -0700467 count = views.length;
Fabrice Di Meglio2bd961a2013-08-27 19:46:43 -0700468 final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion;
Romain Guyf7dabb02009-06-25 14:47:14 -0700469
Romain Guy725015a2009-06-23 14:27:34 -0700470 for (int i = 0; i < count; i++) {
471 View child = views[i];
472 if (child.getVisibility() != GONE) {
473 LayoutParams params = (LayoutParams) child.getLayoutParams();
Romain Guy95607032009-06-24 14:37:03 -0700474
475 applyVerticalSizeRules(params, myHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800476 measureChild(child, params, myWidth, myHeight);
Romain Guyf7dabb02009-06-25 14:47:14 -0700477 if (positionChildVertical(child, params, myHeight, isWrapContentHeight)) {
478 offsetVerticalAxis = true;
479 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800480
Romain Guyf7dabb02009-06-25 14:47:14 -0700481 if (isWrapContentWidth) {
Fabrice Di Meglio306fe5c2013-01-23 18:46:25 -0800482 if (isLayoutRtl()) {
Chet Haasee8222dd2013-09-05 07:44:18 -0700483 if (targetSdkVersion < Build.VERSION_CODES.KITKAT) {
Fabrice Di Meglio2bd961a2013-08-27 19:46:43 -0700484 width = Math.max(width, myWidth - params.mLeft);
485 } else {
486 width = Math.max(width, myWidth - params.mLeft - params.leftMargin);
487 }
Fabrice Di Meglio306fe5c2013-01-23 18:46:25 -0800488 } else {
Chet Haasee8222dd2013-09-05 07:44:18 -0700489 if (targetSdkVersion < Build.VERSION_CODES.KITKAT) {
Fabrice Di Meglio2bd961a2013-08-27 19:46:43 -0700490 width = Math.max(width, params.mRight);
491 } else {
492 width = Math.max(width, params.mRight + params.rightMargin);
493 }
Fabrice Di Meglio306fe5c2013-01-23 18:46:25 -0800494 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800495 }
Romain Guyf7dabb02009-06-25 14:47:14 -0700496
497 if (isWrapContentHeight) {
Chet Haasee8222dd2013-09-05 07:44:18 -0700498 if (targetSdkVersion < Build.VERSION_CODES.KITKAT) {
Fabrice Di Meglio2bd961a2013-08-27 19:46:43 -0700499 height = Math.max(height, params.mBottom);
500 } else {
501 height = Math.max(height, params.mBottom + params.bottomMargin);
502 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800503 }
504
505 if (child != ignore || verticalGravity) {
506 left = Math.min(left, params.mLeft - params.leftMargin);
507 top = Math.min(top, params.mTop - params.topMargin);
508 }
509
510 if (child != ignore || horizontalGravity) {
511 right = Math.max(right, params.mRight + params.rightMargin);
512 bottom = Math.max(bottom, params.mBottom + params.bottomMargin);
513 }
514 }
515 }
516
517 if (mHasBaselineAlignedChild) {
Romain Guy725015a2009-06-23 14:27:34 -0700518 for (int i = 0; i < count; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800519 View child = getChildAt(i);
520 if (child.getVisibility() != GONE) {
521 LayoutParams params = (LayoutParams) child.getLayoutParams();
522 alignBaseline(child, params);
523
524 if (child != ignore || verticalGravity) {
Romain Guy725015a2009-06-23 14:27:34 -0700525 left = Math.min(left, params.mLeft - params.leftMargin);
526 top = Math.min(top, params.mTop - params.topMargin);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800527 }
528
529 if (child != ignore || horizontalGravity) {
530 right = Math.max(right, params.mRight + params.rightMargin);
531 bottom = Math.max(bottom, params.mBottom + params.bottomMargin);
532 }
533 }
534 }
535 }
536
Romain Guyf7dabb02009-06-25 14:47:14 -0700537 if (isWrapContentWidth) {
Romain Guya1f3e4a2009-06-04 15:10:46 -0700538 // Width already has left padding in it since it was calculated by looking at
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800539 // the right of each child view
540 width += mPaddingRight;
541
Adam Powell758d5a42013-09-13 09:22:30 -0700542 if (mLayoutParams != null && mLayoutParams.width >= 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800543 width = Math.max(width, mLayoutParams.width);
544 }
545
546 width = Math.max(width, getSuggestedMinimumWidth());
547 width = resolveSize(width, widthMeasureSpec);
Romain Guyf7dabb02009-06-25 14:47:14 -0700548
549 if (offsetHorizontalAxis) {
Romain Guyd10a5762009-07-28 11:18:14 -0700550 for (int i = 0; i < count; i++) {
Romain Guyf7dabb02009-06-25 14:47:14 -0700551 View child = getChildAt(i);
552 if (child.getVisibility() != GONE) {
553 LayoutParams params = (LayoutParams) child.getLayoutParams();
Fabrice Di Megliof443f982012-07-13 20:24:03 -0700554 final int[] rules = params.getRules(layoutDirection);
Romain Guyf7dabb02009-06-25 14:47:14 -0700555 if (rules[CENTER_IN_PARENT] != 0 || rules[CENTER_HORIZONTAL] != 0) {
556 centerHorizontal(child, params, width);
Romain Guy42460ac2010-01-11 16:46:33 -0800557 } else if (rules[ALIGN_PARENT_RIGHT] != 0) {
558 final int childWidth = child.getMeasuredWidth();
559 params.mLeft = width - mPaddingRight - childWidth;
560 params.mRight = params.mLeft + childWidth;
Romain Guyf7dabb02009-06-25 14:47:14 -0700561 }
562 }
563 }
564 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800565 }
Romain Guyf7dabb02009-06-25 14:47:14 -0700566
567 if (isWrapContentHeight) {
Romain Guya1f3e4a2009-06-04 15:10:46 -0700568 // Height already has top padding in it since it was calculated by looking at
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800569 // the bottom of each child view
570 height += mPaddingBottom;
571
Adam Powell758d5a42013-09-13 09:22:30 -0700572 if (mLayoutParams != null && mLayoutParams.height >= 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800573 height = Math.max(height, mLayoutParams.height);
574 }
575
576 height = Math.max(height, getSuggestedMinimumHeight());
577 height = resolveSize(height, heightMeasureSpec);
Romain Guyf7dabb02009-06-25 14:47:14 -0700578
579 if (offsetVerticalAxis) {
580 for (int i = 0; i < count; i++) {
581 View child = getChildAt(i);
582 if (child.getVisibility() != GONE) {
583 LayoutParams params = (LayoutParams) child.getLayoutParams();
Fabrice Di Megliof443f982012-07-13 20:24:03 -0700584 final int[] rules = params.getRules(layoutDirection);
Romain Guyf7dabb02009-06-25 14:47:14 -0700585 if (rules[CENTER_IN_PARENT] != 0 || rules[CENTER_VERTICAL] != 0) {
586 centerVertical(child, params, height);
Romain Guy42460ac2010-01-11 16:46:33 -0800587 } else if (rules[ALIGN_PARENT_BOTTOM] != 0) {
588 final int childHeight = child.getMeasuredHeight();
589 params.mTop = height - mPaddingBottom - childHeight;
590 params.mBottom = params.mTop + childHeight;
Romain Guyf7dabb02009-06-25 14:47:14 -0700591 }
592 }
593 }
594 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800595 }
596
597 if (horizontalGravity || verticalGravity) {
598 final Rect selfBounds = mSelfBounds;
599 selfBounds.set(mPaddingLeft, mPaddingTop, width - mPaddingRight,
600 height - mPaddingBottom);
601
602 final Rect contentBounds = mContentBounds;
Fabrice Di Meglio6a036402011-05-23 14:43:23 -0700603 Gravity.apply(mGravity, right - left, bottom - top, selfBounds, contentBounds,
Fabrice Di Meglioc0053222011-06-13 12:16:51 -0700604 layoutDirection);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800605
606 final int horizontalOffset = contentBounds.left - left;
607 final int verticalOffset = contentBounds.top - top;
608 if (horizontalOffset != 0 || verticalOffset != 0) {
Romain Guy725015a2009-06-23 14:27:34 -0700609 for (int i = 0; i < count; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800610 View child = getChildAt(i);
611 if (child.getVisibility() != GONE && child != ignore) {
612 LayoutParams params = (LayoutParams) child.getLayoutParams();
Romain Guyd10a5762009-07-28 11:18:14 -0700613 if (horizontalGravity) {
614 params.mLeft += horizontalOffset;
615 params.mRight += horizontalOffset;
616 }
617 if (verticalGravity) {
618 params.mTop += verticalOffset;
619 params.mBottom += verticalOffset;
620 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800621 }
622 }
623 }
624 }
625
Fabrice Di Meglio306fe5c2013-01-23 18:46:25 -0800626 if (isLayoutRtl()) {
627 final int offsetWidth = myWidth - width;
628 for (int i = 0; i < count; i++) {
629 View child = getChildAt(i);
630 if (child.getVisibility() != GONE) {
631 LayoutParams params = (LayoutParams) child.getLayoutParams();
632 params.mLeft -= offsetWidth;
633 params.mRight -= offsetWidth;
634 }
635 }
636
637 }
638
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800639 setMeasuredDimension(width, height);
640 }
641
642 private void alignBaseline(View child, LayoutParams params) {
Fabrice Di Meglioe56ffdc2012-09-23 14:51:16 -0700643 final int layoutDirection = getLayoutDirection();
Fabrice Di Megliof443f982012-07-13 20:24:03 -0700644 int[] rules = params.getRules(layoutDirection);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800645 int anchorBaseline = getRelatedViewBaseline(rules, ALIGN_BASELINE);
646
647 if (anchorBaseline != -1) {
648 LayoutParams anchorParams = getRelatedViewParams(rules, ALIGN_BASELINE);
649 if (anchorParams != null) {
650 int offset = anchorParams.mTop + anchorBaseline;
651 int baseline = child.getBaseline();
652 if (baseline != -1) {
653 offset -= baseline;
654 }
655 int height = params.mBottom - params.mTop;
656 params.mTop = offset;
657 params.mBottom = params.mTop + height;
658 }
659 }
660
661 if (mBaselineView == null) {
662 mBaselineView = child;
663 } else {
664 LayoutParams lp = (LayoutParams) mBaselineView.getLayoutParams();
665 if (params.mTop < lp.mTop || (params.mTop == lp.mTop && params.mLeft < lp.mLeft)) {
666 mBaselineView = child;
667 }
668 }
669 }
670
671 /**
672 * Measure a child. The child should have left, top, right and bottom information
673 * stored in its LayoutParams. If any of these values is -1 it means that the view
674 * can extend up to the corresponding edge.
675 *
676 * @param child Child to measure
677 * @param params LayoutParams associated with child
678 * @param myWidth Width of the the RelativeLayout
679 * @param myHeight Height of the RelativeLayout
680 */
Romain Guy725015a2009-06-23 14:27:34 -0700681 private void measureChild(View child, LayoutParams params, int myWidth, int myHeight) {
Romain Guye8fb03c2013-04-25 11:40:45 -0700682 int childWidthMeasureSpec = getChildMeasureSpec(params.mLeft,
683 params.mRight, params.width,
684 params.leftMargin, params.rightMargin,
685 mPaddingLeft, mPaddingRight,
686 myWidth);
Romain Guy1b7c7912013-04-25 14:55:28 -0700687 int childHeightMeasureSpec = getChildMeasureSpec(params.mTop,
688 params.mBottom, params.height,
689 params.topMargin, params.bottomMargin,
690 mPaddingTop, mPaddingBottom,
691 myHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800692 child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
693 }
694
Romain Guyf782e602009-06-25 15:26:49 -0700695 private void measureChildHorizontal(View child, LayoutParams params, int myWidth, int myHeight) {
Romain Guy95607032009-06-24 14:37:03 -0700696 int childWidthMeasureSpec = getChildMeasureSpec(params.mLeft,
697 params.mRight, params.width,
698 params.leftMargin, params.rightMargin,
699 mPaddingLeft, mPaddingRight,
700 myWidth);
Romain Guy76d59a32013-04-08 10:51:35 -0700701 int maxHeight = myHeight;
702 if (mMeasureVerticalWithPaddingMargin) {
703 maxHeight = Math.max(0, myHeight - mPaddingTop - mPaddingBottom -
704 params.topMargin - params.bottomMargin);
705 }
Romain Guyf782e602009-06-25 15:26:49 -0700706 int childHeightMeasureSpec;
Adam Powell7da4b732012-12-07 15:28:33 -0800707 if (myHeight < 0 && !mAllowBrokenMeasureSpecs) {
Romain Guyf16c7a92013-02-11 17:43:59 -0800708 if (params.height >= 0) {
709 childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
710 params.height, MeasureSpec.EXACTLY);
711 } else {
712 // Negative values in a mySize/myWidth/myWidth value in RelativeLayout measurement
713 // is code for, "we got an unspecified mode in the RelativeLayout's measurespec."
714 // Carry it forward.
715 childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
716 }
Adam Powell132a7422012-09-30 12:39:56 -0700717 } else if (params.width == LayoutParams.MATCH_PARENT) {
Romain Guy76d59a32013-04-08 10:51:35 -0700718 childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(maxHeight, MeasureSpec.EXACTLY);
Romain Guyf782e602009-06-25 15:26:49 -0700719 } else {
Romain Guy76d59a32013-04-08 10:51:35 -0700720 childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(maxHeight, MeasureSpec.AT_MOST);
Romain Guyf782e602009-06-25 15:26:49 -0700721 }
Romain Guy725015a2009-06-23 14:27:34 -0700722 child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
723 }
724
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800725 /**
726 * Get a measure spec that accounts for all of the constraints on this view.
Fabrice Di Megliof443f982012-07-13 20:24:03 -0700727 * This includes size constraints imposed by the RelativeLayout as well as
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800728 * the View's desired dimension.
729 *
730 * @param childStart The left or top field of the child's layout params
731 * @param childEnd The right or bottom field of the child's layout params
732 * @param childSize The child's desired size (the width or height field of
733 * the child's layout params)
734 * @param startMargin The left or top margin
735 * @param endMargin The right or bottom margin
736 * @param startPadding mPaddingLeft or mPaddingTop
737 * @param endPadding mPaddingRight or mPaddingBottom
738 * @param mySize The width or height of this view (the RelativeLayout)
739 * @return MeasureSpec for the child
740 */
741 private int getChildMeasureSpec(int childStart, int childEnd,
742 int childSize, int startMargin, int endMargin, int startPadding,
743 int endPadding, int mySize) {
744 int childSpecMode = 0;
745 int childSpecSize = 0;
746
Alan Viverette517a0042013-12-04 17:08:44 -0800747 // Negative values in a mySize/myWidth/myWidth value in RelativeLayout
748 // measurement is code for, "we got an unspecified mode in the
749 // RelativeLayout's measure spec."
750 if (mySize < 0 && !mAllowBrokenMeasureSpecs) {
751 if (childSize >= 0) {
752 // The child specified an exact size.
753 childSpecSize = childSize;
754 childSpecMode = MeasureSpec.EXACTLY;
755 } else if (childStart >= 0 && childEnd >= 0) {
756 // Constraints fixed both edges, so child has an exact size.
757 childSpecSize = Math.max(0, childEnd - childStart);
758 childSpecMode = MeasureSpec.EXACTLY;
759 } else {
760 // Allow the child to be whatever size it wants.
761 childSpecSize = 0;
762 childSpecMode = MeasureSpec.UNSPECIFIED;
763 }
764
765 return MeasureSpec.makeMeasureSpec(childSpecSize, childSpecMode);
766 }
767
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800768 // Figure out start and end bounds.
769 int tempStart = childStart;
770 int tempEnd = childEnd;
771
772 // If the view did not express a layout constraint for an edge, use
773 // view's margins and our padding
774 if (tempStart < 0) {
775 tempStart = startPadding + startMargin;
776 }
777 if (tempEnd < 0) {
778 tempEnd = mySize - endPadding - endMargin;
779 }
780
781 // Figure out maximum size available to this view
782 int maxAvailable = tempEnd - tempStart;
783
784 if (childStart >= 0 && childEnd >= 0) {
785 // Constraints fixed both edges, so child must be an exact size
786 childSpecMode = MeasureSpec.EXACTLY;
787 childSpecSize = maxAvailable;
788 } else {
789 if (childSize >= 0) {
790 // Child wanted an exact size. Give as much as possible
791 childSpecMode = MeasureSpec.EXACTLY;
792
793 if (maxAvailable >= 0) {
794 // We have a maxmum size in this dimension.
795 childSpecSize = Math.min(maxAvailable, childSize);
796 } else {
797 // We can grow in this dimension.
798 childSpecSize = childSize;
799 }
Romain Guy980a9382010-01-08 15:06:28 -0800800 } else if (childSize == LayoutParams.MATCH_PARENT) {
Fabrice Di Megliof443f982012-07-13 20:24:03 -0700801 // Child wanted to be as big as possible. Give all available
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800802 // space
803 childSpecMode = MeasureSpec.EXACTLY;
804 childSpecSize = maxAvailable;
805 } else if (childSize == LayoutParams.WRAP_CONTENT) {
806 // Child wants to wrap content. Use AT_MOST
807 // to communicate available space if we know
808 // our max size
809 if (maxAvailable >= 0) {
Fabrice Di Megliof443f982012-07-13 20:24:03 -0700810 // We have a maximum size in this dimension.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800811 childSpecMode = MeasureSpec.AT_MOST;
812 childSpecSize = maxAvailable;
813 } else {
814 // We can grow in this dimension. Child can be as big as it
815 // wants
816 childSpecMode = MeasureSpec.UNSPECIFIED;
817 childSpecSize = 0;
818 }
819 }
820 }
821
822 return MeasureSpec.makeMeasureSpec(childSpecSize, childSpecMode);
823 }
824
Romain Guyf7dabb02009-06-25 14:47:14 -0700825 private boolean positionChildHorizontal(View child, LayoutParams params, int myWidth,
826 boolean wrapContent) {
827
Fabrice Di Meglioe56ffdc2012-09-23 14:51:16 -0700828 final int layoutDirection = getLayoutDirection();
Fabrice Di Megliof443f982012-07-13 20:24:03 -0700829 int[] rules = params.getRules(layoutDirection);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800830
831 if (params.mLeft < 0 && params.mRight >= 0) {
832 // Right is fixed, but left varies
833 params.mLeft = params.mRight - child.getMeasuredWidth();
834 } else if (params.mLeft >= 0 && params.mRight < 0) {
835 // Left is fixed, but right varies
836 params.mRight = params.mLeft + child.getMeasuredWidth();
837 } else if (params.mLeft < 0 && params.mRight < 0) {
838 // Both left and right vary
Romain Guyf7dabb02009-06-25 14:47:14 -0700839 if (rules[CENTER_IN_PARENT] != 0 || rules[CENTER_HORIZONTAL] != 0) {
840 if (!wrapContent) {
841 centerHorizontal(child, params, myWidth);
842 } else {
843 params.mLeft = mPaddingLeft + params.leftMargin;
844 params.mRight = params.mLeft + child.getMeasuredWidth();
845 }
846 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800847 } else {
Fabrice Di Megliof443f982012-07-13 20:24:03 -0700848 // This is the default case. For RTL we start from the right and for LTR we start
849 // from the left. This will give LEFT/TOP for LTR and RIGHT/TOP for RTL.
850 if (isLayoutRtl()) {
851 params.mRight = myWidth - mPaddingRight- params.rightMargin;
852 params.mLeft = params.mRight - child.getMeasuredWidth();
853 } else {
854 params.mLeft = mPaddingLeft + params.leftMargin;
855 params.mRight = params.mLeft + child.getMeasuredWidth();
856 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800857 }
858 }
Fabrice Di Megliof443f982012-07-13 20:24:03 -0700859 return rules[ALIGN_PARENT_END] != 0;
Romain Guy725015a2009-06-23 14:27:34 -0700860 }
861
Romain Guyf7dabb02009-06-25 14:47:14 -0700862 private boolean positionChildVertical(View child, LayoutParams params, int myHeight,
863 boolean wrapContent) {
864
Romain Guy725015a2009-06-23 14:27:34 -0700865 int[] rules = params.getRules();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800866
867 if (params.mTop < 0 && params.mBottom >= 0) {
868 // Bottom is fixed, but top varies
869 params.mTop = params.mBottom - child.getMeasuredHeight();
870 } else if (params.mTop >= 0 && params.mBottom < 0) {
871 // Top is fixed, but bottom varies
872 params.mBottom = params.mTop + child.getMeasuredHeight();
873 } else if (params.mTop < 0 && params.mBottom < 0) {
874 // Both top and bottom vary
Romain Guyf7dabb02009-06-25 14:47:14 -0700875 if (rules[CENTER_IN_PARENT] != 0 || rules[CENTER_VERTICAL] != 0) {
876 if (!wrapContent) {
877 centerVertical(child, params, myHeight);
878 } else {
879 params.mTop = mPaddingTop + params.topMargin;
880 params.mBottom = params.mTop + child.getMeasuredHeight();
881 }
882 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800883 } else {
884 params.mTop = mPaddingTop + params.topMargin;
885 params.mBottom = params.mTop + child.getMeasuredHeight();
886 }
887 }
Romain Guy42460ac2010-01-11 16:46:33 -0800888 return rules[ALIGN_PARENT_BOTTOM] != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800889 }
890
Fabrice Di Meglio54726132013-01-18 18:36:45 -0800891 private void applyHorizontalSizeRules(LayoutParams childParams, int myWidth, int[] rules) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800892 RelativeLayout.LayoutParams anchorParams;
893
894 // -1 indicated a "soft requirement" in that direction. For example:
895 // left=10, right=-1 means the view must start at 10, but can go as far as it wants to the right
896 // left =-1, right=10 means the view must end at 10, but can go as far as it wants to the left
897 // left=10, right=20 means the left and right ends are both fixed
898 childParams.mLeft = -1;
899 childParams.mRight = -1;
900
901 anchorParams = getRelatedViewParams(rules, LEFT_OF);
902 if (anchorParams != null) {
903 childParams.mRight = anchorParams.mLeft - (anchorParams.leftMargin +
904 childParams.rightMargin);
905 } else if (childParams.alignWithParent && rules[LEFT_OF] != 0) {
906 if (myWidth >= 0) {
907 childParams.mRight = myWidth - mPaddingRight - childParams.rightMargin;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800908 }
909 }
910
911 anchorParams = getRelatedViewParams(rules, RIGHT_OF);
912 if (anchorParams != null) {
913 childParams.mLeft = anchorParams.mRight + (anchorParams.rightMargin +
914 childParams.leftMargin);
915 } else if (childParams.alignWithParent && rules[RIGHT_OF] != 0) {
916 childParams.mLeft = mPaddingLeft + childParams.leftMargin;
917 }
918
919 anchorParams = getRelatedViewParams(rules, ALIGN_LEFT);
920 if (anchorParams != null) {
921 childParams.mLeft = anchorParams.mLeft + childParams.leftMargin;
922 } else if (childParams.alignWithParent && rules[ALIGN_LEFT] != 0) {
923 childParams.mLeft = mPaddingLeft + childParams.leftMargin;
924 }
925
926 anchorParams = getRelatedViewParams(rules, ALIGN_RIGHT);
927 if (anchorParams != null) {
928 childParams.mRight = anchorParams.mRight - childParams.rightMargin;
929 } else if (childParams.alignWithParent && rules[ALIGN_RIGHT] != 0) {
930 if (myWidth >= 0) {
931 childParams.mRight = myWidth - mPaddingRight - childParams.rightMargin;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800932 }
933 }
934
Romain Guy1b7c7912013-04-25 14:55:28 -0700935 if (0 != rules[ALIGN_PARENT_LEFT]) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800936 childParams.mLeft = mPaddingLeft + childParams.leftMargin;
937 }
938
Romain Guy1b7c7912013-04-25 14:55:28 -0700939 if (0 != rules[ALIGN_PARENT_RIGHT]) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800940 if (myWidth >= 0) {
941 childParams.mRight = myWidth - mPaddingRight - childParams.rightMargin;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800942 }
943 }
Romain Guy725015a2009-06-23 14:27:34 -0700944 }
945
946 private void applyVerticalSizeRules(LayoutParams childParams, int myHeight) {
947 int[] rules = childParams.getRules();
948 RelativeLayout.LayoutParams anchorParams;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800949
950 childParams.mTop = -1;
951 childParams.mBottom = -1;
952
953 anchorParams = getRelatedViewParams(rules, ABOVE);
954 if (anchorParams != null) {
955 childParams.mBottom = anchorParams.mTop - (anchorParams.topMargin +
956 childParams.bottomMargin);
957 } else if (childParams.alignWithParent && rules[ABOVE] != 0) {
958 if (myHeight >= 0) {
959 childParams.mBottom = myHeight - mPaddingBottom - childParams.bottomMargin;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800960 }
961 }
962
963 anchorParams = getRelatedViewParams(rules, BELOW);
964 if (anchorParams != null) {
965 childParams.mTop = anchorParams.mBottom + (anchorParams.bottomMargin +
966 childParams.topMargin);
967 } else if (childParams.alignWithParent && rules[BELOW] != 0) {
968 childParams.mTop = mPaddingTop + childParams.topMargin;
969 }
970
971 anchorParams = getRelatedViewParams(rules, ALIGN_TOP);
972 if (anchorParams != null) {
973 childParams.mTop = anchorParams.mTop + childParams.topMargin;
974 } else if (childParams.alignWithParent && rules[ALIGN_TOP] != 0) {
975 childParams.mTop = mPaddingTop + childParams.topMargin;
976 }
977
978 anchorParams = getRelatedViewParams(rules, ALIGN_BOTTOM);
979 if (anchorParams != null) {
980 childParams.mBottom = anchorParams.mBottom - childParams.bottomMargin;
981 } else if (childParams.alignWithParent && rules[ALIGN_BOTTOM] != 0) {
982 if (myHeight >= 0) {
983 childParams.mBottom = myHeight - mPaddingBottom - childParams.bottomMargin;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800984 }
985 }
986
Romain Guy1b7c7912013-04-25 14:55:28 -0700987 if (0 != rules[ALIGN_PARENT_TOP]) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800988 childParams.mTop = mPaddingTop + childParams.topMargin;
989 }
990
Romain Guy1b7c7912013-04-25 14:55:28 -0700991 if (0 != rules[ALIGN_PARENT_BOTTOM]) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800992 if (myHeight >= 0) {
993 childParams.mBottom = myHeight - mPaddingBottom - childParams.bottomMargin;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800994 }
995 }
996
997 if (rules[ALIGN_BASELINE] != 0) {
998 mHasBaselineAlignedChild = true;
999 }
1000 }
1001
1002 private View getRelatedView(int[] rules, int relation) {
1003 int id = rules[relation];
1004 if (id != 0) {
Romain Guy1ab621e2009-06-25 13:31:57 -07001005 DependencyGraph.Node node = mGraph.mKeyNodes.get(id);
Romain Guya0fd1d72009-06-24 14:25:43 -07001006 if (node == null) return null;
1007 View v = node.view;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001008
1009 // Find the first non-GONE view up the chain
1010 while (v.getVisibility() == View.GONE) {
Fabrice Di Meglio13705ed2012-11-26 20:05:31 -08001011 rules = ((LayoutParams) v.getLayoutParams()).getRules(v.getLayoutDirection());
Romain Guy1ab621e2009-06-25 13:31:57 -07001012 node = mGraph.mKeyNodes.get((rules[relation]));
Romain Guya0fd1d72009-06-24 14:25:43 -07001013 if (node == null) return null;
1014 v = node.view;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001015 }
1016
1017 return v;
1018 }
1019
1020 return null;
1021 }
1022
1023 private LayoutParams getRelatedViewParams(int[] rules, int relation) {
1024 View v = getRelatedView(rules, relation);
1025 if (v != null) {
1026 ViewGroup.LayoutParams params = v.getLayoutParams();
1027 if (params instanceof LayoutParams) {
1028 return (LayoutParams) v.getLayoutParams();
1029 }
1030 }
1031 return null;
1032 }
1033
1034 private int getRelatedViewBaseline(int[] rules, int relation) {
1035 View v = getRelatedView(rules, relation);
1036 if (v != null) {
1037 return v.getBaseline();
1038 }
1039 return -1;
1040 }
1041
Romain Guyf16c7a92013-02-11 17:43:59 -08001042 private static void centerHorizontal(View child, LayoutParams params, int myWidth) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001043 int childWidth = child.getMeasuredWidth();
1044 int left = (myWidth - childWidth) / 2;
1045
1046 params.mLeft = left;
1047 params.mRight = left + childWidth;
1048 }
1049
Romain Guyf16c7a92013-02-11 17:43:59 -08001050 private static void centerVertical(View child, LayoutParams params, int myHeight) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001051 int childHeight = child.getMeasuredHeight();
1052 int top = (myHeight - childHeight) / 2;
1053
1054 params.mTop = top;
1055 params.mBottom = top + childHeight;
1056 }
1057
1058 @Override
1059 protected void onLayout(boolean changed, int l, int t, int r, int b) {
1060 // The layout has actually already been performed and the positions
1061 // cached. Apply the cached values to the children.
Fabrice Di Meglio13705ed2012-11-26 20:05:31 -08001062 final int count = getChildCount();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001063
1064 for (int i = 0; i < count; i++) {
1065 View child = getChildAt(i);
1066 if (child.getVisibility() != GONE) {
1067 RelativeLayout.LayoutParams st =
1068 (RelativeLayout.LayoutParams) child.getLayoutParams();
1069 child.layout(st.mLeft, st.mTop, st.mRight, st.mBottom);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001070 }
1071 }
1072 }
1073
1074 @Override
1075 public LayoutParams generateLayoutParams(AttributeSet attrs) {
1076 return new RelativeLayout.LayoutParams(getContext(), attrs);
1077 }
1078
1079 /**
1080 * Returns a set of layout parameters with a width of
1081 * {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT},
1082 * a height of {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT} and no spanning.
1083 */
1084 @Override
1085 protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
1086 return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
1087 }
1088
1089 // Override to allow type-checking of LayoutParams.
1090 @Override
1091 protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
1092 return p instanceof RelativeLayout.LayoutParams;
1093 }
1094
1095 @Override
1096 protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
1097 return new LayoutParams(p);
1098 }
1099
svetoslavganov75986cf2009-05-14 22:28:01 -07001100 @Override
1101 public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
1102 if (mTopToBottomLeftToRightSet == null) {
1103 mTopToBottomLeftToRightSet = new TreeSet<View>(new TopToBottomLeftToRightComparator());
1104 }
1105
1106 // sort children top-to-bottom and left-to-right
1107 for (int i = 0, count = getChildCount(); i < count; i++) {
1108 mTopToBottomLeftToRightSet.add(getChildAt(i));
1109 }
1110
1111 for (View view : mTopToBottomLeftToRightSet) {
Svetoslav Ganov0b0a41d2011-09-07 18:06:03 -07001112 if (view.getVisibility() == View.VISIBLE
1113 && view.dispatchPopulateAccessibilityEvent(event)) {
svetoslavganov75986cf2009-05-14 22:28:01 -07001114 mTopToBottomLeftToRightSet.clear();
1115 return true;
1116 }
1117 }
1118
1119 mTopToBottomLeftToRightSet.clear();
1120 return false;
1121 }
1122
Svetoslav Ganov8a78fd42012-01-17 14:36:46 -08001123 @Override
1124 public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
1125 super.onInitializeAccessibilityEvent(event);
1126 event.setClassName(RelativeLayout.class.getName());
1127 }
1128
1129 @Override
1130 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
1131 super.onInitializeAccessibilityNodeInfo(info);
1132 info.setClassName(RelativeLayout.class.getName());
1133 }
1134
svetoslavganov75986cf2009-05-14 22:28:01 -07001135 /**
1136 * Compares two views in left-to-right and top-to-bottom fashion.
1137 */
1138 private class TopToBottomLeftToRightComparator implements Comparator<View> {
1139 public int compare(View first, View second) {
1140 // top - bottom
1141 int topDifference = first.getTop() - second.getTop();
1142 if (topDifference != 0) {
1143 return topDifference;
1144 }
1145 // left - right
1146 int leftDifference = first.getLeft() - second.getLeft();
1147 if (leftDifference != 0) {
1148 return leftDifference;
1149 }
1150 // break tie by height
1151 int heightDiference = first.getHeight() - second.getHeight();
1152 if (heightDiference != 0) {
1153 return heightDiference;
1154 }
1155 // break tie by width
1156 int widthDiference = first.getWidth() - second.getWidth();
1157 if (widthDiference != 0) {
1158 return widthDiference;
1159 }
1160 return 0;
1161 }
1162 }
1163
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001164 /**
1165 * Per-child layout information associated with RelativeLayout.
1166 *
1167 * @attr ref android.R.styleable#RelativeLayout_Layout_layout_alignWithParentIfMissing
1168 * @attr ref android.R.styleable#RelativeLayout_Layout_layout_toLeftOf
1169 * @attr ref android.R.styleable#RelativeLayout_Layout_layout_toRightOf
1170 * @attr ref android.R.styleable#RelativeLayout_Layout_layout_above
1171 * @attr ref android.R.styleable#RelativeLayout_Layout_layout_below
1172 * @attr ref android.R.styleable#RelativeLayout_Layout_layout_alignBaseline
1173 * @attr ref android.R.styleable#RelativeLayout_Layout_layout_alignLeft
1174 * @attr ref android.R.styleable#RelativeLayout_Layout_layout_alignTop
1175 * @attr ref android.R.styleable#RelativeLayout_Layout_layout_alignRight
1176 * @attr ref android.R.styleable#RelativeLayout_Layout_layout_alignBottom
1177 * @attr ref android.R.styleable#RelativeLayout_Layout_layout_alignParentLeft
1178 * @attr ref android.R.styleable#RelativeLayout_Layout_layout_alignParentTop
1179 * @attr ref android.R.styleable#RelativeLayout_Layout_layout_alignParentRight
1180 * @attr ref android.R.styleable#RelativeLayout_Layout_layout_alignParentBottom
1181 * @attr ref android.R.styleable#RelativeLayout_Layout_layout_centerInParent
1182 * @attr ref android.R.styleable#RelativeLayout_Layout_layout_centerHorizontal
1183 * @attr ref android.R.styleable#RelativeLayout_Layout_layout_centerVertical
Fabrice Di Megliof443f982012-07-13 20:24:03 -07001184 * @attr ref android.R.styleable#RelativeLayout_Layout_layout_toStartOf
1185 * @attr ref android.R.styleable#RelativeLayout_Layout_layout_toEndOf
1186 * @attr ref android.R.styleable#RelativeLayout_Layout_layout_alignStart
1187 * @attr ref android.R.styleable#RelativeLayout_Layout_layout_alignEnd
1188 * @attr ref android.R.styleable#RelativeLayout_Layout_layout_alignParentStart
1189 * @attr ref android.R.styleable#RelativeLayout_Layout_layout_alignParentEnd
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001190 */
1191 public static class LayoutParams extends ViewGroup.MarginLayoutParams {
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07001192 @ViewDebug.ExportedProperty(category = "layout", resolveId = true, indexMapping = {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001193 @ViewDebug.IntToString(from = ABOVE, to = "above"),
1194 @ViewDebug.IntToString(from = ALIGN_BASELINE, to = "alignBaseline"),
1195 @ViewDebug.IntToString(from = ALIGN_BOTTOM, to = "alignBottom"),
1196 @ViewDebug.IntToString(from = ALIGN_LEFT, to = "alignLeft"),
1197 @ViewDebug.IntToString(from = ALIGN_PARENT_BOTTOM, to = "alignParentBottom"),
1198 @ViewDebug.IntToString(from = ALIGN_PARENT_LEFT, to = "alignParentLeft"),
1199 @ViewDebug.IntToString(from = ALIGN_PARENT_RIGHT, to = "alignParentRight"),
1200 @ViewDebug.IntToString(from = ALIGN_PARENT_TOP, to = "alignParentTop"),
1201 @ViewDebug.IntToString(from = ALIGN_RIGHT, to = "alignRight"),
1202 @ViewDebug.IntToString(from = ALIGN_TOP, to = "alignTop"),
1203 @ViewDebug.IntToString(from = BELOW, to = "below"),
1204 @ViewDebug.IntToString(from = CENTER_HORIZONTAL, to = "centerHorizontal"),
1205 @ViewDebug.IntToString(from = CENTER_IN_PARENT, to = "center"),
1206 @ViewDebug.IntToString(from = CENTER_VERTICAL, to = "centerVertical"),
1207 @ViewDebug.IntToString(from = LEFT_OF, to = "leftOf"),
Fabrice Di Megliof443f982012-07-13 20:24:03 -07001208 @ViewDebug.IntToString(from = RIGHT_OF, to = "rightOf"),
1209 @ViewDebug.IntToString(from = ALIGN_START, to = "alignStart"),
1210 @ViewDebug.IntToString(from = ALIGN_END, to = "alignEnd"),
1211 @ViewDebug.IntToString(from = ALIGN_PARENT_START, to = "alignParentStart"),
1212 @ViewDebug.IntToString(from = ALIGN_PARENT_END, to = "alignParentEnd"),
1213 @ViewDebug.IntToString(from = START_OF, to = "startOf"),
1214 @ViewDebug.IntToString(from = END_OF, to = "endOf")
The Android Open Source Project10592532009-03-18 17:39:46 -07001215 }, mapping = {
1216 @ViewDebug.IntToString(from = TRUE, to = "true"),
Romain Guya1f3e4a2009-06-04 15:10:46 -07001217 @ViewDebug.IntToString(from = 0, to = "false/NO_ID")
The Android Open Source Project10592532009-03-18 17:39:46 -07001218 })
Fabrice Di Megliof443f982012-07-13 20:24:03 -07001219
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001220 private int[] mRules = new int[VERB_COUNT];
Fabrice Di Megliof443f982012-07-13 20:24:03 -07001221 private int[] mInitialRules = new int[VERB_COUNT];
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001222
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001223 private int mLeft, mTop, mRight, mBottom;
1224
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07001225 private int mStart = DEFAULT_MARGIN_RELATIVE;
1226 private int mEnd = DEFAULT_MARGIN_RELATIVE;
Fabrice Di Megliof443f982012-07-13 20:24:03 -07001227
1228 private boolean mRulesChanged = false;
Fabrice Di Meglioc44d8802013-02-19 17:42:13 -08001229 private boolean mIsRtlCompatibilityMode = false;
Fabrice Di Megliof443f982012-07-13 20:24:03 -07001230
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001231 /**
1232 * When true, uses the parent as the anchor if the anchor doesn't exist or if
1233 * the anchor's visibility is GONE.
1234 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07001235 @ViewDebug.ExportedProperty(category = "layout")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001236 public boolean alignWithParent;
1237
1238 public LayoutParams(Context c, AttributeSet attrs) {
1239 super(c, attrs);
1240
1241 TypedArray a = c.obtainStyledAttributes(attrs,
1242 com.android.internal.R.styleable.RelativeLayout_Layout);
1243
Fabrice Di Meglioc44d8802013-02-19 17:42:13 -08001244 final int targetSdkVersion = c.getApplicationInfo().targetSdkVersion;
1245 mIsRtlCompatibilityMode = (targetSdkVersion < JELLY_BEAN_MR1 ||
1246 !c.getApplicationInfo().hasRtlSupport());
1247
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001248 final int[] rules = mRules;
Romain Guyf16c7a92013-02-11 17:43:59 -08001249 //noinspection MismatchedReadAndWriteOfArray
Fabrice Di Megliof443f982012-07-13 20:24:03 -07001250 final int[] initialRules = mInitialRules;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001251
1252 final int N = a.getIndexCount();
1253 for (int i = 0; i < N; i++) {
1254 int attr = a.getIndex(i);
1255 switch (attr) {
1256 case com.android.internal.R.styleable.RelativeLayout_Layout_layout_alignWithParentIfMissing:
1257 alignWithParent = a.getBoolean(attr, false);
1258 break;
1259 case com.android.internal.R.styleable.RelativeLayout_Layout_layout_toLeftOf:
1260 rules[LEFT_OF] = a.getResourceId(attr, 0);
1261 break;
1262 case com.android.internal.R.styleable.RelativeLayout_Layout_layout_toRightOf:
1263 rules[RIGHT_OF] = a.getResourceId(attr, 0);
1264 break;
1265 case com.android.internal.R.styleable.RelativeLayout_Layout_layout_above:
1266 rules[ABOVE] = a.getResourceId(attr, 0);
1267 break;
1268 case com.android.internal.R.styleable.RelativeLayout_Layout_layout_below:
1269 rules[BELOW] = a.getResourceId(attr, 0);
1270 break;
1271 case com.android.internal.R.styleable.RelativeLayout_Layout_layout_alignBaseline:
1272 rules[ALIGN_BASELINE] = a.getResourceId(attr, 0);
1273 break;
1274 case com.android.internal.R.styleable.RelativeLayout_Layout_layout_alignLeft:
1275 rules[ALIGN_LEFT] = a.getResourceId(attr, 0);
1276 break;
1277 case com.android.internal.R.styleable.RelativeLayout_Layout_layout_alignTop:
1278 rules[ALIGN_TOP] = a.getResourceId(attr, 0);
1279 break;
1280 case com.android.internal.R.styleable.RelativeLayout_Layout_layout_alignRight:
1281 rules[ALIGN_RIGHT] = a.getResourceId(attr, 0);
1282 break;
1283 case com.android.internal.R.styleable.RelativeLayout_Layout_layout_alignBottom:
1284 rules[ALIGN_BOTTOM] = a.getResourceId(attr, 0);
1285 break;
1286 case com.android.internal.R.styleable.RelativeLayout_Layout_layout_alignParentLeft:
1287 rules[ALIGN_PARENT_LEFT] = a.getBoolean(attr, false) ? TRUE : 0;
1288 break;
1289 case com.android.internal.R.styleable.RelativeLayout_Layout_layout_alignParentTop:
1290 rules[ALIGN_PARENT_TOP] = a.getBoolean(attr, false) ? TRUE : 0;
1291 break;
1292 case com.android.internal.R.styleable.RelativeLayout_Layout_layout_alignParentRight:
1293 rules[ALIGN_PARENT_RIGHT] = a.getBoolean(attr, false) ? TRUE : 0;
1294 break;
1295 case com.android.internal.R.styleable.RelativeLayout_Layout_layout_alignParentBottom:
1296 rules[ALIGN_PARENT_BOTTOM] = a.getBoolean(attr, false) ? TRUE : 0;
1297 break;
1298 case com.android.internal.R.styleable.RelativeLayout_Layout_layout_centerInParent:
1299 rules[CENTER_IN_PARENT] = a.getBoolean(attr, false) ? TRUE : 0;
1300 break;
1301 case com.android.internal.R.styleable.RelativeLayout_Layout_layout_centerHorizontal:
1302 rules[CENTER_HORIZONTAL] = a.getBoolean(attr, false) ? TRUE : 0;
1303 break;
1304 case com.android.internal.R.styleable.RelativeLayout_Layout_layout_centerVertical:
1305 rules[CENTER_VERTICAL] = a.getBoolean(attr, false) ? TRUE : 0;
1306 break;
Fabrice Di Megliof443f982012-07-13 20:24:03 -07001307 case com.android.internal.R.styleable.RelativeLayout_Layout_layout_toStartOf:
1308 rules[START_OF] = a.getResourceId(attr, 0);
1309 break;
1310 case com.android.internal.R.styleable.RelativeLayout_Layout_layout_toEndOf:
1311 rules[END_OF] = a.getResourceId(attr, 0);
1312 break;
1313 case com.android.internal.R.styleable.RelativeLayout_Layout_layout_alignStart:
1314 rules[ALIGN_START] = a.getResourceId(attr, 0);
1315 break;
1316 case com.android.internal.R.styleable.RelativeLayout_Layout_layout_alignEnd:
1317 rules[ALIGN_END] = a.getResourceId(attr, 0);
1318 break;
1319 case com.android.internal.R.styleable.RelativeLayout_Layout_layout_alignParentStart:
1320 rules[ALIGN_PARENT_START] = a.getBoolean(attr, false) ? TRUE : 0;
1321 break;
1322 case com.android.internal.R.styleable.RelativeLayout_Layout_layout_alignParentEnd:
1323 rules[ALIGN_PARENT_END] = a.getBoolean(attr, false) ? TRUE : 0;
1324 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001325 }
1326 }
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07001327 mRulesChanged = true;
Romain Guyf16c7a92013-02-11 17:43:59 -08001328 System.arraycopy(rules, LEFT_OF, initialRules, LEFT_OF, VERB_COUNT);
Fabrice Di Megliof443f982012-07-13 20:24:03 -07001329
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001330 a.recycle();
1331 }
1332
1333 public LayoutParams(int w, int h) {
1334 super(w, h);
1335 }
1336
1337 /**
1338 * {@inheritDoc}
1339 */
1340 public LayoutParams(ViewGroup.LayoutParams source) {
1341 super(source);
1342 }
1343
1344 /**
1345 * {@inheritDoc}
1346 */
1347 public LayoutParams(ViewGroup.MarginLayoutParams source) {
1348 super(source);
1349 }
1350
Alan Viverette0a0e1552013-08-07 13:24:09 -07001351 /**
1352 * Copy constructor. Clones the width, height, margin values, and rules
1353 * of the source.
1354 *
1355 * @param source The layout params to copy from.
1356 */
1357 public LayoutParams(LayoutParams source) {
1358 super(source);
1359
1360 this.mIsRtlCompatibilityMode = source.mIsRtlCompatibilityMode;
1361 this.mRulesChanged = source.mRulesChanged;
1362 this.alignWithParent = source.alignWithParent;
1363
1364 System.arraycopy(source.mRules, LEFT_OF, this.mRules, LEFT_OF, VERB_COUNT);
1365 System.arraycopy(
1366 source.mInitialRules, LEFT_OF, this.mInitialRules, LEFT_OF, VERB_COUNT);
1367 }
1368
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001369 @Override
1370 public String debug(String output) {
1371 return output + "ViewGroup.LayoutParams={ width=" + sizeToString(width) +
1372 ", height=" + sizeToString(height) + " }";
1373 }
1374
1375 /**
1376 * Adds a layout rule to be interpreted by the RelativeLayout. This
1377 * method should only be used for constraints that don't refer to another sibling
1378 * (e.g., CENTER_IN_PARENT) or take a boolean value ({@link RelativeLayout#TRUE}
Fabrice Di Megliof443f982012-07-13 20:24:03 -07001379 * 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 -08001380 * {@link #addRule(int, int)} instead.
1381 *
1382 * @param verb One of the verbs defined by
1383 * {@link android.widget.RelativeLayout RelativeLayout}, such as
1384 * ALIGN_WITH_PARENT_LEFT.
1385 * @see #addRule(int, int)
1386 */
1387 public void addRule(int verb) {
1388 mRules[verb] = TRUE;
Fabrice Di Megliof443f982012-07-13 20:24:03 -07001389 mInitialRules[verb] = TRUE;
1390 mRulesChanged = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001391 }
1392
1393 /**
1394 * Adds a layout rule to be interpreted by the RelativeLayout. Use this for
1395 * verbs that take a target, such as a sibling (ALIGN_RIGHT) or a boolean
1396 * value (VISIBLE).
1397 *
1398 * @param verb One of the verbs defined by
1399 * {@link android.widget.RelativeLayout RelativeLayout}, such as
1400 * ALIGN_WITH_PARENT_LEFT.
1401 * @param anchor The id of another view to use as an anchor,
1402 * or a boolean value(represented as {@link RelativeLayout#TRUE})
1403 * for true or 0 for false). For verbs that don't refer to another sibling
1404 * (for example, ALIGN_WITH_PARENT_BOTTOM) just use -1.
1405 * @see #addRule(int)
1406 */
1407 public void addRule(int verb, int anchor) {
1408 mRules[verb] = anchor;
Fabrice Di Megliof443f982012-07-13 20:24:03 -07001409 mInitialRules[verb] = anchor;
1410 mRulesChanged = true;
1411 }
1412
Fabrice Di Meglioa4c10302012-07-26 12:27:56 -07001413 /**
1414 * Removes a layout rule to be interpreted by the RelativeLayout.
1415 *
1416 * @param verb One of the verbs defined by
1417 * {@link android.widget.RelativeLayout RelativeLayout}, such as
1418 * ALIGN_WITH_PARENT_LEFT.
1419 * @see #addRule(int)
1420 * @see #addRule(int, int)
1421 */
1422 public void removeRule(int verb) {
1423 mRules[verb] = 0;
1424 mInitialRules[verb] = 0;
1425 mRulesChanged = true;
1426 }
1427
Fabrice Di Megliof443f982012-07-13 20:24:03 -07001428 private boolean hasRelativeRules() {
1429 return (mInitialRules[START_OF] != 0 || mInitialRules[END_OF] != 0 ||
1430 mInitialRules[ALIGN_START] != 0 || mInitialRules[ALIGN_END] != 0 ||
1431 mInitialRules[ALIGN_PARENT_START] != 0 || mInitialRules[ALIGN_PARENT_END] != 0);
1432 }
1433
Fabrice Di Meglioc44d8802013-02-19 17:42:13 -08001434 // The way we are resolving rules depends on the layout direction and if we are pre JB MR1
1435 // or not.
1436 //
1437 // If we are pre JB MR1 (said as "RTL compatibility mode"), "left"/"right" rules are having
1438 // predominance over any "start/end" rules that could have been defined. A special case:
1439 // if no "left"/"right" rule has been defined and "start"/"end" rules are defined then we
1440 // resolve those "start"/"end" rules to "left"/"right" respectively.
1441 //
1442 // If we are JB MR1+, then "start"/"end" rules are having predominance over "left"/"right"
1443 // rules. If no "start"/"end" rule is defined then we use "left"/"right" rules.
1444 //
1445 // In all cases, the result of the resolution should clear the "start"/"end" rules to leave
1446 // only the "left"/"right" rules at the end.
Fabrice Di Megliof443f982012-07-13 20:24:03 -07001447 private void resolveRules(int layoutDirection) {
1448 final boolean isLayoutRtl = (layoutDirection == View.LAYOUT_DIRECTION_RTL);
Fabrice Di Meglioc44d8802013-02-19 17:42:13 -08001449
Fabrice Di Megliof443f982012-07-13 20:24:03 -07001450 // Reset to initial state
Romain Guyf16c7a92013-02-11 17:43:59 -08001451 System.arraycopy(mInitialRules, LEFT_OF, mRules, LEFT_OF, VERB_COUNT);
Fabrice Di Meglioc44d8802013-02-19 17:42:13 -08001452
1453 // Apply rules depending on direction and if we are in RTL compatibility mode
1454 if (mIsRtlCompatibilityMode) {
1455 if (mRules[ALIGN_START] != 0) {
1456 if (mRules[ALIGN_LEFT] == 0) {
1457 // "left" rule is not defined but "start" rule is: use the "start" rule as
1458 // the "left" rule
1459 mRules[ALIGN_LEFT] = mRules[ALIGN_START];
1460 }
1461 mRules[ALIGN_START] = 0;
1462 }
1463
1464 if (mRules[ALIGN_END] != 0) {
1465 if (mRules[ALIGN_RIGHT] == 0) {
1466 // "right" rule is not defined but "end" rule is: use the "end" rule as the
1467 // "right" rule
1468 mRules[ALIGN_RIGHT] = mRules[ALIGN_END];
1469 }
1470 mRules[ALIGN_END] = 0;
1471 }
1472
1473 if (mRules[START_OF] != 0) {
1474 if (mRules[LEFT_OF] == 0) {
1475 // "left" rule is not defined but "start" rule is: use the "start" rule as
1476 // the "left" rule
1477 mRules[LEFT_OF] = mRules[START_OF];
1478 }
1479 mRules[START_OF] = 0;
1480 }
1481
1482 if (mRules[END_OF] != 0) {
1483 if (mRules[RIGHT_OF] == 0) {
1484 // "right" rule is not defined but "end" rule is: use the "end" rule as the
1485 // "right" rule
1486 mRules[RIGHT_OF] = mRules[END_OF];
1487 }
1488 mRules[END_OF] = 0;
1489 }
1490
1491 if (mRules[ALIGN_PARENT_START] != 0) {
1492 if (mRules[ALIGN_PARENT_LEFT] == 0) {
1493 // "left" rule is not defined but "start" rule is: use the "start" rule as
1494 // the "left" rule
1495 mRules[ALIGN_PARENT_LEFT] = mRules[ALIGN_PARENT_START];
1496 }
1497 mRules[ALIGN_PARENT_START] = 0;
1498 }
1499
1500 if (mRules[ALIGN_PARENT_RIGHT] == 0) {
1501 if (mRules[ALIGN_PARENT_RIGHT] == 0) {
1502 // "right" rule is not defined but "end" rule is: use the "end" rule as the
1503 // "right" rule
1504 mRules[ALIGN_PARENT_RIGHT] = mRules[ALIGN_PARENT_END];
1505 }
1506 mRules[ALIGN_PARENT_END] = 0;
1507 }
1508 } else {
1509 // JB MR1+ case
1510 if ((mRules[ALIGN_START] != 0 || mRules[ALIGN_END] != 0) &&
1511 (mRules[ALIGN_LEFT] != 0 || mRules[ALIGN_RIGHT] != 0)) {
1512 // "start"/"end" rules take precedence over "left"/"right" rules
1513 mRules[ALIGN_LEFT] = 0;
1514 mRules[ALIGN_RIGHT] = 0;
1515 }
1516 if (mRules[ALIGN_START] != 0) {
1517 // "start" rule resolved to "left" or "right" depending on the direction
1518 mRules[isLayoutRtl ? ALIGN_RIGHT : ALIGN_LEFT] = mRules[ALIGN_START];
1519 mRules[ALIGN_START] = 0;
1520 }
1521 if (mRules[ALIGN_END] != 0) {
1522 // "end" rule resolved to "left" or "right" depending on the direction
1523 mRules[isLayoutRtl ? ALIGN_LEFT : ALIGN_RIGHT] = mRules[ALIGN_END];
1524 mRules[ALIGN_END] = 0;
1525 }
1526
1527 if ((mRules[START_OF] != 0 || mRules[END_OF] != 0) &&
1528 (mRules[LEFT_OF] != 0 || mRules[RIGHT_OF] != 0)) {
1529 // "start"/"end" rules take precedence over "left"/"right" rules
1530 mRules[LEFT_OF] = 0;
1531 mRules[RIGHT_OF] = 0;
1532 }
1533 if (mRules[START_OF] != 0) {
1534 // "start" rule resolved to "left" or "right" depending on the direction
1535 mRules[isLayoutRtl ? RIGHT_OF : LEFT_OF] = mRules[START_OF];
1536 mRules[START_OF] = 0;
1537 }
1538 if (mRules[END_OF] != 0) {
1539 // "end" rule resolved to "left" or "right" depending on the direction
1540 mRules[isLayoutRtl ? LEFT_OF : RIGHT_OF] = mRules[END_OF];
1541 mRules[END_OF] = 0;
1542 }
1543
1544 if ((mRules[ALIGN_PARENT_START] != 0 || mRules[ALIGN_PARENT_END] != 0) &&
1545 (mRules[ALIGN_PARENT_LEFT] != 0 || mRules[ALIGN_PARENT_RIGHT] != 0)) {
1546 // "start"/"end" rules take precedence over "left"/"right" rules
1547 mRules[ALIGN_PARENT_LEFT] = 0;
1548 mRules[ALIGN_PARENT_RIGHT] = 0;
1549 }
1550 if (mRules[ALIGN_PARENT_START] != 0) {
1551 // "start" rule resolved to "left" or "right" depending on the direction
1552 mRules[isLayoutRtl ? ALIGN_PARENT_RIGHT : ALIGN_PARENT_LEFT] = mRules[ALIGN_PARENT_START];
1553 mRules[ALIGN_PARENT_START] = 0;
1554 }
1555 if (mRules[ALIGN_PARENT_END] != 0) {
1556 // "end" rule resolved to "left" or "right" depending on the direction
1557 mRules[isLayoutRtl ? ALIGN_PARENT_LEFT : ALIGN_PARENT_RIGHT] = mRules[ALIGN_PARENT_END];
1558 mRules[ALIGN_PARENT_END] = 0;
1559 }
Fabrice Di Megliof443f982012-07-13 20:24:03 -07001560 }
1561 mRulesChanged = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001562 }
1563
1564 /**
1565 * Retrieves a complete list of all supported rules, where the index is the rule
1566 * verb, and the element value is the value specified, or "false" if it was never
Fabrice Di Megliof443f982012-07-13 20:24:03 -07001567 * set. If there are relative rules defined (*_START / *_END), they will be resolved
1568 * depending on the layout direction.
1569 *
1570 * @param layoutDirection the direction of the layout.
1571 * Should be either {@link View#LAYOUT_DIRECTION_LTR}
1572 * or {@link View#LAYOUT_DIRECTION_RTL}
1573 * @return the supported rules
1574 * @see #addRule(int, int)
1575 *
1576 * @hide
1577 */
1578 public int[] getRules(int layoutDirection) {
1579 if (hasRelativeRules() &&
1580 (mRulesChanged || layoutDirection != getLayoutDirection())) {
1581 resolveRules(layoutDirection);
1582 if (layoutDirection != getLayoutDirection()) {
1583 setLayoutDirection(layoutDirection);
1584 }
1585 }
1586 return mRules;
1587 }
1588
1589 /**
1590 * Retrieves a complete list of all supported rules, where the index is the rule
1591 * verb, and the element value is the value specified, or "false" if it was never
1592 * set. There will be no resolution of relative rules done.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001593 *
1594 * @return the supported rules
1595 * @see #addRule(int, int)
1596 */
1597 public int[] getRules() {
1598 return mRules;
1599 }
Fabrice Di Megliof443f982012-07-13 20:24:03 -07001600
1601 @Override
Fabrice Di Meglio2918ab62012-10-10 16:39:25 -07001602 public void resolveLayoutDirection(int layoutDirection) {
Fabrice Di Megliof443f982012-07-13 20:24:03 -07001603 final boolean isLayoutRtl = isLayoutRtl();
1604 if (isLayoutRtl) {
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07001605 if (mStart != DEFAULT_MARGIN_RELATIVE) mRight = mStart;
1606 if (mEnd != DEFAULT_MARGIN_RELATIVE) mLeft = mEnd;
Fabrice Di Megliof443f982012-07-13 20:24:03 -07001607 } else {
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07001608 if (mStart != DEFAULT_MARGIN_RELATIVE) mLeft = mStart;
1609 if (mEnd != DEFAULT_MARGIN_RELATIVE) mRight = mEnd;
Fabrice Di Megliof443f982012-07-13 20:24:03 -07001610 }
1611
1612 if (hasRelativeRules() && layoutDirection != getLayoutDirection()) {
1613 resolveRules(layoutDirection);
1614 }
1615 // This will set the layout direction
Fabrice Di Meglio2918ab62012-10-10 16:39:25 -07001616 super.resolveLayoutDirection(layoutDirection);
Fabrice Di Megliof443f982012-07-13 20:24:03 -07001617 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001618 }
Romain Guy725015a2009-06-23 14:27:34 -07001619
1620 private static class DependencyGraph {
1621 /**
Romain Guy1ab621e2009-06-25 13:31:57 -07001622 * List of all views in the graph.
1623 */
1624 private ArrayList<Node> mNodes = new ArrayList<Node>();
1625
1626 /**
Romain Guy725015a2009-06-23 14:27:34 -07001627 * List of nodes in the graph. Each node is identified by its
1628 * view id (see View#getId()).
1629 */
Romain Guy1ab621e2009-06-25 13:31:57 -07001630 private SparseArray<Node> mKeyNodes = new SparseArray<Node>();
Romain Guy725015a2009-06-23 14:27:34 -07001631
1632 /**
1633 * Temporary data structure used to build the list of roots
1634 * for this graph.
1635 */
Romain Guybc5d8762012-01-06 16:40:49 -08001636 private ArrayDeque<Node> mRoots = new ArrayDeque<Node>();
Romain Guy725015a2009-06-23 14:27:34 -07001637
1638 /**
1639 * Clears the graph.
1640 */
1641 void clear() {
Romain Guy1ab621e2009-06-25 13:31:57 -07001642 final ArrayList<Node> nodes = mNodes;
Romain Guy725015a2009-06-23 14:27:34 -07001643 final int count = nodes.size();
1644
1645 for (int i = 0; i < count; i++) {
Romain Guy1ab621e2009-06-25 13:31:57 -07001646 nodes.get(i).release();
Romain Guy725015a2009-06-23 14:27:34 -07001647 }
1648 nodes.clear();
1649
Romain Guy1ab621e2009-06-25 13:31:57 -07001650 mKeyNodes.clear();
Romain Guy725015a2009-06-23 14:27:34 -07001651 mRoots.clear();
1652 }
1653
1654 /**
1655 * Adds a view to the graph.
1656 *
1657 * @param view The view to be added as a node to the graph.
1658 */
1659 void add(View view) {
Romain Guy1ab621e2009-06-25 13:31:57 -07001660 final int id = view.getId();
1661 final Node node = Node.acquire(view);
1662
1663 if (id != View.NO_ID) {
1664 mKeyNodes.put(id, node);
1665 }
1666
1667 mNodes.add(node);
Romain Guy725015a2009-06-23 14:27:34 -07001668 }
1669
1670 /**
1671 * Builds a sorted list of views. The sorting order depends on the dependencies
1672 * between the view. For instance, if view C needs view A to be processed first
1673 * and view A needs view B to be processed first, the dependency graph
1674 * is: B -> A -> C. The sorted array will contain views B, A and C in this order.
1675 *
1676 * @param sorted The sorted list of views. The length of this array must
1677 * be equal to getChildCount().
1678 * @param rules The list of rules to take into account.
1679 */
1680 void getSortedViews(View[] sorted, int... rules) {
Romain Guybc5d8762012-01-06 16:40:49 -08001681 final ArrayDeque<Node> roots = findRoots(rules);
Romain Guy725015a2009-06-23 14:27:34 -07001682 int index = 0;
1683
Romain Guybc5d8762012-01-06 16:40:49 -08001684 Node node;
1685 while ((node = roots.pollLast()) != null) {
Romain Guy725015a2009-06-23 14:27:34 -07001686 final View view = node.view;
1687 final int key = view.getId();
1688
1689 sorted[index++] = view;
1690
Romain Guy6876b4f2013-06-03 14:25:56 -07001691 final ArrayMap<Node, DependencyGraph> dependents = node.dependents;
1692 final int count = dependents.size();
1693 for (int i = 0; i < count; i++) {
1694 final Node dependent = dependents.keyAt(i);
Romain Guy725015a2009-06-23 14:27:34 -07001695 final SparseArray<Node> dependencies = dependent.dependencies;
1696
1697 dependencies.remove(key);
1698 if (dependencies.size() == 0) {
1699 roots.add(dependent);
1700 }
1701 }
1702 }
1703
1704 if (index < sorted.length) {
1705 throw new IllegalStateException("Circular dependencies cannot exist"
1706 + " in RelativeLayout");
1707 }
1708 }
1709
1710 /**
1711 * Finds the roots of the graph. A root is a node with no dependency and
1712 * with [0..n] dependents.
1713 *
1714 * @param rulesFilter The list of rules to consider when building the
1715 * dependencies
1716 *
1717 * @return A list of node, each being a root of the graph
1718 */
Romain Guybc5d8762012-01-06 16:40:49 -08001719 private ArrayDeque<Node> findRoots(int[] rulesFilter) {
Romain Guy1ab621e2009-06-25 13:31:57 -07001720 final SparseArray<Node> keyNodes = mKeyNodes;
1721 final ArrayList<Node> nodes = mNodes;
Romain Guy725015a2009-06-23 14:27:34 -07001722 final int count = nodes.size();
1723
1724 // Find roots can be invoked several times, so make sure to clear
1725 // all dependents and dependencies before running the algorithm
1726 for (int i = 0; i < count; i++) {
Romain Guy1ab621e2009-06-25 13:31:57 -07001727 final Node node = nodes.get(i);
Romain Guy725015a2009-06-23 14:27:34 -07001728 node.dependents.clear();
1729 node.dependencies.clear();
1730 }
1731
1732 // Builds up the dependents and dependencies for each node of the graph
1733 for (int i = 0; i < count; i++) {
Romain Guy1ab621e2009-06-25 13:31:57 -07001734 final Node node = nodes.get(i);
Romain Guy725015a2009-06-23 14:27:34 -07001735
1736 final LayoutParams layoutParams = (LayoutParams) node.view.getLayoutParams();
1737 final int[] rules = layoutParams.mRules;
1738 final int rulesCount = rulesFilter.length;
1739
1740 // Look only the the rules passed in parameter, this way we build only the
1741 // dependencies for a specific set of rules
1742 for (int j = 0; j < rulesCount; j++) {
1743 final int rule = rules[rulesFilter[j]];
1744 if (rule > 0) {
1745 // The node this node depends on
Romain Guy1ab621e2009-06-25 13:31:57 -07001746 final Node dependency = keyNodes.get(rule);
Romain Guyda3003e2009-07-19 19:47:42 -07001747 // Skip unknowns and self dependencies
1748 if (dependency == null || dependency == node) {
Romain Guyb8f8de82009-06-25 12:03:56 -07001749 continue;
1750 }
Romain Guy725015a2009-06-23 14:27:34 -07001751 // Add the current node as a dependent
Romain Guybc5d8762012-01-06 16:40:49 -08001752 dependency.dependents.put(node, this);
Romain Guy725015a2009-06-23 14:27:34 -07001753 // Add a dependency to the current node
1754 node.dependencies.put(rule, dependency);
1755 }
1756 }
1757 }
1758
Romain Guybc5d8762012-01-06 16:40:49 -08001759 final ArrayDeque<Node> roots = mRoots;
Romain Guy725015a2009-06-23 14:27:34 -07001760 roots.clear();
1761
1762 // Finds all the roots in the graph: all nodes with no dependencies
1763 for (int i = 0; i < count; i++) {
Romain Guy1ab621e2009-06-25 13:31:57 -07001764 final Node node = nodes.get(i);
Romain Guybc5d8762012-01-06 16:40:49 -08001765 if (node.dependencies.size() == 0) roots.addLast(node);
Romain Guy725015a2009-06-23 14:27:34 -07001766 }
1767
1768 return roots;
1769 }
1770
1771 /**
Romain Guy725015a2009-06-23 14:27:34 -07001772 * A node in the dependency graph. A node is a view, its list of dependencies
1773 * and its list of dependents.
1774 *
1775 * A node with no dependent is considered a root of the graph.
1776 */
Svetoslav Ganovabae2a12012-11-27 16:59:37 -08001777 static class Node {
Romain Guy725015a2009-06-23 14:27:34 -07001778 /**
1779 * The view representing this node in the layout.
1780 */
1781 View view;
1782
1783 /**
1784 * The list of dependents for this node; a dependent is a node
1785 * that needs this node to be processed first.
1786 */
Romain Guy6876b4f2013-06-03 14:25:56 -07001787 final ArrayMap<Node, DependencyGraph> dependents =
1788 new ArrayMap<Node, DependencyGraph>();
Romain Guy725015a2009-06-23 14:27:34 -07001789
1790 /**
1791 * The list of dependencies for this node.
1792 */
1793 final SparseArray<Node> dependencies = new SparseArray<Node>();
1794
1795 /*
1796 * START POOL IMPLEMENTATION
1797 */
Romain Guybaac4632009-06-29 14:28:29 -07001798 // The pool is static, so all nodes instances are shared across
1799 // activities, that's why we give it a rather high limit
1800 private static final int POOL_LIMIT = 100;
Romain Guy6876b4f2013-06-03 14:25:56 -07001801 private static final SynchronizedPool<Node> sPool =
1802 new SynchronizedPool<Node>(POOL_LIMIT);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001803
Romain Guy725015a2009-06-23 14:27:34 -07001804 static Node acquire(View view) {
Svetoslav Ganovabae2a12012-11-27 16:59:37 -08001805 Node node = sPool.acquire();
1806 if (node == null) {
1807 node = new Node();
1808 }
Romain Guy725015a2009-06-23 14:27:34 -07001809 node.view = view;
Romain Guy725015a2009-06-23 14:27:34 -07001810 return node;
1811 }
1812
1813 void release() {
1814 view = null;
1815 dependents.clear();
1816 dependencies.clear();
1817
1818 sPool.release(this);
1819 }
1820 /*
1821 * END POOL IMPLEMENTATION
1822 */
1823 }
1824 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001825}