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 static org.junit.Assert.assertEquals; 20 import static org.junit.Assert.assertFalse; 21 import static org.junit.Assert.assertNotNull; 22 import static org.junit.Assert.assertNull; 23 import static org.junit.Assert.assertTrue; 24 import static org.junit.Assert.fail; 25 26 import android.app.Activity; 27 import android.app.Instrumentation; 28 import android.content.Context; 29 import android.content.res.Resources; 30 import android.graphics.Color; 31 import android.graphics.Rect; 32 import android.graphics.drawable.Drawable; 33 import android.test.ViewAsserts; 34 import android.util.AttributeSet; 35 import android.util.Xml; 36 import android.view.Gravity; 37 import android.view.View; 38 import android.view.View.MeasureSpec; 39 import android.view.ViewGroup; 40 import android.view.ViewTreeObserver; 41 import android.widget.AbsoluteLayout; 42 import android.widget.LinearLayout; 43 import android.widget.LinearLayout.LayoutParams; 44 import android.widget.ListView; 45 import android.widget.TextView; 46 import android.widget.cts.util.TestUtils; 47 48 import androidx.annotation.ColorInt; 49 import androidx.annotation.Nullable; 50 import androidx.test.InstrumentationRegistry; 51 import androidx.test.annotation.UiThreadTest; 52 import androidx.test.filters.MediumTest; 53 import androidx.test.rule.ActivityTestRule; 54 import androidx.test.runner.AndroidJUnit4; 55 56 import com.android.compatibility.common.util.WidgetTestUtils; 57 58 import org.junit.Before; 59 import org.junit.Rule; 60 import org.junit.Test; 61 import org.junit.runner.RunWith; 62 import org.xmlpull.v1.XmlPullParser; 63 64 import java.util.concurrent.CountDownLatch; 65 import java.util.concurrent.TimeUnit; 66 67 /** 68 * Test {@link LinearLayout}. 69 */ 70 @MediumTest 71 @RunWith(AndroidJUnit4.class) 72 public class LinearLayoutTest { 73 private Instrumentation mInstrumentation; 74 private Activity mActivity; 75 76 @Rule 77 public ActivityTestRule<LinearLayoutCtsActivity> mActivityRule = 78 new ActivityTestRule<>(LinearLayoutCtsActivity.class); 79 80 @Before setup()81 public void setup() { 82 mInstrumentation = InstrumentationRegistry.getInstrumentation(); 83 mActivity = mActivityRule.getActivity(); 84 } 85 86 @Test testConstructor()87 public void testConstructor() { 88 new LinearLayout(mActivity); 89 90 new LinearLayout(mActivity, null); 91 92 XmlPullParser parser = mActivity.getResources().getXml(R.layout.linearlayout_layout); 93 AttributeSet attrs = Xml.asAttributeSet(parser); 94 new LinearLayout(mActivity, attrs); 95 } 96 97 @Test(expected=NullPointerException.class) testConstructorNullContext()98 public void testConstructorNullContext() { 99 new LinearLayout(null, null); 100 } 101 102 @UiThreadTest 103 @Test testAccessBaselineAligned()104 public void testAccessBaselineAligned() { 105 LinearLayout parent = (LinearLayout) mActivity.findViewById(R.id.linear_empty); 106 parent.setBaselineAligned(true); 107 assertTrue(parent.isBaselineAligned()); 108 109 parent.setBaselineAligned(false); 110 assertFalse(parent.isBaselineAligned()); 111 112 // android:baselineAligned="false" in LinearLayout weightsum 113 parent = (LinearLayout) mActivity.findViewById(R.id.linear_weightsum); 114 assertFalse(parent.isBaselineAligned()); 115 116 // default mBaselineAligned is true. 117 parent = (LinearLayout) mActivity.findViewById(R.id.linear_horizontal); 118 assertTrue(parent.isBaselineAligned()); 119 120 // default mBaselineAligned is true. 121 // Only applicable if {@link #mOrientation} is horizontal 122 parent = (LinearLayout) mActivity.findViewById(R.id.linear_vertical); 123 assertTrue(parent.isBaselineAligned()); 124 } 125 126 @UiThreadTest 127 @Test testGetBaseline()128 public void testGetBaseline() { 129 LinearLayout parent = (LinearLayout) mActivity.findViewById(R.id.linear_empty); 130 131 ListView lv1 = new ListView(mActivity); 132 parent.addView(lv1); 133 assertEquals(-1, parent.getBaseline()); 134 135 ListView lv2 = new ListView(mActivity); 136 parent.addView(lv2); 137 parent.setBaselineAlignedChildIndex(1); 138 try { 139 parent.getBaseline(); 140 fail("LinearLayout.getBaseline() should throw exception here."); 141 } catch (RuntimeException e) { 142 } 143 144 ListView lv3 = new MockListView(mActivity); 145 parent.addView(lv3); 146 parent.setBaselineAlignedChildIndex(2); 147 assertEquals(lv3.getBaseline(), parent.getBaseline()); 148 } 149 150 @UiThreadTest 151 @Test testAccessBaselineAlignedChildIndex()152 public void testAccessBaselineAlignedChildIndex() { 153 LinearLayout parent = (LinearLayout) mActivity.findViewById(R.id.linear_empty); 154 155 // set BaselineAlignedChildIndex 156 ListView lv1 = new ListView(mActivity); 157 ListView lv2 = new ListView(mActivity); 158 ListView lv3 = new ListView(mActivity); 159 parent.addView(lv1); 160 parent.addView(lv2); 161 parent.addView(lv3); 162 parent.setBaselineAlignedChildIndex(1); 163 assertEquals(1, parent.getBaselineAlignedChildIndex()); 164 165 parent.setBaselineAlignedChildIndex(2); 166 assertEquals(2, parent.getBaselineAlignedChildIndex()); 167 168 try { 169 parent.setBaselineAlignedChildIndex(-1); 170 fail("LinearLayout should throw IllegalArgumentException here."); 171 } catch (IllegalArgumentException e) { 172 } 173 try { 174 parent.setBaselineAlignedChildIndex(3); 175 fail("LinearLayout should throw IllegalArgumentException here."); 176 } catch (IllegalArgumentException e) { 177 } 178 179 parent = (LinearLayout) mActivity.findViewById(R.id.linear_baseline_aligned_child_index); 180 assertEquals(1, parent.getBaselineAlignedChildIndex()); 181 } 182 183 /** 184 * weightsum is a horizontal LinearLayout. There are three children in it. 185 */ 186 @Test testAccessWeightSum()187 public void testAccessWeightSum() { 188 LinearLayout parent = (LinearLayout) mActivity.findViewById(R.id.linear_weightsum); 189 TextView weight02 = (TextView) parent.findViewById(R.id.weight_0_2); 190 TextView weight05 = (TextView) parent.findViewById(R.id.weight_0_5); 191 TextView weight03 = (TextView) parent.findViewById(R.id.weight_0_3); 192 193 assertNotNull(parent); 194 assertNotNull(weight02); 195 assertNotNull(weight05); 196 assertNotNull(weight03); 197 198 assertEquals(mActivity.getResources().getString(R.string.horizontal_text_1), 199 weight02.getText().toString()); 200 assertEquals(mActivity.getResources().getString(R.string.horizontal_text_2), 201 weight05.getText().toString()); 202 assertEquals(mActivity.getResources().getString(R.string.horizontal_text_3), 203 weight03.getText().toString()); 204 205 assertEquals(LinearLayout.HORIZONTAL, parent.getOrientation()); 206 assertEquals(1.0f, parent.getWeightSum(), 0.0f); 207 208 int parentWidth = parent.getWidth(); 209 assertEquals(Math.ceil(parentWidth * 0.2), weight02.getWidth(), 1.0); 210 assertEquals(Math.ceil(parentWidth * 0.5), weight05.getWidth(), 1.0); 211 assertEquals(Math.ceil(parentWidth * 0.3), weight03.getWidth(), 1.0); 212 } 213 214 @UiThreadTest 215 @Test testWeightDistribution()216 public void testWeightDistribution() { 217 LinearLayout parent = (LinearLayout) mActivity.findViewById(R.id.linear_empty); 218 219 for (int i = 0; i < 3; i++) { 220 parent.addView(new View(mActivity), new LayoutParams(0, 0, 1)); 221 } 222 223 int size = 100; 224 int spec = MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY); 225 226 for (int i = 0; i < 3; i++) { 227 View child = parent.getChildAt(i); 228 LayoutParams lp = (LayoutParams) child.getLayoutParams(); 229 lp.height = 0; 230 lp.width = LayoutParams.MATCH_PARENT; 231 child.setLayoutParams(lp); 232 } 233 parent.setOrientation(LinearLayout.VERTICAL); 234 parent.measure(spec, spec); 235 parent.layout(0, 0, size, size); 236 assertEquals(100, parent.getWidth()); 237 assertEquals(100, parent.getChildAt(0).getWidth()); 238 assertEquals(100, parent.getChildAt(1).getWidth()); 239 assertEquals(100, parent.getChildAt(2).getWidth()); 240 assertEquals(100, parent.getHeight()); 241 assertEquals(33, parent.getChildAt(0).getHeight()); 242 assertEquals(33, parent.getChildAt(1).getHeight()); 243 assertEquals(34, parent.getChildAt(2).getHeight()); 244 245 for (int i = 0; i < 3; i++) { 246 View child = parent.getChildAt(i); 247 LayoutParams lp = (LayoutParams) child.getLayoutParams(); 248 lp.height = LayoutParams.MATCH_PARENT; 249 lp.width = 0; 250 child.setLayoutParams(lp); 251 } 252 parent.setOrientation(LinearLayout.HORIZONTAL); 253 parent.measure(spec, spec); 254 parent.layout(0, 0, size, size); 255 assertEquals(100, parent.getWidth()); 256 assertEquals(33, parent.getChildAt(0).getWidth()); 257 assertEquals(33, parent.getChildAt(1).getWidth()); 258 assertEquals(34, parent.getChildAt(2).getWidth()); 259 assertEquals(100, parent.getHeight()); 260 assertEquals(100, parent.getChildAt(0).getHeight()); 261 assertEquals(100, parent.getChildAt(1).getHeight()); 262 assertEquals(100, parent.getChildAt(2).getHeight()); 263 } 264 265 @UiThreadTest 266 @Test testGenerateLayoutParams()267 public void testGenerateLayoutParams() { 268 ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(320, 240); 269 MockLinearLayout parent = (MockLinearLayout) mActivity.findViewById(R.id.linear_custom); 270 LayoutParams layoutParams1 = parent.generateLayoutParams(lp); 271 assertEquals(320, layoutParams1.width); 272 assertEquals(240, layoutParams1.height); 273 } 274 275 @UiThreadTest 276 @Test testCheckLayoutParams()277 public void testCheckLayoutParams() { 278 MockLinearLayout parent = (MockLinearLayout) mActivity.findViewById(R.id.linear_custom); 279 280 ViewGroup.LayoutParams params = new AbsoluteLayout.LayoutParams(240, 320, 0, 0); 281 assertFalse(parent.checkLayoutParams(params)); 282 283 params = new LinearLayout.LayoutParams(240, 320); 284 assertTrue(parent.checkLayoutParams(params)); 285 } 286 287 @UiThreadTest 288 @Test testGenerateDefaultLayoutParams()289 public void testGenerateDefaultLayoutParams() { 290 MockLinearLayout parent = (MockLinearLayout) mActivity.findViewById(R.id.linear_custom); 291 292 parent.setOrientation(LinearLayout.HORIZONTAL); 293 ViewGroup.LayoutParams param = parent.generateDefaultLayoutParams(); 294 assertNotNull(param); 295 assertTrue(param instanceof LinearLayout.LayoutParams); 296 assertEquals(ViewGroup.LayoutParams.WRAP_CONTENT, param.width); 297 assertEquals(ViewGroup.LayoutParams.WRAP_CONTENT, param.height); 298 299 parent.setOrientation(LinearLayout.VERTICAL); 300 param = parent.generateDefaultLayoutParams(); 301 assertNotNull(param); 302 assertTrue(param instanceof LinearLayout.LayoutParams); 303 assertEquals(ViewGroup.LayoutParams.MATCH_PARENT, param.width); 304 assertEquals(ViewGroup.LayoutParams.WRAP_CONTENT, param.height); 305 306 parent.setOrientation(-1); 307 assertNull(parent.generateDefaultLayoutParams()); 308 } 309 310 @UiThreadTest 311 @Test testGenerateLayoutParamsFromMarginParams()312 public void testGenerateLayoutParamsFromMarginParams() { 313 MockLinearLayout parent = (MockLinearLayout) mActivity.findViewById(R.id.linear_custom); 314 315 ViewGroup.MarginLayoutParams lp = new ViewGroup.MarginLayoutParams(3, 5); 316 lp.leftMargin = 1; 317 lp.topMargin = 2; 318 lp.rightMargin = 3; 319 lp.bottomMargin = 4; 320 LinearLayout.LayoutParams generated = parent.generateLayoutParams(lp); 321 assertNotNull(generated); 322 assertEquals(3, generated.width); 323 assertEquals(5, generated.height); 324 325 assertEquals(1, generated.leftMargin); 326 assertEquals(2, generated.topMargin); 327 assertEquals(3, generated.rightMargin); 328 assertEquals(4, generated.bottomMargin); 329 } 330 331 /** 332 * layout of horizontal LinearLayout. 333 * ---------------------------------------------------- 334 * | ------------ | | | 335 * | | top view | | --------------- | | 336 * | | | | | center view | | --------------- | 337 * | ------------ | | | | | bottom view | | 338 * | | --------------- | | | | 339 * | parent | | --------------- | 340 * ---------------------------------------------------- 341 */ 342 @Test testLayoutHorizontal()343 public void testLayoutHorizontal() { 344 LinearLayout parent = (LinearLayout) mActivity.findViewById(R.id.linear_horizontal); 345 TextView topView = (TextView) mActivity.findViewById(R.id.gravity_top); 346 TextView centerView = (TextView) mActivity.findViewById(R.id.gravity_center_vertical); 347 TextView bottomView = (TextView) mActivity.findViewById(R.id.gravity_bottom); 348 349 assertNotNull(parent); 350 assertNotNull(topView); 351 assertNotNull(centerView); 352 assertNotNull(bottomView); 353 354 assertEquals(mActivity.getResources().getString(R.string.horizontal_text_1), 355 topView.getText().toString()); 356 assertEquals(mActivity.getResources().getString(R.string.horizontal_text_2), 357 centerView.getText().toString()); 358 assertEquals(mActivity.getResources().getString(R.string.horizontal_text_3), 359 bottomView.getText().toString()); 360 361 assertEquals(LinearLayout.HORIZONTAL, parent.getOrientation()); 362 363 ViewAsserts.assertTopAligned(parent, topView); 364 ViewAsserts.assertVerticalCenterAligned(parent, centerView); 365 ViewAsserts.assertBottomAligned(parent, bottomView); 366 367 assertEquals(0, topView.getTop()); 368 assertEquals(topView.getHeight(), topView.getBottom()); 369 assertEquals(0, topView.getLeft()); 370 assertEquals(centerView.getLeft(), topView.getRight()); 371 372 int offset = (parent.getHeight() - centerView.getHeight()) / 2; 373 assertEquals(offset, centerView.getTop()); 374 assertEquals(offset + centerView.getHeight(), centerView.getBottom()); 375 assertEquals(topView.getRight(), centerView.getLeft()); 376 assertEquals(bottomView.getLeft(), centerView.getRight()); 377 378 assertEquals(parent.getHeight() - bottomView.getHeight(), bottomView.getTop()); 379 assertEquals(parent.getHeight(), bottomView.getBottom()); 380 assertEquals(centerView.getRight(), bottomView.getLeft()); 381 assertEquals(parent.getWidth(), bottomView.getRight()); 382 } 383 384 /** 385 * layout of vertical LinearLayout. 386 * ----------------------------------- 387 * | ------------- | 388 * | | left view | | 389 * | ------------- | 390 * | - - - - - - - - - - - - - - - - | 391 * | --------------- | 392 * | | center view | | 393 * | --------------- | 394 * | - - - - - - - - - - - - - - - - | 395 * | -------------- | 396 * | parent | right view | | 397 * | -------------- | 398 * ----------------------------------- 399 */ 400 @Test testLayoutVertical()401 public void testLayoutVertical() { 402 LinearLayout parent = (LinearLayout) mActivity.findViewById(R.id.linear_vertical); 403 TextView leftView = (TextView) mActivity.findViewById(R.id.gravity_left); 404 TextView centerView = (TextView) mActivity.findViewById(R.id.gravity_center_horizontal); 405 TextView rightView = (TextView) mActivity.findViewById(R.id.gravity_right); 406 407 assertNotNull(parent); 408 assertNotNull(leftView); 409 assertNotNull(centerView); 410 assertNotNull(rightView); 411 412 assertEquals(mActivity.getResources().getString(R.string.vertical_text_1), 413 leftView.getText().toString()); 414 assertEquals(mActivity.getResources().getString(R.string.vertical_text_2), 415 centerView.getText().toString()); 416 assertEquals(mActivity.getResources().getString(R.string.vertical_text_3), 417 rightView.getText().toString()); 418 419 assertEquals(LinearLayout.VERTICAL, parent.getOrientation()); 420 421 ViewAsserts.assertLeftAligned(parent, leftView); 422 ViewAsserts.assertHorizontalCenterAligned(parent, centerView); 423 ViewAsserts.assertRightAligned(parent, rightView); 424 425 assertEquals(0, leftView.getTop()); 426 assertEquals(centerView.getTop(), leftView.getBottom()); 427 assertEquals(0, leftView.getLeft()); 428 assertEquals(leftView.getWidth(), leftView.getRight()); 429 430 int offset = (parent.getWidth() - centerView.getWidth()) / 2; 431 assertEquals(leftView.getBottom(), centerView.getTop()); 432 assertEquals(rightView.getTop(), centerView.getBottom()); 433 assertEquals(offset, centerView.getLeft()); 434 assertEquals(offset + centerView.getWidth(), centerView.getRight()); 435 436 assertEquals(centerView.getBottom(), rightView.getTop()); 437 assertEquals(parent.getHeight(), rightView.getBottom()); 438 assertEquals(parent.getWidth() - rightView.getWidth(), rightView.getLeft()); 439 assertEquals(parent.getWidth(), rightView.getRight()); 440 } 441 442 @Test testVerticalCenterGravityOnHorizontalLayout()443 public void testVerticalCenterGravityOnHorizontalLayout() throws Throwable { 444 LinearLayout parent = (LinearLayout) mActivity.findViewById(R.id.linear_weightsum); 445 TextView leftView = (TextView) parent.findViewById(R.id.weight_0_2); 446 TextView centerView = (TextView) parent.findViewById(R.id.weight_0_5); 447 TextView rightView = (TextView) parent.findViewById(R.id.weight_0_3); 448 449 WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent, 450 () -> parent.setLayoutDirection(View.LAYOUT_DIRECTION_LTR)); 451 452 int originalLeftViewLeft = leftView.getLeft(); 453 int originalLeftViewRight = leftView.getRight(); 454 int originalCenterViewLeft = centerView.getLeft(); 455 int originalCenterViewRight = centerView.getRight(); 456 int originalRightViewLeft = rightView.getLeft(); 457 int originalRightViewRight = rightView.getRight(); 458 459 WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent, 460 () -> parent.setVerticalGravity(Gravity.CENTER_VERTICAL)); 461 462 assertEquals(Gravity.CENTER_VERTICAL, parent.getGravity() & Gravity.VERTICAL_GRAVITY_MASK); 463 464 ViewAsserts.assertVerticalCenterAligned(parent, leftView); 465 ViewAsserts.assertVerticalCenterAligned(parent, centerView); 466 ViewAsserts.assertVerticalCenterAligned(parent, rightView); 467 468 final int parentHeight = parent.getHeight(); 469 470 int verticalOffset = (parentHeight - leftView.getHeight()) / 2; 471 assertEquals(verticalOffset, leftView.getTop()); 472 assertEquals(verticalOffset + leftView.getHeight(), leftView.getBottom()); 473 assertEquals(originalLeftViewLeft, leftView.getLeft()); 474 assertEquals(originalLeftViewRight, leftView.getRight()); 475 476 verticalOffset = (parentHeight - centerView.getHeight()) / 2; 477 assertEquals(verticalOffset, centerView.getTop()); 478 assertEquals(verticalOffset + centerView.getHeight(), centerView.getBottom()); 479 assertEquals(originalCenterViewLeft, centerView.getLeft()); 480 assertEquals(originalCenterViewRight, centerView.getRight()); 481 482 verticalOffset = (parentHeight - rightView.getHeight()) / 2; 483 assertEquals(verticalOffset, rightView.getTop()); 484 assertEquals(verticalOffset + rightView.getHeight(), rightView.getBottom()); 485 assertEquals(originalRightViewLeft, rightView.getLeft()); 486 assertEquals(originalRightViewRight, rightView.getRight()); 487 } 488 489 @Test testBottomGravityOnHorizontalLayout()490 public void testBottomGravityOnHorizontalLayout() throws Throwable { 491 LinearLayout parent = (LinearLayout) mActivity.findViewById(R.id.linear_weightsum); 492 TextView leftView = (TextView) parent.findViewById(R.id.weight_0_2); 493 TextView centerView = (TextView) parent.findViewById(R.id.weight_0_5); 494 TextView rightView = (TextView) parent.findViewById(R.id.weight_0_3); 495 496 WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent, 497 () -> parent.setLayoutDirection(View.LAYOUT_DIRECTION_LTR)); 498 499 int originalLeftViewLeft = leftView.getLeft(); 500 int originalLeftViewRight = leftView.getRight(); 501 int originalCenterViewLeft = centerView.getLeft(); 502 int originalCenterViewRight = centerView.getRight(); 503 int originalRightViewLeft = rightView.getLeft(); 504 int originalRightViewRight = rightView.getRight(); 505 506 WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent, 507 () -> parent.setVerticalGravity(Gravity.BOTTOM)); 508 509 assertEquals(Gravity.BOTTOM, parent.getGravity() & Gravity.VERTICAL_GRAVITY_MASK); 510 511 ViewAsserts.assertBottomAligned(parent, leftView); 512 ViewAsserts.assertBottomAligned(parent, centerView); 513 ViewAsserts.assertBottomAligned(parent, rightView); 514 515 final int parentHeight = parent.getHeight(); 516 517 assertEquals(parentHeight - leftView.getHeight(), leftView.getTop()); 518 assertEquals(parentHeight, leftView.getBottom()); 519 assertEquals(originalLeftViewLeft, leftView.getLeft()); 520 assertEquals(originalLeftViewRight, leftView.getRight()); 521 522 assertEquals(parentHeight - centerView.getHeight(), centerView.getTop()); 523 assertEquals(parentHeight, centerView.getBottom()); 524 assertEquals(originalCenterViewLeft, centerView.getLeft()); 525 assertEquals(originalCenterViewRight, centerView.getRight()); 526 527 assertEquals(parentHeight - rightView.getHeight(), rightView.getTop()); 528 assertEquals(parentHeight, rightView.getBottom()); 529 assertEquals(originalRightViewLeft, rightView.getLeft()); 530 assertEquals(originalRightViewRight, rightView.getRight()); 531 } 532 533 @Test testHorizontalCenterGravityOnVerticalLayout()534 public void testHorizontalCenterGravityOnVerticalLayout() throws Throwable { 535 LinearLayout parent = (LinearLayout) mActivity.findViewById(R.id.linear_weightsum_vertical); 536 TextView topView = (TextView) parent.findViewById(R.id.weight_0_1); 537 TextView centerView = (TextView) parent.findViewById(R.id.weight_0_4); 538 TextView bottomView = (TextView) parent.findViewById(R.id.weight_0_5); 539 540 WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent, 541 () -> parent.setLayoutDirection(View.LAYOUT_DIRECTION_LTR)); 542 543 final int parentWidth = parent.getHeight(); 544 545 int originalTopViewTop = topView.getTop(); 546 int originalTopViewBottom = topView.getBottom(); 547 int originalCenterViewTop = centerView.getTop(); 548 int originalCenterViewBottom = centerView.getBottom(); 549 int originalBottomViewTop = bottomView.getTop(); 550 int originalBottomViewBottom = bottomView.getBottom(); 551 552 WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent, 553 () -> parent.setHorizontalGravity(Gravity.CENTER_HORIZONTAL)); 554 555 assertEquals(Gravity.CENTER_HORIZONTAL, 556 parent.getGravity() & Gravity.HORIZONTAL_GRAVITY_MASK); 557 558 ViewAsserts.assertHorizontalCenterAligned(parent, topView); 559 ViewAsserts.assertHorizontalCenterAligned(parent, centerView); 560 ViewAsserts.assertHorizontalCenterAligned(parent, bottomView); 561 562 int horizontalOffset = (parentWidth - topView.getWidth()) / 2; 563 assertEquals(originalTopViewTop, topView.getTop()); 564 assertEquals(originalTopViewBottom, topView.getBottom()); 565 assertEquals(horizontalOffset, topView.getLeft()); 566 assertEquals(horizontalOffset + topView.getWidth(), topView.getRight()); 567 568 horizontalOffset = (parentWidth - centerView.getWidth()) / 2; 569 assertEquals(originalCenterViewTop, centerView.getTop()); 570 assertEquals(originalCenterViewBottom, centerView.getBottom()); 571 assertEquals(horizontalOffset, centerView.getLeft()); 572 assertEquals(horizontalOffset + centerView.getWidth(), centerView.getRight()); 573 574 horizontalOffset = (parentWidth - bottomView.getWidth()) / 2; 575 assertEquals(originalBottomViewTop, bottomView.getTop()); 576 assertEquals(originalBottomViewBottom, bottomView.getBottom()); 577 assertEquals(horizontalOffset, bottomView.getLeft()); 578 assertEquals(horizontalOffset + bottomView.getWidth(), bottomView.getRight()); 579 } 580 581 @Test testRightGravityOnVerticalLayout()582 public void testRightGravityOnVerticalLayout() throws Throwable { 583 LinearLayout parent = (LinearLayout) mActivity.findViewById(R.id.linear_weightsum_vertical); 584 TextView topView = (TextView) parent.findViewById(R.id.weight_0_1); 585 TextView centerView = (TextView) parent.findViewById(R.id.weight_0_4); 586 TextView bottomView = (TextView) parent.findViewById(R.id.weight_0_5); 587 588 WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent, 589 () -> parent.setLayoutDirection(View.LAYOUT_DIRECTION_LTR)); 590 591 final int parentWidth = parent.getHeight(); 592 593 int originalTopViewTop = topView.getTop(); 594 int originalTopViewBottom = topView.getBottom(); 595 int originalCenterViewTop = centerView.getTop(); 596 int originalCenterViewBottom = centerView.getBottom(); 597 int originalBottomViewTop = bottomView.getTop(); 598 int originalBottomViewBottom = bottomView.getBottom(); 599 600 WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent, 601 () -> parent.setHorizontalGravity(Gravity.RIGHT)); 602 603 assertEquals(Gravity.RIGHT, parent.getGravity() & Gravity.HORIZONTAL_GRAVITY_MASK); 604 605 ViewAsserts.assertRightAligned(parent, topView); 606 ViewAsserts.assertRightAligned(parent, centerView); 607 ViewAsserts.assertRightAligned(parent, bottomView); 608 609 assertEquals(originalTopViewTop, topView.getTop()); 610 assertEquals(originalTopViewBottom, topView.getBottom()); 611 assertEquals(parentWidth - topView.getWidth(), topView.getLeft()); 612 assertEquals(parentWidth, topView.getRight()); 613 614 assertEquals(originalCenterViewTop, centerView.getTop()); 615 assertEquals(originalCenterViewBottom, centerView.getBottom()); 616 assertEquals(parentWidth - centerView.getWidth(), centerView.getLeft()); 617 assertEquals(parentWidth, centerView.getRight()); 618 619 assertEquals(originalBottomViewTop, bottomView.getTop()); 620 assertEquals(originalBottomViewBottom, bottomView.getBottom()); 621 assertEquals(parentWidth - bottomView.getWidth(), bottomView.getLeft()); 622 assertEquals(parentWidth, bottomView.getRight()); 623 } 624 verifyBounds(final ViewGroup viewGroup, final View view, final CountDownLatch countDownLatch, final int left, final int top, final int width, final int height)625 private void verifyBounds(final ViewGroup viewGroup, final View view, 626 final CountDownLatch countDownLatch, final int left, final int top, 627 final int width, final int height) { 628 viewGroup.getViewTreeObserver().addOnPreDrawListener( 629 new ViewTreeObserver.OnPreDrawListener() { 630 @Override 631 public boolean onPreDraw() { 632 assertEquals(left, view.getLeft()); 633 assertEquals(top, view.getTop()); 634 assertEquals(width, view.getWidth()); 635 assertEquals(height, view.getHeight()); 636 countDownLatch.countDown(); 637 viewGroup.getViewTreeObserver().removeOnPreDrawListener(this); 638 return true; 639 } 640 }); 641 } 642 643 @Test testVisibilityAffectsLayout()644 public void testVisibilityAffectsLayout() throws Throwable { 645 // Toggling view visibility between GONE/VISIBLE can affect the position of 646 // other children in that container. This test verifies that these changes 647 // on the first child of a LinearLayout affects the position of a second child 648 final int childWidth = 100; 649 final int childHeight = 200; 650 final LinearLayout parent = new LinearLayout(mActivity); 651 ViewGroup.LayoutParams parentParams = new ViewGroup.LayoutParams( 652 ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); 653 parent.setLayoutParams(parentParams); 654 final View child1 = new View(mActivity); 655 child1.setBackgroundColor(Color.GREEN); 656 ViewGroup.LayoutParams childParams = new ViewGroup.LayoutParams(childWidth, childHeight); 657 child1.setLayoutParams(childParams); 658 final View child2 = new View(mActivity); 659 child2.setBackgroundColor(Color.RED); 660 childParams = new ViewGroup.LayoutParams(childWidth, childHeight); 661 child2.setLayoutParams(childParams); 662 final ViewGroup viewGroup = (ViewGroup) mActivity.findViewById(R.id.linearlayout_root); 663 664 final CountDownLatch countDownLatch1 = new CountDownLatch(1); 665 mActivityRule.runOnUiThread(() -> { 666 viewGroup.removeAllViews(); 667 viewGroup.addView(parent); 668 parent.addView(child1); 669 parent.addView(child2); 670 verifyBounds(viewGroup, child1, countDownLatch1, 0, 0, childWidth, childHeight); 671 verifyBounds(viewGroup, child2, countDownLatch1, 672 childWidth, 0, childWidth, childHeight); 673 }); 674 try { 675 assertTrue(countDownLatch1.await(500, TimeUnit.MILLISECONDS)); 676 } catch (InterruptedException ie) { 677 fail(ie.getMessage()); 678 } 679 680 final CountDownLatch countDownLatch2 = new CountDownLatch(1); 681 mActivityRule.runOnUiThread(() -> { 682 child1.setVisibility(View.GONE); 683 verifyBounds(viewGroup, child2, countDownLatch2, 0, 0, childWidth, childHeight); 684 }); 685 try { 686 assertTrue(countDownLatch2.await(500, TimeUnit.MILLISECONDS)); 687 } catch (InterruptedException ie) { 688 fail(ie.getMessage()); 689 } 690 691 final CountDownLatch countDownLatch3 = new CountDownLatch(2); 692 mActivityRule.runOnUiThread(() -> { 693 child1.setVisibility(View.VISIBLE); 694 verifyBounds(viewGroup, child1, countDownLatch3, 0, 0, childWidth, childHeight); 695 verifyBounds(viewGroup, child2, countDownLatch3, 696 childWidth, 0, childWidth, childHeight); 697 }); 698 try { 699 assertTrue(countDownLatch3.await(500, TimeUnit.MILLISECONDS)); 700 } catch (InterruptedException ie) { 701 fail(ie.getMessage()); 702 } 703 } 704 verifyVisualsOfVerticalLayoutWithDivider(LinearLayout parent, int expectedDividerPositionMask, int expectedDividerSize, @ColorInt int expectedDividerColor, int expectedDividerPadding)705 private void verifyVisualsOfVerticalLayoutWithDivider(LinearLayout parent, 706 int expectedDividerPositionMask, 707 int expectedDividerSize, @ColorInt int expectedDividerColor, 708 int expectedDividerPadding) { 709 final int parentWidth = parent.getWidth(); 710 final int parentHeight = parent.getHeight(); 711 712 final boolean expectingTopDivider = 713 (expectedDividerPositionMask & LinearLayout.SHOW_DIVIDER_BEGINNING) != 0; 714 final boolean expectingMiddleDivider = 715 (expectedDividerPositionMask & LinearLayout.SHOW_DIVIDER_MIDDLE) != 0; 716 final boolean expectingBottomDivider = 717 (expectedDividerPositionMask & LinearLayout.SHOW_DIVIDER_END) != 0; 718 final int expectedDividerCount = (expectingTopDivider ? 1 : 0) 719 + (expectingMiddleDivider ? 1 : 0) + (expectingBottomDivider ? 1 : 0); 720 721 final int expectedChildHeight = 722 (parentHeight - expectedDividerCount * expectedDividerSize) / 2; 723 724 final int expectedTopChildTop = expectingTopDivider ? expectedDividerSize : 0; 725 TestUtils.assertRegionPixelsOfColor("Region of first child is blue", parent, 726 new Rect(0, expectedTopChildTop, parentWidth, 727 expectedTopChildTop + expectedChildHeight), 728 Color.BLUE, 1, true); 729 730 final int expectedBottomChildBottom = 731 expectingBottomDivider ? parentHeight - expectedDividerSize : parentHeight; 732 TestUtils.assertRegionPixelsOfColor("Region of second child is green", parent, 733 new Rect(0, expectedBottomChildBottom - expectedChildHeight, parentWidth, 734 expectedBottomChildBottom), 735 Color.GREEN, 1, true); 736 737 if (expectedDividerSize == 0) { 738 return; 739 } 740 741 // Do we expect top divider? 742 if (expectingTopDivider) { 743 TestUtils.assertRegionPixelsOfColor( 744 "Region of top divider is " + TestUtils.formatColorToHex(expectedDividerColor), 745 parent, 746 new Rect(expectedDividerPadding, 0, parentWidth - expectedDividerPadding, 747 expectedDividerSize), 748 expectedDividerColor, 1, true); 749 TestUtils.assertRegionPixelsOfColor("Region of left padding of top divider is yellow", 750 parent, 751 new Rect(0, 0, expectedDividerPadding, expectedDividerSize), 752 Color.YELLOW, 1, true); 753 TestUtils.assertRegionPixelsOfColor("Region of right padding of top divider is yellow", 754 parent, 755 new Rect(parentWidth - expectedDividerPadding, 0, parentWidth, 756 expectedDividerSize), 757 Color.YELLOW, 1, true); 758 } 759 760 // Do we expect middle divider? 761 if (expectingMiddleDivider) { 762 final int expectedMiddleDividerTop = expectedTopChildTop + expectedChildHeight; 763 TestUtils.assertRegionPixelsOfColor( 764 "Region of middle divider is " + 765 TestUtils.formatColorToHex(expectedDividerColor), 766 parent, 767 new Rect(expectedDividerPadding, expectedMiddleDividerTop, 768 parentWidth - expectedDividerPadding, 769 expectedMiddleDividerTop + expectedDividerSize), 770 expectedDividerColor, 1, true); 771 TestUtils.assertRegionPixelsOfColor( 772 "Region of left padding of middle divider is yellow", 773 parent, 774 new Rect(0, expectedMiddleDividerTop, expectedDividerPadding, 775 expectedMiddleDividerTop + expectedDividerSize), 776 Color.YELLOW, 1, true); 777 TestUtils.assertRegionPixelsOfColor( 778 "Region of right padding of middle divider is yellow", 779 parent, 780 new Rect(parentWidth - expectedDividerPadding, expectedMiddleDividerTop, 781 parentWidth, expectedMiddleDividerTop + expectedDividerSize), 782 Color.YELLOW, 1, true); 783 } 784 785 // Do we expect bottom divider? 786 if (expectingBottomDivider) { 787 final int expectedBottomDividerTop = expectedBottomChildBottom; 788 TestUtils.assertRegionPixelsOfColor( 789 "Region of bottom divider is " + 790 TestUtils.formatColorToHex(expectedDividerColor), 791 parent, 792 new Rect(expectedDividerPadding, expectedBottomDividerTop, 793 parentWidth - expectedDividerPadding, 794 expectedBottomDividerTop + expectedDividerSize), 795 expectedDividerColor, 1, true); 796 TestUtils.assertRegionPixelsOfColor( 797 "Region of left padding of bottom divider is yellow", 798 parent, 799 new Rect(0, expectedBottomDividerTop, expectedDividerPadding, 800 expectedBottomDividerTop + expectedDividerSize), 801 Color.YELLOW, 1, true); 802 TestUtils.assertRegionPixelsOfColor( 803 "Region of right padding of bottom divider is yellow", 804 parent, 805 new Rect(parentWidth - expectedDividerPadding, expectedBottomDividerTop, 806 parentWidth, expectedBottomDividerTop + expectedDividerSize), 807 Color.YELLOW, 1, true); 808 } 809 } 810 811 /** 812 * layout of vertical LinearLayout. 813 * ----------------------------------- 814 * | ------------------------------- | 815 * | | child1 | | 816 * | ------------------------------- | 817 * | - - - - - - divider - - - - - - | 818 * | ------------------------------- | 819 * | | child2 | | 820 * | ------------------------------- | 821 * ----------------------------------- 822 * 823 * Parent is filled with yellow color. Child 1 is filled with green and child 2 is filled 824 * with blue. Divider is red at the beginning. Throughout this method we reconfigure the 825 * visibility, drawable and paddings of the divider and verify the overall visuals of the 826 * container. 827 */ 828 @Test testDividersInVerticalLayout()829 public void testDividersInVerticalLayout() throws Throwable { 830 final LinearLayout parent = 831 (LinearLayout) mActivity.findViewById(R.id.linear_vertical_with_divider); 832 833 final Resources res = mActivity.getResources(); 834 final int dividerSize = res.getDimensionPixelSize(R.dimen.linear_layout_divider_size); 835 final int dividerPadding = res.getDimensionPixelSize(R.dimen.linear_layout_divider_padding); 836 837 assertEquals(LinearLayout.SHOW_DIVIDER_MIDDLE, parent.getShowDividers()); 838 assertEquals(dividerPadding, parent.getDividerPadding()); 839 final Drawable dividerDrawable = parent.getDividerDrawable(); 840 TestUtils.assertAllPixelsOfColor("Divider is red", dividerDrawable, 841 dividerDrawable.getIntrinsicWidth(), dividerDrawable.getIntrinsicHeight(), 842 false, Color.RED, 1, true); 843 844 // Test the initial visuals of the entire parent 845 verifyVisualsOfVerticalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_MIDDLE, 846 dividerSize, Color.RED, dividerPadding); 847 848 // Change the divider to magenta 849 WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent, 850 () -> parent.setDividerDrawable( 851 mActivity.getDrawable(R.drawable.linear_layout_divider_magenta))); 852 verifyVisualsOfVerticalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_MIDDLE, 853 dividerSize, Color.MAGENTA, dividerPadding); 854 855 // Change the divider to null (no divider effectively) 856 WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent, 857 () -> parent.setDividerDrawable(null)); 858 verifyVisualsOfVerticalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_MIDDLE, 859 0, Color.TRANSPARENT, 0); 860 861 // Change the divider back to red 862 WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent, 863 () -> parent.setDividerDrawable( 864 mActivity.getDrawable(R.drawable.linear_layout_divider_red))); 865 verifyVisualsOfVerticalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_MIDDLE, 866 dividerSize, Color.RED, dividerPadding); 867 868 // Change the padding to half the original size 869 final int halfPadding = dividerPadding / 2; 870 WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent, 871 () -> parent.setDividerPadding(halfPadding)); 872 assertEquals(halfPadding, parent.getDividerPadding()); 873 verifyVisualsOfVerticalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_MIDDLE, 874 dividerSize, Color.RED, halfPadding); 875 876 // Change the padding to twice the original size 877 final int doublePadding = dividerPadding * 2; 878 WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent, 879 () -> parent.setDividerPadding(doublePadding)); 880 assertEquals(doublePadding, parent.getDividerPadding()); 881 verifyVisualsOfVerticalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_MIDDLE, 882 dividerSize, Color.RED, doublePadding); 883 884 // And back to the original padding 885 WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent, 886 () -> parent.setDividerPadding(dividerPadding)); 887 assertEquals(dividerPadding, parent.getDividerPadding()); 888 verifyVisualsOfVerticalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_MIDDLE, 889 dividerSize, Color.RED, dividerPadding); 890 891 // Set show dividers to NONE (no divider effectively) 892 WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent, 893 () -> parent.setShowDividers(LinearLayout.SHOW_DIVIDER_NONE)); 894 assertEquals(LinearLayout.SHOW_DIVIDER_NONE, parent.getShowDividers()); 895 verifyVisualsOfVerticalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_NONE, 896 0, Color.TRANSPARENT, 0); 897 898 // Show only top divider 899 WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent, 900 () -> parent.setShowDividers(LinearLayout.SHOW_DIVIDER_BEGINNING)); 901 assertEquals(LinearLayout.SHOW_DIVIDER_BEGINNING, parent.getShowDividers()); 902 verifyVisualsOfVerticalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_BEGINNING, 903 dividerSize, Color.RED, dividerPadding); 904 905 // Show only bottom divider 906 WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent, 907 () -> parent.setShowDividers(LinearLayout.SHOW_DIVIDER_END)); 908 assertEquals(LinearLayout.SHOW_DIVIDER_END, parent.getShowDividers()); 909 verifyVisualsOfVerticalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_END, 910 dividerSize, Color.RED, dividerPadding); 911 912 // Show top and bottom dividers 913 WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent, 914 () -> parent.setShowDividers( 915 LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_END)); 916 assertEquals(LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_END, 917 parent.getShowDividers()); 918 verifyVisualsOfVerticalLayoutWithDivider(parent, 919 LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_END, 920 dividerSize, Color.RED, dividerPadding); 921 922 // Show top and middle dividers 923 WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent, 924 () -> parent.setShowDividers( 925 LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_MIDDLE)); 926 assertEquals(LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_MIDDLE, 927 parent.getShowDividers()); 928 verifyVisualsOfVerticalLayoutWithDivider(parent, 929 LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_MIDDLE, 930 dividerSize, Color.RED, dividerPadding); 931 932 // Show middle and bottom dividers 933 WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent, 934 () -> parent.setShowDividers( 935 LinearLayout.SHOW_DIVIDER_MIDDLE | LinearLayout.SHOW_DIVIDER_END)); 936 assertEquals(LinearLayout.SHOW_DIVIDER_MIDDLE | LinearLayout.SHOW_DIVIDER_END, 937 parent.getShowDividers()); 938 verifyVisualsOfVerticalLayoutWithDivider(parent, 939 LinearLayout.SHOW_DIVIDER_MIDDLE | LinearLayout.SHOW_DIVIDER_END, 940 dividerSize, Color.RED, dividerPadding); 941 942 // Show top, middle and bottom dividers 943 WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent, 944 () -> parent.setShowDividers( 945 LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_MIDDLE 946 | LinearLayout.SHOW_DIVIDER_END)); 947 assertEquals( 948 LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_MIDDLE 949 | LinearLayout.SHOW_DIVIDER_END, 950 parent.getShowDividers()); 951 verifyVisualsOfVerticalLayoutWithDivider(parent, 952 LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_MIDDLE 953 | LinearLayout.SHOW_DIVIDER_END, 954 dividerSize, Color.RED, dividerPadding); 955 } 956 verifyVisualsOfHorizontalLayoutWithDivider(LinearLayout parent, int expectedDividerPositionMask, int expectedDividerSize, @ColorInt int expectedDividerColor, int expectedDividerPadding)957 private void verifyVisualsOfHorizontalLayoutWithDivider(LinearLayout parent, 958 int expectedDividerPositionMask, 959 int expectedDividerSize, @ColorInt int expectedDividerColor, 960 int expectedDividerPadding) { 961 final int parentWidth = parent.getWidth(); 962 final int parentHeight = parent.getHeight(); 963 964 final boolean expectingLeftDivider = 965 (expectedDividerPositionMask & LinearLayout.SHOW_DIVIDER_BEGINNING) != 0; 966 final boolean expectingMiddleDivider = 967 (expectedDividerPositionMask & LinearLayout.SHOW_DIVIDER_MIDDLE) != 0; 968 final boolean expectingRightDivider = 969 (expectedDividerPositionMask & LinearLayout.SHOW_DIVIDER_END) != 0; 970 final int expectedDividerCount = (expectingLeftDivider ? 1 : 0) 971 + (expectingMiddleDivider ? 1 : 0) + (expectingRightDivider ? 1 : 0); 972 973 final int expectedChildWidth = 974 (parentWidth - expectedDividerCount * expectedDividerSize) / 2; 975 976 final int expectedLeftChildLeft = expectingLeftDivider ? expectedDividerSize : 0; 977 TestUtils.assertRegionPixelsOfColor("Region of first child is blue", parent, 978 new Rect(expectedLeftChildLeft, 0, 979 expectedLeftChildLeft + expectedChildWidth, parentHeight), 980 Color.BLUE, 1, true); 981 982 final int expectedRightChildRight = 983 expectingRightDivider ? parentWidth - expectedDividerSize : parentWidth; 984 TestUtils.assertRegionPixelsOfColor("Region of second child is green", parent, 985 new Rect(expectedRightChildRight - expectedChildWidth, 0, expectedRightChildRight, 986 parentHeight), 987 Color.GREEN, 1, true); 988 989 if (expectedDividerSize == 0) { 990 return; 991 } 992 993 // Do we expect left divider? 994 if (expectingLeftDivider) { 995 TestUtils.assertRegionPixelsOfColor( 996 "Region of left divider is " + TestUtils.formatColorToHex(expectedDividerColor), 997 parent, 998 new Rect(0, expectedDividerPadding, expectedDividerSize, 999 parentHeight - expectedDividerPadding), 1000 expectedDividerColor, 1, true); 1001 TestUtils.assertRegionPixelsOfColor( 1002 "Region of top padding of left divider is yellow", 1003 parent, 1004 new Rect(0, 0, expectedDividerSize, expectedDividerPadding), 1005 Color.YELLOW, 1, true); 1006 TestUtils.assertRegionPixelsOfColor( 1007 "Region of bottom padding of left divider is yellow", 1008 parent, 1009 new Rect(0, parentHeight - expectedDividerPadding, expectedDividerSize, 1010 parentHeight), 1011 Color.YELLOW, 1, true); 1012 } 1013 1014 // Do we expect middle divider? 1015 if (expectingMiddleDivider) { 1016 final int expectedMiddleDividerLeft = expectedLeftChildLeft + expectedChildWidth; 1017 TestUtils.assertRegionPixelsOfColor( 1018 "Region of middle divider is " + 1019 TestUtils.formatColorToHex(expectedDividerColor), 1020 parent, 1021 new Rect(expectedMiddleDividerLeft, expectedDividerPadding, 1022 expectedMiddleDividerLeft + expectedDividerSize, 1023 parentHeight - expectedDividerPadding), 1024 expectedDividerColor, 1, true); 1025 TestUtils.assertRegionPixelsOfColor( 1026 "Region of top padding of middle divider is yellow", 1027 parent, 1028 new Rect(expectedMiddleDividerLeft, 0, 1029 expectedMiddleDividerLeft + expectedDividerSize, 1030 expectedDividerPadding), 1031 Color.YELLOW, 1, true); 1032 TestUtils.assertRegionPixelsOfColor( 1033 "Region of bottom padding of middle divider is yellow", 1034 parent, 1035 new Rect(expectedMiddleDividerLeft, parentHeight - expectedDividerPadding, 1036 expectedMiddleDividerLeft + expectedDividerSize, parentHeight), 1037 Color.YELLOW, 1, true); 1038 } 1039 1040 // Do we expect right divider? 1041 if (expectingRightDivider) { 1042 final int expectedRightDividerLeft = expectedRightChildRight; 1043 TestUtils.assertRegionPixelsOfColor( 1044 "Region of right divider is " + 1045 TestUtils.formatColorToHex(expectedDividerColor), 1046 parent, 1047 new Rect(expectedRightDividerLeft, expectedDividerPadding, 1048 expectedRightDividerLeft + expectedDividerSize, 1049 parentHeight - expectedDividerPadding), 1050 expectedDividerColor, 1, true); 1051 TestUtils.assertRegionPixelsOfColor( 1052 "Region of top padding of right divider is yellow", 1053 parent, 1054 new Rect(expectedRightDividerLeft, 0, 1055 expectedRightDividerLeft + expectedDividerSize, 1056 expectedDividerPadding), 1057 Color.YELLOW, 1, true); 1058 TestUtils.assertRegionPixelsOfColor( 1059 "Region of bottom padding of right divider is yellow", 1060 parent, 1061 new Rect(expectedRightDividerLeft, parentHeight - expectedDividerPadding, 1062 expectedRightDividerLeft + expectedDividerSize, parentHeight), 1063 Color.YELLOW, 1, true); 1064 } 1065 } 1066 1067 /** 1068 * layout of horizontal LinearLayout. 1069 * ----------------------------------- 1070 * | ------------ | ------------- | 1071 * | | | | | | 1072 * | | | d | | | 1073 * | | | i | | | 1074 * | | | v | | | 1075 * | | child1 | i | child2 | | 1076 * | | | d | | | 1077 * | | | e | | | 1078 * | | | r | | | 1079 * | | | | | | 1080 * | ------------ | ------------- | 1081 * ----------------------------------- 1082 * 1083 * Parent is filled with yellow color. Child 1 is filled with green and child 2 is filled 1084 * with blue. Divider is red at the beginning. Throughout this method we reconfigure the 1085 * visibility, drawable and paddings of the divider and verify the overall visuals of the 1086 * container. 1087 */ 1088 @Test testDividersInHorizontalLayout()1089 public void testDividersInHorizontalLayout() throws Throwable { 1090 final LinearLayout parent = 1091 (LinearLayout) mActivity.findViewById(R.id.linear_horizontal_with_divider); 1092 1093 WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent, 1094 () -> parent.setLayoutDirection(View.LAYOUT_DIRECTION_LTR)); 1095 1096 final Resources res = mActivity.getResources(); 1097 final int dividerSize = res.getDimensionPixelSize(R.dimen.linear_layout_divider_size); 1098 final int dividerPadding = res.getDimensionPixelSize(R.dimen.linear_layout_divider_padding); 1099 1100 assertEquals(LinearLayout.SHOW_DIVIDER_MIDDLE, parent.getShowDividers()); 1101 assertEquals(dividerPadding, parent.getDividerPadding()); 1102 final Drawable dividerDrawable = parent.getDividerDrawable(); 1103 TestUtils.assertAllPixelsOfColor("Divider is red", dividerDrawable, 1104 dividerDrawable.getIntrinsicWidth(), dividerDrawable.getIntrinsicHeight(), 1105 false, Color.RED, 1, true); 1106 1107 // Test the initial visuals of the entire parent 1108 verifyVisualsOfHorizontalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_MIDDLE, 1109 dividerSize, Color.RED, dividerPadding); 1110 1111 // Change the divider to magenta 1112 WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent, 1113 () -> parent.setDividerDrawable( 1114 mActivity.getDrawable(R.drawable.linear_layout_divider_magenta))); 1115 verifyVisualsOfHorizontalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_MIDDLE, 1116 dividerSize, Color.MAGENTA, dividerPadding); 1117 1118 // Change the divider to null (no divider effectively) 1119 WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent, 1120 () -> parent.setDividerDrawable(null)); 1121 verifyVisualsOfHorizontalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_MIDDLE, 1122 0, Color.TRANSPARENT, 0); 1123 1124 // Change the divider back to red 1125 WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent, 1126 () -> parent.setDividerDrawable( 1127 mActivity.getDrawable(R.drawable.linear_layout_divider_red))); 1128 verifyVisualsOfHorizontalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_MIDDLE, 1129 dividerSize, Color.RED, dividerPadding); 1130 1131 // Change the padding to half the original size 1132 final int halfPadding = dividerPadding / 2; 1133 WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent, 1134 () -> parent.setDividerPadding(halfPadding)); 1135 assertEquals(halfPadding, parent.getDividerPadding()); 1136 verifyVisualsOfHorizontalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_MIDDLE, 1137 dividerSize, Color.RED, halfPadding); 1138 1139 // Change the padding to twice the original size 1140 final int doublePadding = dividerPadding * 2; 1141 WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent, 1142 () -> parent.setDividerPadding(doublePadding)); 1143 assertEquals(doublePadding, parent.getDividerPadding()); 1144 verifyVisualsOfHorizontalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_MIDDLE, 1145 dividerSize, Color.RED, doublePadding); 1146 1147 // And back to the original padding 1148 WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent, 1149 () -> parent.setDividerPadding(dividerPadding)); 1150 assertEquals(dividerPadding, parent.getDividerPadding()); 1151 verifyVisualsOfHorizontalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_MIDDLE, 1152 dividerSize, Color.RED, dividerPadding); 1153 1154 // Set show dividers to NONE (no divider effectively) 1155 WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent, 1156 () -> parent.setShowDividers(LinearLayout.SHOW_DIVIDER_NONE)); 1157 assertEquals(LinearLayout.SHOW_DIVIDER_NONE, parent.getShowDividers()); 1158 verifyVisualsOfHorizontalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_NONE, 1159 0, Color.TRANSPARENT, 0); 1160 1161 // Show only left divider 1162 WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent, 1163 () -> parent.setShowDividers(LinearLayout.SHOW_DIVIDER_BEGINNING)); 1164 assertEquals(LinearLayout.SHOW_DIVIDER_BEGINNING, parent.getShowDividers()); 1165 verifyVisualsOfHorizontalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_BEGINNING, 1166 dividerSize, Color.RED, dividerPadding); 1167 1168 // Show only right divider 1169 WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent, 1170 () -> parent.setShowDividers(LinearLayout.SHOW_DIVIDER_END)); 1171 assertEquals(LinearLayout.SHOW_DIVIDER_END, parent.getShowDividers()); 1172 verifyVisualsOfHorizontalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_END, 1173 dividerSize, Color.RED, dividerPadding); 1174 1175 // Show left and right dividers 1176 WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent, 1177 () -> parent.setShowDividers( 1178 LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_END)); 1179 assertEquals(LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_END, 1180 parent.getShowDividers()); 1181 verifyVisualsOfHorizontalLayoutWithDivider(parent, 1182 LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_END, 1183 dividerSize, Color.RED, dividerPadding); 1184 1185 // Show left and middle dividers 1186 WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent, 1187 () -> parent.setShowDividers( 1188 LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_MIDDLE)); 1189 assertEquals(LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_MIDDLE, 1190 parent.getShowDividers()); 1191 verifyVisualsOfHorizontalLayoutWithDivider(parent, 1192 LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_MIDDLE, 1193 dividerSize, Color.RED, dividerPadding); 1194 1195 // Show middle and right dividers 1196 WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent, 1197 () -> parent.setShowDividers( 1198 LinearLayout.SHOW_DIVIDER_MIDDLE | LinearLayout.SHOW_DIVIDER_END)); 1199 assertEquals(LinearLayout.SHOW_DIVIDER_MIDDLE | LinearLayout.SHOW_DIVIDER_END, 1200 parent.getShowDividers()); 1201 verifyVisualsOfHorizontalLayoutWithDivider(parent, 1202 LinearLayout.SHOW_DIVIDER_MIDDLE | LinearLayout.SHOW_DIVIDER_END, 1203 dividerSize, Color.RED, dividerPadding); 1204 1205 // Show left, middle and right dividers 1206 WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent, 1207 () -> parent.setShowDividers( 1208 LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_MIDDLE 1209 | LinearLayout.SHOW_DIVIDER_END)); 1210 assertEquals( 1211 LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_MIDDLE 1212 | LinearLayout.SHOW_DIVIDER_END, 1213 parent.getShowDividers()); 1214 verifyVisualsOfHorizontalLayoutWithDivider(parent, 1215 LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_MIDDLE 1216 | LinearLayout.SHOW_DIVIDER_END, 1217 dividerSize, Color.RED, dividerPadding); 1218 } 1219 1220 @Test testZeroWeightDistributionHorizontal()1221 public void testZeroWeightDistributionHorizontal() throws Throwable { 1222 // Ensure that weight is correctly distributed when there is no excess space. 1223 final View content = mActivity.findViewById(android.R.id.content); 1224 WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, content, 1225 () -> mActivity.setContentView(R.layout.linearlayout_zero_weight_horizontal)); 1226 1227 final View parent = mActivity.findViewById(R.id.container1); 1228 assertEquals(0, mActivity.findViewById(R.id.view1).getWidth()); 1229 assertEquals(0, mActivity.findViewById(R.id.view2).getWidth()); 1230 assertEquals(parent.getWidth(), mActivity.findViewById(R.id.view3).getWidth()); 1231 } 1232 1233 @Test testZeroWeightDistributionVertical()1234 public void testZeroWeightDistributionVertical() throws Throwable { 1235 // Ensure that weight is correctly distributed when there is no excess space. 1236 final View content = mActivity.findViewById(android.R.id.content); 1237 WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, content, 1238 () -> mActivity.setContentView(R.layout.linearlayout_zero_weight_vertical)); 1239 1240 final View parent = mActivity.findViewById(R.id.container1); 1241 assertEquals(0, mActivity.findViewById(R.id.view1).getHeight()); 1242 assertEquals(0, mActivity.findViewById(R.id.view2).getHeight()); 1243 assertEquals(parent.getHeight(), mActivity.findViewById(R.id.view3).getHeight()); 1244 } 1245 1246 private class MockListView extends ListView { 1247 private final static int DEFAULT_CHILD_BASE_LINE = 1; 1248 MockListView(Context context)1249 public MockListView(Context context) { 1250 super(context); 1251 } 1252 getBaseline()1253 public int getBaseline() { 1254 return DEFAULT_CHILD_BASE_LINE; 1255 } 1256 } 1257 1258 /** 1259 * Add MockLinearLayout to help for testing protected methods in LinearLayout. 1260 * Because we can not access protected methods in LinearLayout directly, we have to 1261 * extends from it and override protected methods so that we can access them in 1262 * our test codes. 1263 */ 1264 public static class MockLinearLayout extends LinearLayout { MockLinearLayout(Context c)1265 public MockLinearLayout(Context c) { 1266 super(c); 1267 } 1268 MockLinearLayout(Context context, @Nullable AttributeSet attrs)1269 public MockLinearLayout(Context context, @Nullable AttributeSet attrs) { 1270 super(context, attrs); 1271 } 1272 1273 @Override checkLayoutParams(ViewGroup.LayoutParams p)1274 protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { 1275 return super.checkLayoutParams(p); 1276 } 1277 1278 @Override generateDefaultLayoutParams()1279 protected LinearLayout.LayoutParams generateDefaultLayoutParams() { 1280 return super.generateDefaultLayoutParams(); 1281 } 1282 1283 @Override generateLayoutParams(ViewGroup.LayoutParams p)1284 protected LinearLayout.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { 1285 return super.generateLayoutParams(p); 1286 } 1287 } 1288 } 1289