1 /* 2 * Copyright (C) 2009 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.assertSame; 22 import static org.junit.Assert.assertTrue; 23 import static org.junit.Assert.fail; 24 import static org.mockito.Matchers.eq; 25 import static org.mockito.Mockito.spy; 26 import static org.mockito.Mockito.verify; 27 28 import android.app.Activity; 29 import android.app.Instrumentation; 30 import android.content.Context; 31 import android.graphics.Color; 32 import android.graphics.Rect; 33 import android.util.AttributeSet; 34 import android.util.Xml; 35 import android.view.View; 36 import android.view.View.MeasureSpec; 37 import android.view.ViewGroup; 38 import android.widget.EdgeEffect; 39 import android.widget.FrameLayout; 40 import android.widget.HorizontalScrollView; 41 import android.widget.TextView; 42 43 import androidx.test.InstrumentationRegistry; 44 import androidx.test.annotation.UiThreadTest; 45 import androidx.test.filters.MediumTest; 46 import androidx.test.rule.ActivityTestRule; 47 import androidx.test.runner.AndroidJUnit4; 48 49 import com.android.compatibility.common.util.PollingCheck; 50 import com.android.compatibility.common.util.WidgetTestUtils; 51 52 import org.junit.Before; 53 import org.junit.Rule; 54 import org.junit.Test; 55 import org.junit.runner.RunWith; 56 import org.xmlpull.v1.XmlPullParser; 57 58 /** 59 * Test {@link HorizontalScrollView}. 60 */ 61 @MediumTest 62 @RunWith(AndroidJUnit4.class) 63 public class HorizontalScrollViewTest { 64 private static final int ITEM_WIDTH = 250; 65 private static final int ITEM_HEIGHT = 100; 66 private static final int ITEM_COUNT = 15; 67 private static final int PAGE_WIDTH = 100; 68 private static final int PAGE_HEIGHT = 100; 69 private static final int SCROLL_RIGHT = ITEM_WIDTH * ITEM_COUNT - PAGE_WIDTH; 70 71 private Instrumentation mInstrumentation; 72 private Activity mActivity; 73 private HorizontalScrollView mScrollViewRegular; 74 private HorizontalScrollView mScrollViewCustom; 75 private MyHorizontalScrollView mScrollViewCustomEmpty; 76 77 @Rule 78 public ActivityTestRule<HorizontalScrollViewCtsActivity> mActivityRule = 79 new ActivityTestRule<>(HorizontalScrollViewCtsActivity.class); 80 81 @Before 82 public void setup() { 83 mInstrumentation = InstrumentationRegistry.getInstrumentation(); 84 mActivity = mActivityRule.getActivity(); 85 mScrollViewRegular = (HorizontalScrollView) mActivity.findViewById( 86 R.id.horizontal_scroll_view_regular); 87 mScrollViewCustom = (MyHorizontalScrollView) mActivity.findViewById( 88 R.id.horizontal_scroll_view_custom); 89 mScrollViewCustomEmpty = (MyHorizontalScrollView) mActivity.findViewById( 90 R.id.horizontal_scroll_view_custom_empty); 91 } 92 93 @Test 94 public void testConstructor() { 95 XmlPullParser parser = mActivity.getResources().getLayout(R.layout.horizontal_scrollview); 96 AttributeSet attrs = Xml.asAttributeSet(parser); 97 new HorizontalScrollView(mActivity); 98 99 new HorizontalScrollView(mActivity, attrs); 100 101 new HorizontalScrollView(mActivity, attrs, 0); 102 } 103 104 @UiThreadTest 105 @Test 106 public void testGetMaxScrollAmount() { 107 mScrollViewRegular.layout(0, 0, 100, 200); 108 assertEquals((100 - 0) / 2, mScrollViewRegular.getMaxScrollAmount()); 109 110 mScrollViewRegular.layout(0, 0, 150, 100); 111 assertEquals((150 - 0) / 2, mScrollViewRegular.getMaxScrollAmount()); 112 } 113 114 @UiThreadTest 115 @Test 116 public void testAddView() { 117 TextView child0 = new TextView(mActivity); 118 mScrollViewRegular.addView(child0); 119 assertSame(child0, mScrollViewRegular.getChildAt(0)); 120 121 assertEquals(1, mScrollViewRegular.getChildCount()); 122 TextView child1 = new TextView(mActivity); 123 try { 124 mScrollViewRegular.addView(child1); 125 fail("did not throw IllegalStateException when add more than one child"); 126 } catch (IllegalStateException e) { 127 // expected 128 } 129 assertEquals(1, mScrollViewRegular.getChildCount()); 130 } 131 132 @UiThreadTest 133 @Test 134 public void testAddViewWithIndex() { 135 TextView child0 = new TextView(mActivity); 136 mScrollViewRegular.addView(child0, 0); 137 assertSame(child0, mScrollViewRegular.getChildAt(0)); 138 139 assertEquals(1, mScrollViewRegular.getChildCount()); 140 TextView child1 = new TextView(mActivity); 141 try { 142 mScrollViewRegular.addView(child1, 1); 143 fail("did not throw IllegalStateException when add more than one child"); 144 } catch (IllegalStateException e) { 145 // expected 146 } 147 assertEquals(1, mScrollViewRegular.getChildCount()); 148 149 mScrollViewRegular.removeAllViews(); 150 151 mScrollViewRegular.addView(child0, -1); 152 assertSame(child0, mScrollViewRegular.getChildAt(0)); 153 154 assertEquals(1, mScrollViewRegular.getChildCount()); 155 child1 = new TextView(mActivity); 156 try { 157 mScrollViewRegular.addView(child1, -1); 158 fail("did not throw IllegalStateException when add more than one child"); 159 } catch (IllegalStateException e) { 160 // expected 161 } 162 assertEquals(1, mScrollViewRegular.getChildCount()); 163 164 mScrollViewRegular.removeAllViews(); 165 166 try { 167 mScrollViewRegular.addView(child0, 1); 168 fail("did not throw IndexOutOfBoundsException when index is larger than 0"); 169 } catch (IndexOutOfBoundsException e) { 170 // expected 171 } 172 } 173 174 @UiThreadTest 175 @Test 176 public void testAddViewWithLayoutParams() { 177 TextView child0 = new TextView(mActivity); 178 mScrollViewRegular.addView(child0, new ViewGroup.LayoutParams(200, 100)); 179 assertSame(child0, mScrollViewRegular.getChildAt(0)); 180 assertEquals(200, child0.getLayoutParams().width); 181 assertEquals(100, child0.getLayoutParams().height); 182 183 assertEquals(1, mScrollViewRegular.getChildCount()); 184 TextView child1 = new TextView(mActivity); 185 try { 186 mScrollViewRegular.addView(child1, new ViewGroup.LayoutParams(200, 100)); 187 fail("did not throw IllegalStateException when add more than one child"); 188 } catch (IllegalStateException e) { 189 // expected 190 } 191 assertEquals(1, mScrollViewRegular.getChildCount()); 192 193 mScrollViewRegular.removeAllViews(); 194 child0 = new TextView(mActivity); 195 196 try { 197 mScrollViewRegular.addView(child0, null); 198 fail("did not throw NullPointerException when LayoutParams is null."); 199 } catch (NullPointerException e) { 200 // expected 201 } 202 } 203 204 @UiThreadTest 205 @Test 206 public void testAddViewWithIndexAndLayoutParams() { 207 TextView child0 = new TextView(mActivity); 208 mScrollViewRegular.addView(child0, 0, new ViewGroup.LayoutParams(200, 100)); 209 assertSame(child0, mScrollViewRegular.getChildAt(0)); 210 assertEquals(200, child0.getLayoutParams().width); 211 assertEquals(100, child0.getLayoutParams().height); 212 213 assertEquals(1, mScrollViewRegular.getChildCount()); 214 TextView child1 = new TextView(mActivity); 215 try { 216 mScrollViewRegular.addView(child1, 0, new ViewGroup.LayoutParams(200, 100)); 217 fail("did not throw IllegalStateException when add more than one child"); 218 } catch (IllegalStateException e) { 219 // expected 220 } 221 assertEquals(1, mScrollViewRegular.getChildCount()); 222 223 mScrollViewRegular.removeAllViews(); 224 225 child0 = new TextView(mActivity); 226 try { 227 mScrollViewRegular.addView(child0, null); 228 fail("did not throw NullPointerException when LayoutParams is null."); 229 } catch (NullPointerException e) { 230 // expected 231 } 232 233 mScrollViewRegular.removeAllViews(); 234 235 mScrollViewRegular.addView(child0, -1, new ViewGroup.LayoutParams(300, 150)); 236 assertSame(child0, mScrollViewRegular.getChildAt(0)); 237 assertEquals(300, child0.getLayoutParams().width); 238 assertEquals(150, child0.getLayoutParams().height); 239 240 assertEquals(1, mScrollViewRegular.getChildCount()); 241 child1 = new TextView(mActivity); 242 try { 243 mScrollViewRegular.addView(child1, -1, new ViewGroup.LayoutParams(200, 100)); 244 fail("did not throw IllegalStateException when add more than one child"); 245 } catch (IllegalStateException e) { 246 // expected 247 } 248 assertEquals(1, mScrollViewRegular.getChildCount()); 249 250 mScrollViewRegular.removeAllViews(); 251 252 try { 253 mScrollViewRegular.addView(child0, 1, new ViewGroup.LayoutParams(200, 100)); 254 fail("did not throw IndexOutOfBoundsException when index is larger than 0"); 255 } catch (IndexOutOfBoundsException e) { 256 // expected 257 } 258 } 259 260 @UiThreadTest 261 @Test 262 public void testAccessFillViewport() { 263 assertFalse(mScrollViewRegular.isFillViewport()); 264 mScrollViewRegular.layout(0, 0, 100, 100); 265 assertFalse(mScrollViewRegular.isLayoutRequested()); 266 267 mScrollViewRegular.setFillViewport(false); 268 assertFalse(mScrollViewRegular.isFillViewport()); 269 assertFalse(mScrollViewRegular.isLayoutRequested()); 270 271 mScrollViewRegular.setFillViewport(true); 272 assertTrue(mScrollViewRegular.isFillViewport()); 273 assertTrue(mScrollViewRegular.isLayoutRequested()); 274 275 mScrollViewRegular.layout(0, 0, 100, 100); 276 assertFalse(mScrollViewCustom.isLayoutRequested()); 277 278 mScrollViewRegular.setFillViewport(false); 279 assertFalse(mScrollViewRegular.isFillViewport()); 280 assertTrue(mScrollViewRegular.isLayoutRequested()); 281 } 282 283 @Test 284 public void testAccessSmoothScrollingEnabled() throws Throwable { 285 assertTrue(mScrollViewCustom.isSmoothScrollingEnabled()); 286 287 // scroll immediately 288 mScrollViewCustom.setSmoothScrollingEnabled(false); 289 assertFalse(mScrollViewCustom.isSmoothScrollingEnabled()); 290 291 mActivityRule.runOnUiThread(() -> mScrollViewCustom.fullScroll(View.FOCUS_RIGHT)); 292 assertEquals(SCROLL_RIGHT, mScrollViewCustom.getScrollX()); 293 294 mActivityRule.runOnUiThread(() -> mScrollViewCustom.fullScroll(View.FOCUS_LEFT)); 295 assertEquals(0, mScrollViewCustom.getScrollX()); 296 297 // smooth scroll 298 mScrollViewCustom.setSmoothScrollingEnabled(true); 299 assertTrue(mScrollViewCustom.isSmoothScrollingEnabled()); 300 301 mActivityRule.runOnUiThread(() -> mScrollViewCustom.fullScroll(View.FOCUS_RIGHT)); 302 pollingCheckSmoothScrolling(0, SCROLL_RIGHT, 0, 0); 303 assertEquals(SCROLL_RIGHT, mScrollViewCustom.getScrollX()); 304 305 mActivityRule.runOnUiThread(() -> mScrollViewCustom.fullScroll(View.FOCUS_LEFT)); 306 pollingCheckSmoothScrolling(SCROLL_RIGHT, 0, 0, 0); 307 assertEquals(0, mScrollViewCustom.getScrollX()); 308 } 309 310 @UiThreadTest 311 @Test 312 public void testMeasureChild() { 313 MyView child = new MyView(mActivity); 314 child.setBackgroundDrawable(null); 315 child.setPadding(0, 0, 0, 0); 316 child.setMinimumWidth(30); 317 child.setLayoutParams(new ViewGroup.LayoutParams(100, 100)); 318 child.measure(MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY), 319 MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY)); 320 321 assertEquals(100, child.getMeasuredHeight()); 322 assertEquals(100, child.getMeasuredWidth()); 323 324 ((MyHorizontalScrollView) mScrollViewCustom).measureChild( 325 child, MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY), 326 MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY)); 327 328 assertEquals(100, child.getMeasuredHeight()); 329 assertEquals(30, child.getMeasuredWidth()); 330 } 331 332 @UiThreadTest 333 @Test 334 public void testMeasureChildWithMargins() { 335 MyView child = new MyView(mActivity); 336 child.setBackgroundDrawable(null); 337 child.setPadding(0, 0, 0, 0); 338 child.setMinimumWidth(30); 339 child.setLayoutParams(new ViewGroup.MarginLayoutParams(100, 100)); 340 child.measure(MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY), 341 MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY)); 342 343 assertEquals(100, child.getMeasuredHeight()); 344 assertEquals(100, child.getMeasuredWidth()); 345 346 ((MyHorizontalScrollView) mScrollViewCustom).measureChildWithMargins(child, 347 MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY), 5, 348 MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY), 5); 349 350 assertEquals(100, child.getMeasuredHeight()); 351 assertEquals(30, child.getMeasuredWidth()); 352 } 353 354 @UiThreadTest 355 @Test 356 public void testMeasureSpecs() { 357 MyView child = spy(new MyView(mActivity)); 358 mScrollViewCustomEmpty.addView(child); 359 360 mScrollViewCustomEmpty.measureChild(child, 361 MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY), 362 MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY)); 363 verify(child).onMeasure( 364 eq(MeasureSpec.makeMeasureSpec(100, MeasureSpec.UNSPECIFIED)), 365 eq(MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY))); 366 } 367 368 @UiThreadTest 369 @Test 370 public void testMeasureSpecsWithPadding() { 371 MyView child = spy(new MyView(mActivity)); 372 mScrollViewCustomEmpty.setPadding(3, 5, 7, 11); 373 mScrollViewCustomEmpty.addView(child); 374 375 mScrollViewCustomEmpty.measureChild(child, 376 MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY), 377 MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY)); 378 verify(child).onMeasure( 379 eq(MeasureSpec.makeMeasureSpec(90, MeasureSpec.UNSPECIFIED)), 380 eq(MeasureSpec.makeMeasureSpec(134, MeasureSpec.EXACTLY))); 381 } 382 383 @UiThreadTest 384 @Test 385 public void testMeasureSpecsWithMargins() { 386 MyView child = spy(new MyView(mActivity)); 387 mScrollViewCustomEmpty.addView(child); 388 389 mScrollViewCustomEmpty.measureChildWithMargins(child, 390 MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY), 15, 391 MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY), 20); 392 verify(child).onMeasure( 393 eq(MeasureSpec.makeMeasureSpec(85, MeasureSpec.UNSPECIFIED)), 394 eq(MeasureSpec.makeMeasureSpec(130, MeasureSpec.EXACTLY))); 395 } 396 397 @UiThreadTest 398 @Test 399 public void testMeasureSpecsWithMarginsAndPadding() { 400 MyView child = spy(new MyView(mActivity)); 401 mScrollViewCustomEmpty.setPadding(3, 5, 7, 11); 402 mScrollViewCustomEmpty.addView(child); 403 404 mScrollViewCustomEmpty.measureChildWithMargins(child, 405 MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY), 15, 406 MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY), 20); 407 verify(child).onMeasure( 408 eq(MeasureSpec.makeMeasureSpec(75, MeasureSpec.UNSPECIFIED)), 409 eq(MeasureSpec.makeMeasureSpec(114, MeasureSpec.EXACTLY))); 410 } 411 412 @UiThreadTest 413 @Test 414 public void testMeasureSpecsWithMarginsAndNoHintWidth() { 415 MyView child = spy(new MyView(mActivity)); 416 mScrollViewCustomEmpty.addView(child); 417 418 mScrollViewCustomEmpty.measureChildWithMargins(child, 419 MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), 15, 420 MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY), 20); 421 verify(child).onMeasure( 422 eq(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)), 423 eq(MeasureSpec.makeMeasureSpec(130, MeasureSpec.EXACTLY))); 424 } 425 426 @UiThreadTest 427 @Test 428 public void testFillViewport() { 429 MyView child = new MyView(mActivity); 430 mScrollViewRegular.setFillViewport(true); 431 child.setLayoutParams(new ViewGroup.LayoutParams( 432 ViewGroup.LayoutParams.WRAP_CONTENT, 433 ViewGroup.LayoutParams.WRAP_CONTENT 434 )); 435 436 mScrollViewRegular.addView(child); 437 mScrollViewRegular.measure(MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY), 438 MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY)); 439 440 assertEquals(150, child.getMeasuredWidth()); 441 assertEquals(100, child.getMeasuredHeight()); 442 443 mScrollViewRegular.layout(0, 0, 150, 100); 444 assertEquals(0, child.getLeft()); 445 } 446 447 @UiThreadTest 448 @Test 449 public void testFillViewportWithScrollViewPadding() { 450 mScrollViewRegular.setFillViewport(true); 451 mScrollViewRegular.setPadding(3, 10, 5, 7); 452 453 MyView child = new MyView(mActivity); 454 child.setLayoutParams(new ViewGroup.LayoutParams(10,10)); 455 child.setDesiredWidth(30); 456 457 mScrollViewRegular.addView(child); 458 mScrollViewRegular.measure(MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY), 459 MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY)); 460 461 assertEquals(92, child.getMeasuredWidth()); 462 assertEquals(10, child.getMeasuredHeight()); 463 464 mScrollViewRegular.layout(0, 0, 100, 150); 465 assertEquals(3, child.getLeft()); 466 } 467 468 @UiThreadTest 469 @Test 470 public void testFillViewportWithChildMargins() { 471 mScrollViewRegular.setFillViewport(true); 472 473 MyView child = new MyView(mActivity); 474 FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(10, 10); 475 lp.leftMargin = 3; 476 lp.topMargin = 10; 477 lp.rightMargin = 5; 478 lp.bottomMargin = 7; 479 child.setDesiredWidth(30); 480 child.setLayoutParams(lp); 481 482 mScrollViewRegular.addView(child); 483 mScrollViewRegular.measure(MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY), 484 MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY)); 485 486 assertEquals(92, child.getMeasuredWidth()); 487 assertEquals(10, child.getMeasuredHeight()); 488 489 mScrollViewRegular.layout(0, 0, 100, 150); 490 assertEquals(3, child.getLeft()); 491 } 492 493 @UiThreadTest 494 @Test 495 public void testFillViewportWithScrollViewPaddingAlreadyFills() { 496 mScrollViewRegular.setFillViewport(true); 497 mScrollViewRegular.setPadding(3, 10, 5, 7); 498 499 MyView child = new MyView(mActivity); 500 child.setDesiredWidth(175); 501 502 mScrollViewRegular.addView(child); 503 mScrollViewRegular.measure(MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY), 504 MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY)); 505 506 507 assertEquals(175, child.getMeasuredWidth()); 508 assertEquals(133, child.getMeasuredHeight()); 509 510 mScrollViewRegular.layout(0, 0, 100, 150); 511 assertEquals(3, child.getLeft()); 512 } 513 514 @UiThreadTest 515 @Test 516 public void testFillViewportWithChildMarginsAlreadyFills() { 517 mScrollViewRegular.setFillViewport(true); 518 MyView child = new MyView(mActivity); 519 FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams( 520 ViewGroup.LayoutParams.MATCH_PARENT, 521 ViewGroup.LayoutParams.WRAP_CONTENT); 522 523 lp.leftMargin = 3; 524 lp.topMargin = 10; 525 lp.rightMargin = 5; 526 lp.bottomMargin = 7; 527 child.setLayoutParams(lp); 528 child.setDesiredWidth(175); 529 530 mScrollViewRegular.addView(child); 531 mScrollViewRegular.measure(MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY), 532 MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY)); 533 534 assertEquals(175, child.getMeasuredWidth()); 535 assertEquals(133, child.getMeasuredHeight()); 536 537 mScrollViewRegular.layout(0, 0, 100, 150); 538 assertEquals(3, child.getLeft()); 539 } 540 541 @UiThreadTest 542 @Test 543 public void testPageScroll() { 544 mScrollViewCustom.setSmoothScrollingEnabled(false); 545 assertEquals(0, mScrollViewCustom.getScrollX()); 546 547 assertTrue(mScrollViewCustom.pageScroll(View.FOCUS_RIGHT)); 548 assertEquals(PAGE_WIDTH, mScrollViewCustom.getScrollX()); 549 550 mScrollViewCustom.scrollTo(SCROLL_RIGHT, PAGE_HEIGHT); 551 assertFalse(mScrollViewCustom.pageScroll(View.FOCUS_RIGHT)); 552 assertEquals(SCROLL_RIGHT, mScrollViewCustom.getScrollX()); 553 554 assertTrue(mScrollViewCustom.pageScroll(View.FOCUS_LEFT)); 555 assertEquals(SCROLL_RIGHT - PAGE_WIDTH, mScrollViewCustom.getScrollX()); 556 557 mScrollViewCustom.scrollTo(0, PAGE_HEIGHT); 558 assertFalse(mScrollViewCustom.pageScroll(View.FOCUS_LEFT)); 559 assertEquals(0, mScrollViewCustom.getScrollX()); 560 } 561 562 @UiThreadTest 563 @Test 564 public void testFullScroll() { 565 mScrollViewCustom.setSmoothScrollingEnabled(false); 566 assertEquals(0, mScrollViewCustom.getScrollX()); 567 568 assertTrue(mScrollViewCustom.fullScroll(View.FOCUS_RIGHT)); 569 assertEquals(SCROLL_RIGHT, mScrollViewCustom.getScrollX()); 570 571 assertFalse(mScrollViewCustom.fullScroll(View.FOCUS_RIGHT)); 572 assertEquals(SCROLL_RIGHT, mScrollViewCustom.getScrollX()); 573 574 assertTrue(mScrollViewCustom.fullScroll(View.FOCUS_LEFT)); 575 assertEquals(0, mScrollViewCustom.getScrollX()); 576 577 assertFalse(mScrollViewCustom.fullScroll(View.FOCUS_LEFT)); 578 assertEquals(0, mScrollViewCustom.getScrollX()); 579 } 580 581 @UiThreadTest 582 @Test 583 public void testArrowScroll() { 584 mScrollViewCustom.setSmoothScrollingEnabled(false); 585 assertEquals(0, mScrollViewCustom.getScrollX()); 586 587 int x = mScrollViewCustom.getScrollX(); 588 while (SCROLL_RIGHT != x) { 589 assertTrue(mScrollViewCustom.arrowScroll(View.FOCUS_RIGHT)); 590 assertTrue(x <= mScrollViewCustom.getScrollX()); 591 x = mScrollViewCustom.getScrollX(); 592 } 593 594 assertFalse(mScrollViewCustom.arrowScroll(View.FOCUS_RIGHT)); 595 assertEquals(SCROLL_RIGHT, mScrollViewCustom.getScrollX()); 596 597 x = mScrollViewCustom.getScrollX(); 598 while (0 != x) { 599 assertTrue(mScrollViewCustom.arrowScroll(View.FOCUS_LEFT)); 600 assertTrue(x >= mScrollViewCustom.getScrollX()); 601 x = mScrollViewCustom.getScrollX(); 602 } 603 604 assertFalse(mScrollViewCustom.arrowScroll(View.FOCUS_LEFT)); 605 assertEquals(0, mScrollViewCustom.getScrollX()); 606 } 607 608 @Test 609 public void testSmoothScrollBy() throws Throwable { 610 assertEquals(0, mScrollViewCustom.getScrollX()); 611 assertEquals(0, mScrollViewCustom.getScrollY()); 612 613 mActivityRule.runOnUiThread(() -> mScrollViewCustom.smoothScrollBy(SCROLL_RIGHT, 0)); 614 pollingCheckSmoothScrolling(0, SCROLL_RIGHT, 0, 0); 615 assertEquals(SCROLL_RIGHT, mScrollViewCustom.getScrollX()); 616 assertEquals(0, mScrollViewCustom.getScrollY()); 617 618 mActivityRule.runOnUiThread(() -> mScrollViewCustom.smoothScrollBy(-SCROLL_RIGHT, 0)); 619 pollingCheckSmoothScrolling(SCROLL_RIGHT, 0, 0, 0); 620 assertEquals(0, mScrollViewCustom.getScrollX()); 621 assertEquals(0, mScrollViewCustom.getScrollY()); 622 } 623 624 @Test 625 public void testSmoothScrollTo() throws Throwable { 626 assertEquals(0, mScrollViewCustom.getScrollX()); 627 assertEquals(0, mScrollViewCustom.getScrollY()); 628 629 mActivityRule.runOnUiThread(() -> mScrollViewCustom.smoothScrollTo(SCROLL_RIGHT, 0)); 630 pollingCheckSmoothScrolling(0, SCROLL_RIGHT, 0, 0); 631 assertEquals(SCROLL_RIGHT, mScrollViewCustom.getScrollX()); 632 assertEquals(0, mScrollViewCustom.getScrollY()); 633 634 mActivityRule.runOnUiThread(() -> mScrollViewCustom.smoothScrollTo(0, 0)); 635 pollingCheckSmoothScrolling(SCROLL_RIGHT, 0, 0, 0); 636 assertEquals(0, mScrollViewCustom.getScrollX()); 637 assertEquals(0, mScrollViewCustom.getScrollY()); 638 } 639 640 @Test 641 public void testComputeScrollDeltaToGetChildRectOnScreen() { 642 mScrollViewCustom.setSmoothScrollingEnabled(false); 643 int edge = mScrollViewCustom.getHorizontalFadingEdgeLength(); 644 645 MyHorizontalScrollView myScrollViewCustom = (MyHorizontalScrollView) mScrollViewCustom; 646 647 // Rect's width is smaller than scroll view 648 Rect rect = new Rect(0, 0, 0, 0); 649 assertEquals(0, myScrollViewCustom.computeScrollDeltaToGetChildRectOnScreen(rect)); 650 651 rect = new Rect(edge, 0, PAGE_WIDTH, 0); 652 assertEquals(0, myScrollViewCustom.computeScrollDeltaToGetChildRectOnScreen(rect)); 653 654 mScrollViewCustom.scrollTo(0, 0); 655 rect = new Rect(edge + 1, 0, PAGE_WIDTH, 0); 656 assertEquals(edge, myScrollViewCustom.computeScrollDeltaToGetChildRectOnScreen(rect)); 657 } 658 659 @Test 660 public void testComputeHorizontalScrollRange() { 661 assertTrue(mScrollViewCustom.getChildCount() > 0); 662 assertEquals(ITEM_WIDTH * ITEM_COUNT, 663 ((MyHorizontalScrollView) mScrollViewCustom).computeHorizontalScrollRange()); 664 665 MyHorizontalScrollView scrollView = new MyHorizontalScrollView(mActivity); 666 assertEquals(0, scrollView.getChildCount()); 667 assertEquals(0, scrollView.computeHorizontalScrollRange()); 668 } 669 670 @UiThreadTest 671 @Test 672 public void testRequestChildFocus() { 673 mScrollViewCustom.setSmoothScrollingEnabled(false); 674 675 View firstChild = mScrollViewCustom.findViewById(R.id.first_horizontal_child); 676 View lastChild = mScrollViewCustom.findViewById(R.id.last_horizontal_child); 677 firstChild.requestFocus(); 678 679 int scrollX = mScrollViewCustom.getScrollX(); 680 mScrollViewCustom.requestChildFocus(lastChild, lastChild); 681 // check scrolling to the child which wants focus 682 assertTrue(mScrollViewCustom.getScrollX() > scrollX); 683 684 scrollX = mScrollViewCustom.getScrollX(); 685 mScrollViewCustom.requestChildFocus(firstChild, firstChild); 686 // check scrolling to the child which wants focus 687 assertTrue(mScrollViewCustom.getScrollX() < scrollX); 688 } 689 690 @UiThreadTest 691 @Test 692 public void testRequestChildRectangleOnScreen() { 693 mScrollViewCustom.setSmoothScrollingEnabled(false); 694 int edge = mScrollViewCustom.getHorizontalFadingEdgeLength(); 695 696 View child = mScrollViewCustom.findViewById(R.id.first_horizontal_child); 697 final Rect originalRect = new Rect(0, 0, 10, 10); 698 final Rect newRect = new Rect(ITEM_WIDTH - 10, ITEM_HEIGHT - 10, ITEM_WIDTH, ITEM_HEIGHT); 699 700 assertFalse(mScrollViewCustom.requestChildRectangleOnScreen(child, originalRect, true)); 701 assertEquals(0, mScrollViewCustom.getScrollX()); 702 assertEquals(0, mScrollViewCustom.getScrollY()); 703 704 assertTrue(mScrollViewCustom.requestChildRectangleOnScreen(child, newRect, true)); 705 assertEquals(ITEM_WIDTH - mScrollViewCustom.getWidth() + edge, mScrollViewCustom.getScrollX()); 706 assertEquals(0, mScrollViewCustom.getScrollY()); 707 } 708 709 @UiThreadTest 710 @Test 711 public void testRequestLayout() { 712 mScrollViewCustom.requestLayout(); 713 714 assertTrue(mScrollViewCustom.isLayoutRequested()); 715 } 716 717 @Test 718 public void testFling() throws Throwable { 719 mScrollViewCustom.setSmoothScrollingEnabled(true); 720 assertEquals(0, mScrollViewCustom.getScrollX()); 721 722 final int velocityX = WidgetTestUtils.convertDipToPixels(mActivity, 2000); 723 724 // fling towards right 725 mActivityRule.runOnUiThread(() -> mScrollViewCustom.fling(velocityX)); 726 pollingCheckFling(0, true); 727 728 final int currentX = mScrollViewCustom.getScrollX(); 729 // fling towards left 730 mActivityRule.runOnUiThread(() -> mScrollViewCustom.fling(-velocityX)); 731 pollingCheckFling(currentX, false); 732 } 733 734 @UiThreadTest 735 @Test 736 public void testScrollTo() { 737 mScrollViewCustom.setSmoothScrollingEnabled(false); 738 739 mScrollViewCustom.scrollTo(10, 10); 740 assertEquals(0, mScrollViewCustom.getScrollY()); 741 assertEquals(10, mScrollViewCustom.getScrollX()); 742 743 mScrollViewCustom.scrollTo(PAGE_WIDTH, PAGE_HEIGHT); 744 assertEquals(0, mScrollViewCustom.getScrollY()); 745 assertEquals(PAGE_WIDTH, mScrollViewCustom.getScrollX()); 746 747 mScrollViewCustom.scrollTo(SCROLL_RIGHT, 0); 748 assertEquals(0, mScrollViewCustom.getScrollY()); 749 assertEquals(SCROLL_RIGHT, mScrollViewCustom.getScrollX()); 750 751 // reach the top and left 752 mScrollViewCustom.scrollTo(-10, -10); 753 assertEquals(0, mScrollViewCustom.getScrollY()); 754 assertEquals(0, mScrollViewCustom.getScrollX()); 755 } 756 757 @Test 758 public void testGetHorizontalFadingEdgeStrengths() { 759 MyHorizontalScrollView myScrollViewCustom = (MyHorizontalScrollView) mScrollViewCustom; 760 761 assertTrue(mScrollViewCustom.getChildCount() > 0); 762 assertTrue(myScrollViewCustom.getLeftFadingEdgeStrength() <= 1.0f); 763 assertTrue(myScrollViewCustom.getLeftFadingEdgeStrength() >= 0.0f); 764 assertTrue(myScrollViewCustom.getRightFadingEdgeStrength() <= 1.0f); 765 assertTrue(myScrollViewCustom.getRightFadingEdgeStrength() >= 0.0f); 766 767 MyHorizontalScrollView myScrollView = new MyHorizontalScrollView(mActivity); 768 assertEquals(0, myScrollView.getChildCount()); 769 assertTrue(myScrollViewCustom.getLeftFadingEdgeStrength() <= 1.0f); 770 assertTrue(myScrollViewCustom.getLeftFadingEdgeStrength() >= 0.0f); 771 assertTrue(myScrollViewCustom.getRightFadingEdgeStrength() <= 1.0f); 772 assertTrue(myScrollViewCustom.getRightFadingEdgeStrength() >= 0.0f); 773 } 774 775 @UiThreadTest 776 @Test 777 public void testEdgeEffectColors() { 778 int defaultColor = new EdgeEffect(mScrollViewRegular.getContext()).getColor(); 779 assertEquals(mScrollViewRegular.getLeftEdgeEffectColor(), defaultColor); 780 assertEquals(mScrollViewRegular.getRightEdgeEffectColor(), defaultColor); 781 782 mScrollViewRegular.setEdgeEffectColor(Color.BLUE); 783 assertEquals(mScrollViewRegular.getLeftEdgeEffectColor(), Color.BLUE); 784 assertEquals(mScrollViewRegular.getRightEdgeEffectColor(), Color.BLUE); 785 786 mScrollViewRegular.setLeftEdgeEffectColor(Color.RED); 787 assertEquals(mScrollViewRegular.getLeftEdgeEffectColor(), Color.RED); 788 assertEquals(mScrollViewRegular.getRightEdgeEffectColor(), Color.BLUE); 789 790 mScrollViewRegular.setRightEdgeEffectColor(Color.GREEN); 791 assertEquals(mScrollViewRegular.getLeftEdgeEffectColor(), Color.RED); 792 assertEquals(mScrollViewRegular.getRightEdgeEffectColor(), Color.GREEN); 793 } 794 795 private boolean isInRange(int current, int from, int to) { 796 if (from < to) { 797 return current >= from && current <= to; 798 } 799 return current <= from && current >= to; 800 } 801 802 private void pollingCheckSmoothScrolling(final int fromX, final int toX, 803 final int fromY, final int toY) { 804 805 if (fromX == toX && fromY == toY) { 806 return; 807 } 808 809 if (fromY != toY) { 810 PollingCheck.waitFor(() -> isInRange(mScrollViewCustom.getScrollY(), fromY, toY)); 811 } 812 813 if (fromX != toX) { 814 PollingCheck.waitFor(() -> isInRange(mScrollViewCustom.getScrollX(), fromX, toX)); 815 } 816 817 PollingCheck.waitFor( 818 () -> toX == mScrollViewCustom.getScrollX() && toY == mScrollViewCustom.getScrollY()); 819 } 820 821 private void pollingCheckFling(final int startPosition, final boolean movingRight) { 822 PollingCheck.waitFor(() -> { 823 if (movingRight) { 824 return mScrollViewCustom.getScrollX() > startPosition; 825 } 826 return mScrollViewCustom.getScrollX() < startPosition; 827 }); 828 829 final int[] previousScrollX = new int[] { mScrollViewCustom.getScrollX() }; 830 PollingCheck.waitFor(() -> { 831 if (mScrollViewCustom.getScrollX() == previousScrollX[0]) { 832 return true; 833 } else { 834 previousScrollX[0] = mScrollViewCustom.getScrollX(); 835 return false; 836 } 837 }); 838 } 839 840 public static class MyView extends View { 841 // measure in this height if set 842 private Integer mDesiredWidth; 843 public MyView(Context context) { 844 super(context); 845 } 846 847 public void setDesiredWidth(Integer desiredWidth) { 848 mDesiredWidth = desiredWidth; 849 } 850 851 @Override 852 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 853 super.onMeasure(widthMeasureSpec, heightMeasureSpec); 854 if (mDesiredWidth != null) { 855 int mode = MeasureSpec.getMode(widthMeasureSpec); 856 int size = MeasureSpec.getSize(widthMeasureSpec); 857 int newWidth = size; 858 if (mode == MeasureSpec.AT_MOST) { 859 newWidth = Math.max(size, mDesiredWidth); 860 } else if (mode == MeasureSpec.UNSPECIFIED) { 861 newWidth = mDesiredWidth; 862 } 863 setMeasuredDimension(newWidth, getMeasuredHeight()); 864 } 865 } 866 } 867 868 public static class MyHorizontalScrollView extends HorizontalScrollView { 869 public MyHorizontalScrollView(Context context) { 870 super(context); 871 } 872 873 public MyHorizontalScrollView(Context context, AttributeSet attrs) { 874 super(context, attrs); 875 } 876 877 public MyHorizontalScrollView(Context context, AttributeSet attrs, int defStyle) { 878 super(context, attrs, defStyle); 879 } 880 881 @Override 882 protected int computeHorizontalScrollRange() { 883 return super.computeHorizontalScrollRange(); 884 } 885 886 @Override 887 protected int computeScrollDeltaToGetChildRectOnScreen(Rect rect) { 888 return super.computeScrollDeltaToGetChildRectOnScreen(rect); 889 } 890 891 @Override 892 protected float getLeftFadingEdgeStrength() { 893 return super.getLeftFadingEdgeStrength(); 894 } 895 896 @Override 897 protected float getRightFadingEdgeStrength() { 898 return super.getRightFadingEdgeStrength(); 899 } 900 901 @Override 902 protected void measureChild(View child, int parentWidthMeasureSpec, 903 int parentHeightMeasureSpec) { 904 super.measureChild(child, parentWidthMeasureSpec, parentHeightMeasureSpec); 905 } 906 907 @Override 908 protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed, 909 int parentHeightMeasureSpec, int heightUsed) { 910 super.measureChildWithMargins(child, parentWidthMeasureSpec, 911 widthUsed, parentHeightMeasureSpec, heightUsed); 912 } 913 914 @Override 915 public int computeVerticalScrollRange() { 916 return super.computeVerticalScrollRange(); 917 } 918 919 @Override 920 public int computeVerticalScrollOffset() { 921 return super.computeVerticalScrollOffset(); 922 } 923 924 @Override 925 public int computeVerticalScrollExtent() { 926 return super.computeVerticalScrollExtent(); 927 } 928 } 929 } 930