1 /* 2 * Copyright (C) 2008 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 17 package android.widget.cts; 18 19 import org.xmlpull.v1.XmlPullParser; 20 21 import android.app.Activity; 22 import android.content.Context; 23 import android.graphics.Color; 24 import android.test.ActivityInstrumentationTestCase; 25 import android.test.ViewAsserts; 26 import android.util.AttributeSet; 27 import android.util.Xml; 28 import android.view.View; 29 import android.view.View.MeasureSpec; 30 import android.view.ViewGroup; 31 import android.view.ViewTreeObserver; 32 import android.widget.AbsoluteLayout; 33 import android.widget.LinearLayout; 34 import android.widget.LinearLayout.LayoutParams; 35 import android.widget.ListView; 36 import android.widget.TextView; 37 import android.widget.cts.R; 38 39 import java.util.concurrent.CountDownLatch; 40 import java.util.concurrent.TimeUnit; 41 42 /** 43 * Test {@link LinearLayout}. 44 */ 45 public class LinearLayoutTest extends ActivityInstrumentationTestCase<LinearLayoutCtsActivity> { 46 private Context mContext; 47 private Activity mActivity; 48 LinearLayoutTest()49 public LinearLayoutTest() { 50 super("android.widget.cts", LinearLayoutCtsActivity.class); 51 } 52 53 @Override setUp()54 protected void setUp() throws Exception { 55 super.setUp(); 56 mActivity = getActivity(); 57 mContext = getInstrumentation().getTargetContext(); 58 } 59 testConstructor()60 public void testConstructor() { 61 new LinearLayout(mContext); 62 63 new LinearLayout(mContext, null); 64 65 XmlPullParser parser = mContext.getResources().getXml(R.layout.linearlayout_layout); 66 AttributeSet attrs = Xml.asAttributeSet(parser); 67 new LinearLayout(mContext, attrs); 68 69 try { 70 new LinearLayout(null, null); 71 fail("should throw NullPointerException."); 72 } catch (NullPointerException e) { 73 } 74 } 75 testAccessBaselineAligned()76 public void testAccessBaselineAligned() { 77 LinearLayout linearLayout = new LinearLayout(mContext); 78 linearLayout.setBaselineAligned(true); 79 assertTrue(linearLayout.isBaselineAligned()); 80 81 linearLayout.setBaselineAligned(false); 82 assertFalse(linearLayout.isBaselineAligned()); 83 84 // android:baselineAligned="false" in LinearLayout weightsum 85 linearLayout = (LinearLayout) mActivity.findViewById(R.id.weightsum); 86 assertFalse(linearLayout.isBaselineAligned()); 87 88 // default mBaselineAligned is true. 89 linearLayout = (LinearLayout) mActivity.findViewById(R.id.horizontal); 90 assertTrue(linearLayout.isBaselineAligned()); 91 92 // default mBaselineAligned is true. 93 // Only applicable if {@link #mOrientation} is horizontal 94 linearLayout = (LinearLayout) mActivity.findViewById(R.id.vertical); 95 assertTrue(linearLayout.isBaselineAligned()); 96 } 97 testGetBaseline()98 public void testGetBaseline() { 99 LinearLayout linearLayout = new LinearLayout(mContext); 100 101 ListView lv1 = new ListView(mContext); 102 linearLayout.addView(lv1); 103 assertEquals(-1, linearLayout.getBaseline()); 104 105 ListView lv2 = new ListView(mContext); 106 linearLayout.addView(lv2); 107 linearLayout.setBaselineAlignedChildIndex(1); 108 try { 109 linearLayout.getBaseline(); 110 fail("LinearLayout.getBaseline() should throw exception here."); 111 } catch (RuntimeException e) { 112 } 113 114 MockListView lv3 = new MockListView(mContext); 115 linearLayout.addView(lv3); 116 linearLayout.setBaselineAlignedChildIndex(2); 117 assertEquals(lv3.getBaseline(), linearLayout.getBaseline()); 118 } 119 testAccessBaselineAlignedChildIndex()120 public void testAccessBaselineAlignedChildIndex() { 121 LinearLayout linearLayout = new LinearLayout(mContext); 122 // set BaselineAlignedChildIndex 123 ListView lv1 = new ListView(mContext); 124 ListView lv2 = new ListView(mContext); 125 ListView lv3 = new ListView(mContext); 126 linearLayout.addView(lv1); 127 linearLayout.addView(lv2); 128 linearLayout.addView(lv3); 129 linearLayout.setBaselineAlignedChildIndex(1); 130 assertEquals(1, linearLayout.getBaselineAlignedChildIndex()); 131 132 linearLayout.setBaselineAlignedChildIndex(2); 133 assertEquals(2, linearLayout.getBaselineAlignedChildIndex()); 134 135 try { 136 linearLayout.setBaselineAlignedChildIndex(-1); 137 fail("LinearLayout should throw IllegalArgumentException here."); 138 } catch (IllegalArgumentException e) { 139 } 140 try { 141 linearLayout.setBaselineAlignedChildIndex(3); 142 fail("LinearLayout should throw IllegalArgumentException here."); 143 } catch (IllegalArgumentException e) { 144 } 145 146 linearLayout = (LinearLayout) mActivity.findViewById(R.id.baseline_aligned_child_index); 147 assertEquals(1, linearLayout.getBaselineAlignedChildIndex()); 148 } 149 150 /** 151 * weightsum is a horizontal LinearLayout. There are three children in it. 152 */ testAccessWeightSum()153 public void testAccessWeightSum() { 154 LinearLayout parent = (LinearLayout) mActivity.findViewById(R.id.weightsum); 155 TextView weight02 = (TextView) mActivity.findViewById(R.id.weight_0_2); 156 TextView weight05 = (TextView) mActivity.findViewById(R.id.weight_0_5); 157 TextView weight03 = (TextView) mActivity.findViewById(R.id.weight_0_3); 158 159 assertNotNull(parent); 160 assertNotNull(weight02); 161 assertNotNull(weight05); 162 assertNotNull(weight03); 163 164 assertEquals(mContext.getResources().getString(R.string.horizontal_text_1), 165 weight02.getText().toString()); 166 assertEquals(mContext.getResources().getString(R.string.horizontal_text_2), 167 weight05.getText().toString()); 168 assertEquals(mContext.getResources().getString(R.string.horizontal_text_3), 169 weight03.getText().toString()); 170 171 assertEquals(LinearLayout.HORIZONTAL, parent.getOrientation()); 172 assertEquals(1.0f, parent.getWeightSum()); 173 174 int parentWidth = parent.getWidth(); 175 assertEquals(Math.ceil(parentWidth * 0.2), weight02.getWidth(), 1.0); 176 assertEquals(Math.ceil(parentWidth * 0.5), weight05.getWidth(), 1.0); 177 assertEquals(Math.ceil(parentWidth * 0.3), weight03.getWidth(), 1.0); 178 } 179 testWeightDistribution()180 public void testWeightDistribution() { 181 LinearLayout layout = new LinearLayout(mActivity); 182 for (int i = 0; i < 3; i++) { 183 layout.addView(new View(mActivity), new LayoutParams(0, 0, 1)); 184 } 185 186 int size = 100; 187 int spec = MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY); 188 189 for (int i = 0; i < 3; i++) { 190 View child = layout.getChildAt(i); 191 LayoutParams lp = (LayoutParams) child.getLayoutParams(); 192 lp.height = 0; 193 lp.width = LayoutParams.MATCH_PARENT; 194 child.setLayoutParams(lp); 195 } 196 layout.setOrientation(LinearLayout.VERTICAL); 197 layout.measure(spec, spec); 198 layout.layout(0, 0, size, size); 199 assertEquals(100, layout.getWidth()); 200 assertEquals(100, layout.getChildAt(0).getWidth()); 201 assertEquals(100, layout.getChildAt(1).getWidth()); 202 assertEquals(100, layout.getChildAt(2).getWidth()); 203 assertEquals(100, layout.getHeight()); 204 assertEquals(33, layout.getChildAt(0).getHeight()); 205 assertEquals(33, layout.getChildAt(1).getHeight()); 206 assertEquals(34, layout.getChildAt(2).getHeight()); 207 208 for (int i = 0; i < 3; i++) { 209 View child = layout.getChildAt(i); 210 LayoutParams lp = (LayoutParams) child.getLayoutParams(); 211 lp.height = LayoutParams.MATCH_PARENT; 212 lp.width = 0; 213 child.setLayoutParams(lp); 214 } 215 layout.setOrientation(LinearLayout.HORIZONTAL); 216 layout.measure(spec, spec); 217 layout.layout(0, 0, size, size); 218 assertEquals(100, layout.getWidth()); 219 assertEquals(33, layout.getChildAt(0).getWidth()); 220 assertEquals(33, layout.getChildAt(1).getWidth()); 221 assertEquals(34, layout.getChildAt(2).getWidth()); 222 assertEquals(100, layout.getHeight()); 223 assertEquals(100, layout.getChildAt(0).getHeight()); 224 assertEquals(100, layout.getChildAt(1).getHeight()); 225 assertEquals(100, layout.getChildAt(2).getHeight()); 226 } 227 testGenerateLayoutParams()228 public void testGenerateLayoutParams() { 229 ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(320, 240); 230 MockLinearLayout mockLinearLayout = new MockLinearLayout(mContext); 231 LayoutParams layoutParams1 = mockLinearLayout.generateLayoutParams(lp); 232 assertEquals(320, layoutParams1.width); 233 assertEquals(240, layoutParams1.height); 234 235 // generateLayoutParams() always throw a RuntimeException. 236 // XmlPullParser parser = mContext.getResources().getXml(R.layout.linearlayout_layout); 237 // AttributeSet attrs = Xml.asAttributeSet(parser); 238 // LinearLayout linearLayout = new LinearLayout(mContext, attrs); 239 // LayoutParams layoutParams2 = linearLayout.generateLayoutParams(attrs); 240 // assertEquals(LayoutParams.MATCH_PARENT, layoutParams2.width); 241 // assertEquals(LayoutParams.WRAP_CONTENT, layoutParams2.height); 242 } 243 testCheckLayoutParams()244 public void testCheckLayoutParams() { 245 MockLinearLayout mockLinearLayout = new MockLinearLayout(mContext); 246 247 ViewGroup.LayoutParams params = new AbsoluteLayout.LayoutParams(240, 320, 0, 0); 248 assertFalse(mockLinearLayout.checkLayoutParams(params)); 249 250 params = new LinearLayout.LayoutParams(240, 320); 251 assertTrue(mockLinearLayout.checkLayoutParams(params)); 252 } 253 testGenerateDefaultLayoutParams()254 public void testGenerateDefaultLayoutParams() { 255 MockLinearLayout mockLinearLayout = new MockLinearLayout(mContext); 256 257 mockLinearLayout.setOrientation(LinearLayout.HORIZONTAL); 258 ViewGroup.LayoutParams param = mockLinearLayout.generateDefaultLayoutParams(); 259 assertNotNull(param); 260 assertTrue(param instanceof LinearLayout.LayoutParams); 261 assertEquals(ViewGroup.LayoutParams.WRAP_CONTENT, param.width); 262 assertEquals(ViewGroup.LayoutParams.WRAP_CONTENT, param.height); 263 264 mockLinearLayout.setOrientation(LinearLayout.VERTICAL); 265 param = mockLinearLayout.generateDefaultLayoutParams(); 266 assertNotNull(param); 267 assertTrue(param instanceof LinearLayout.LayoutParams); 268 assertEquals(ViewGroup.LayoutParams.MATCH_PARENT, param.width); 269 assertEquals(ViewGroup.LayoutParams.WRAP_CONTENT, param.height); 270 271 mockLinearLayout.setOrientation(-1); 272 assertNull(mockLinearLayout.generateDefaultLayoutParams()); 273 } 274 testGenerateLayoutParamsFromMarginParams()275 public void testGenerateLayoutParamsFromMarginParams() { 276 MockLinearLayout layout = new MockLinearLayout(mContext); 277 ViewGroup.MarginLayoutParams lp = new ViewGroup.MarginLayoutParams(3, 5); 278 lp.leftMargin = 1; 279 lp.topMargin = 2; 280 lp.rightMargin = 3; 281 lp.bottomMargin = 4; 282 LinearLayout.LayoutParams generated = layout.generateLayoutParams(lp); 283 assertNotNull(generated); 284 assertEquals(3, generated.width); 285 assertEquals(5, generated.height); 286 287 assertEquals(1, generated.leftMargin); 288 assertEquals(2, generated.topMargin); 289 assertEquals(3, generated.rightMargin); 290 assertEquals(4, generated.bottomMargin); 291 } 292 293 /** 294 * layout of horizontal LinearLayout. 295 * ---------------------------------------------------- 296 * | ------------ | | | 297 * | | top view | | --------------- | | 298 * | | | | | center view | | --------------- | 299 * | ------------ | | | | | bottom view | | 300 * | | --------------- | | | | 301 * | parent | | --------------- | 302 * ---------------------------------------------------- 303 */ testLayoutHorizontal()304 public void testLayoutHorizontal() { 305 LinearLayout parent = (LinearLayout) mActivity.findViewById(R.id.horizontal); 306 TextView topView = (TextView) mActivity.findViewById(R.id.gravity_top); 307 TextView centerView = (TextView) mActivity.findViewById(R.id.gravity_center_vertical); 308 TextView bottomView = (TextView) mActivity.findViewById(R.id.gravity_bottom); 309 310 assertNotNull(parent); 311 assertNotNull(topView); 312 assertNotNull(centerView); 313 assertNotNull(bottomView); 314 315 assertEquals(mContext.getResources().getString(R.string.horizontal_text_1), 316 topView.getText().toString()); 317 assertEquals(mContext.getResources().getString(R.string.horizontal_text_2), 318 centerView.getText().toString()); 319 assertEquals(mContext.getResources().getString(R.string.horizontal_text_3), 320 bottomView.getText().toString()); 321 322 assertEquals(LinearLayout.HORIZONTAL, parent.getOrientation()); 323 324 ViewAsserts.assertTopAligned(parent, topView); 325 ViewAsserts.assertVerticalCenterAligned(parent, centerView); 326 ViewAsserts.assertBottomAligned(parent, bottomView); 327 328 assertEquals(0, topView.getTop()); 329 assertEquals(topView.getHeight(), topView.getBottom()); 330 assertEquals(0, topView.getLeft()); 331 assertEquals(centerView.getLeft(), topView.getRight()); 332 333 int offset = (parent.getHeight() - centerView.getHeight()) / 2; 334 assertEquals(offset, centerView.getTop()); 335 assertEquals(offset + centerView.getHeight(), centerView.getBottom()); 336 assertEquals(topView.getRight(), centerView.getLeft()); 337 assertEquals(bottomView.getLeft(), centerView.getRight()); 338 339 assertEquals(parent.getHeight() - bottomView.getHeight(), bottomView.getTop()); 340 assertEquals(parent.getHeight(), bottomView.getBottom()); 341 assertEquals(centerView.getRight(), bottomView.getLeft()); 342 assertEquals(parent.getWidth(), bottomView.getRight()); 343 } 344 345 /** 346 * layout of vertical LinearLayout. 347 * ----------------------------------- 348 * | ------------- | 349 * | | left view | | 350 * | ------------- | 351 * | - - - - - - - - - - - - - - - - | 352 * | --------------- | 353 * | | center view | | 354 * | --------------- | 355 * | - - - - - - - - - - - - - - - - | 356 * | -------------- | 357 * | parent | right view | | 358 * | -------------- | 359 * ----------------------------------- 360 */ testLayoutVertical()361 public void testLayoutVertical() { 362 LinearLayout parent = (LinearLayout) mActivity.findViewById(R.id.vertical); 363 TextView leftView = (TextView) mActivity.findViewById(R.id.gravity_left); 364 TextView centerView = (TextView) mActivity.findViewById(R.id.gravity_center_horizontal); 365 TextView rightView = (TextView) mActivity.findViewById(R.id.gravity_right); 366 367 assertNotNull(parent); 368 assertNotNull(leftView); 369 assertNotNull(centerView); 370 assertNotNull(rightView); 371 372 assertEquals(mContext.getResources().getString(R.string.vertical_text_1), 373 leftView.getText().toString()); 374 assertEquals(mContext.getResources().getString(R.string.vertical_text_2), 375 centerView.getText().toString()); 376 assertEquals(mContext.getResources().getString(R.string.vertical_text_3), 377 rightView.getText().toString()); 378 379 assertEquals(LinearLayout.VERTICAL, parent.getOrientation()); 380 381 ViewAsserts.assertLeftAligned(parent, leftView); 382 ViewAsserts.assertHorizontalCenterAligned(parent, centerView); 383 ViewAsserts.assertRightAligned(parent, rightView); 384 385 assertEquals(0, leftView.getTop()); 386 assertEquals(centerView.getTop(), leftView.getBottom()); 387 assertEquals(0, leftView.getLeft()); 388 assertEquals(leftView.getWidth(), leftView.getRight()); 389 390 int offset = (parent.getWidth() - centerView.getWidth()) / 2; 391 assertEquals(leftView.getBottom(), centerView.getTop()); 392 assertEquals(rightView.getTop(), centerView.getBottom()); 393 assertEquals(offset, centerView.getLeft()); 394 assertEquals(offset + centerView.getWidth(), centerView.getRight()); 395 396 assertEquals(centerView.getBottom(), rightView.getTop()); 397 assertEquals(parent.getHeight(), rightView.getBottom()); 398 assertEquals(parent.getWidth() - rightView.getWidth(), rightView.getLeft()); 399 assertEquals(parent.getWidth(), rightView.getRight()); 400 } 401 checkBounds(final ViewGroup viewGroup, final View view, final CountDownLatch countDownLatch, final int left, final int top, final int width, final int height)402 private void checkBounds(final ViewGroup viewGroup, final View view, 403 final CountDownLatch countDownLatch, final int left, final int top, 404 final int width, final int height) { 405 viewGroup.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { 406 @Override 407 public boolean onPreDraw() { 408 assertEquals(left, view.getLeft()); 409 assertEquals(top, view.getTop()); 410 assertEquals(width, view.getWidth()); 411 assertEquals(height, view.getHeight()); 412 countDownLatch.countDown(); 413 viewGroup.getViewTreeObserver().removeOnPreDrawListener(this); 414 return true; 415 } 416 }); 417 } 418 testVisibilityAffectsLayout()419 public void testVisibilityAffectsLayout() throws Throwable { 420 // Toggling view visibility between GONE/VISIBLE can affect the position of 421 // other children in that container. This test verifies that these changes 422 // on the first child of a LinearLayout affects the position of a second child 423 final int childWidth = 100; 424 final int childHeight = 200; 425 final LinearLayout parent = new LinearLayout(mActivity); 426 ViewGroup.LayoutParams parentParams = new ViewGroup.LayoutParams( 427 ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); 428 parent.setLayoutParams(parentParams); 429 final View child1 = new View(mActivity); 430 child1.setBackgroundColor(Color.GREEN); 431 ViewGroup.LayoutParams childParams = new ViewGroup.LayoutParams(childWidth, childHeight); 432 child1.setLayoutParams(childParams); 433 final View child2 = new View(mActivity); 434 child2.setBackgroundColor(Color.RED); 435 childParams = new ViewGroup.LayoutParams(childWidth, childHeight); 436 child2.setLayoutParams(childParams); 437 final ViewGroup viewGroup = (ViewGroup) mActivity.findViewById(R.id.linearlayout_root); 438 439 final CountDownLatch countDownLatch1 = new CountDownLatch(1); 440 runTestOnUiThread(new Runnable() { 441 public void run() { 442 viewGroup.removeAllViews(); 443 viewGroup.addView(parent); 444 parent.addView(child1); 445 parent.addView(child2); 446 checkBounds(viewGroup, child1, countDownLatch1, 0, 0, childWidth, childHeight); 447 checkBounds(viewGroup, child2, countDownLatch1, 448 childWidth, 0, childWidth, childHeight); 449 } 450 }); 451 countDownLatch1.await(500, TimeUnit.MILLISECONDS); 452 453 final CountDownLatch countDownLatch2 = new CountDownLatch(1); 454 runTestOnUiThread(new Runnable() { 455 public void run() { 456 child1.setVisibility(View.GONE); 457 checkBounds(viewGroup, child2, countDownLatch2, 0, 0, childWidth, childHeight); 458 } 459 }); 460 countDownLatch2.await(500, TimeUnit.MILLISECONDS); 461 462 final CountDownLatch countDownLatch3 = new CountDownLatch(2); 463 runTestOnUiThread(new Runnable() { 464 public void run() { 465 child1.setVisibility(View.VISIBLE); 466 checkBounds(viewGroup, child1, countDownLatch3, 0, 0, childWidth, childHeight); 467 checkBounds(viewGroup, child2, countDownLatch3, 468 childWidth, 0, childWidth, childHeight); 469 } 470 }); 471 countDownLatch3.await(500, TimeUnit.MILLISECONDS); 472 } 473 474 private class MockListView extends ListView { 475 private final static int DEFAULT_CHILD_BASE_LINE = 1; 476 MockListView(Context context)477 public MockListView(Context context) { 478 super(context); 479 } 480 getBaseline()481 public int getBaseline() { 482 return DEFAULT_CHILD_BASE_LINE; 483 } 484 } 485 486 /** 487 * Add MockLinearLayout to help for testing protected methods in LinearLayout. 488 * Because we can not access protected methods in LinearLayout directly, we have to 489 * extends from it and override protected methods so that we can access them in 490 * our test codes. 491 */ 492 private class MockLinearLayout extends LinearLayout { MockLinearLayout(Context c)493 public MockLinearLayout(Context c) { 494 super(c); 495 } 496 497 @Override checkLayoutParams(ViewGroup.LayoutParams p)498 protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { 499 return super.checkLayoutParams(p); 500 } 501 502 @Override generateDefaultLayoutParams()503 protected LinearLayout.LayoutParams generateDefaultLayoutParams() { 504 return super.generateDefaultLayoutParams(); 505 } 506 507 @Override generateLayoutParams(ViewGroup.LayoutParams p)508 protected LinearLayout.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { 509 return super.generateLayoutParams(p); 510 } 511 } 512 } 513