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