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.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