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 81 public void setup() { 82 mInstrumentation = InstrumentationRegistry.getInstrumentation(); 83 mActivity = mActivityRule.getActivity(); 84 } 85 86 @Test 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) 98 public void testConstructorNullContext() { 99 new LinearLayout(null, null); 100 } 101 102 @UiThreadTest 103 @Test 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 1249 public MockListView(Context context) { 1250 super(context); 1251 } 1252 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 { 1265 public MockLinearLayout(Context c) { 1266 super(c); 1267 } 1268 1269 public MockLinearLayout(Context context, @Nullable AttributeSet attrs) { 1270 super(context, attrs); 1271 } 1272 1273 @Override 1274 protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { 1275 return super.checkLayoutParams(p); 1276 } 1277 1278 @Override 1279 protected LinearLayout.LayoutParams generateDefaultLayoutParams() { 1280 return super.generateDefaultLayoutParams(); 1281 } 1282 1283 @Override 1284 protected LinearLayout.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { 1285 return super.generateLayoutParams(p); 1286 } 1287 } 1288 } 1289