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