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