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