blob: 3abb023e7a0936ae27ceb09f2bb3402a8c60a8f6 [file] [log] [blame]
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.widget.cts;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import android.app.Activity;
import android.app.Instrumentation;
import android.content.Context;
import android.graphics.Rect;
import android.support.test.InstrumentationRegistry;
import android.support.test.annotation.UiThreadTest;
import android.support.test.filters.MediumTest;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.util.AttributeSet;
import android.util.Xml;
import android.view.View;
import android.view.View.MeasureSpec;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.cts.util.TestUtils;
import com.android.compatibility.common.util.PollingCheck;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.xmlpull.v1.XmlPullParser;
/**
* Test {@link ScrollView}.
*/
@MediumTest
@RunWith(AndroidJUnit4.class)
public class ScrollViewTest {
// view dpi constants. Must match those defined in scroll_view layout
private static final int ITEM_WIDTH_DPI = 250;
private static final int ITEM_HEIGHT_DPI = 100;
private static final int ITEM_COUNT = 15;
private static final int PAGE_WIDTH_DPI = 100;
private static final int PAGE_HEIGHT_DPI = 100;
private static final int TOLERANCE = 2;
private int mItemWidth;
private int mItemHeight;
private int mPageWidth;
private int mPageHeight;
private int mScrollBottom;
private int mScrollRight;
private Instrumentation mInstrumentation;
private Activity mActivity;
private ScrollView mScrollViewRegular;
private ScrollView mScrollViewCustom;
private MyScrollView mScrollViewCustomEmpty;
@Rule
public ActivityTestRule<ScrollViewCtsActivity> mActivityRule =
new ActivityTestRule<>(ScrollViewCtsActivity.class);
@Before
public void setup() {
mInstrumentation = InstrumentationRegistry.getInstrumentation();
mActivity = mActivityRule.getActivity();
mScrollViewRegular = (ScrollView) mActivity.findViewById(R.id.scroll_view_regular);
mScrollViewCustom = (ScrollView) mActivity.findViewById(R.id.scroll_view_custom);
mScrollViewCustomEmpty = (MyScrollView) mActivity.findViewById(
R.id.scroll_view_custom_empty);
// calculate pixel positions from dpi constants.
mItemWidth = TestUtils.dpToPx(mActivity, ITEM_WIDTH_DPI);
mItemHeight = TestUtils.dpToPx(mActivity, ITEM_HEIGHT_DPI);
mPageWidth = TestUtils.dpToPx(mActivity, PAGE_WIDTH_DPI);
mPageHeight = TestUtils.dpToPx(mActivity, PAGE_HEIGHT_DPI);
mScrollBottom = mItemHeight * ITEM_COUNT - mPageHeight;
mScrollRight = mItemWidth - mPageWidth;
}
@Test
public void testConstructor() {
XmlPullParser parser = mActivity.getResources().getLayout(R.layout.scrollview_layout);
AttributeSet attrs = Xml.asAttributeSet(parser);
new ScrollView(mActivity);
new ScrollView(mActivity, attrs);
new ScrollView(mActivity, attrs, 0);
}
@UiThreadTest
@Test
public void testGetMaxScrollAmount() {
// the value is half of total layout height
mScrollViewRegular.layout(0, 0, 100, 200);
assertEquals((200 - 0) / 2, mScrollViewRegular.getMaxScrollAmount());
mScrollViewRegular.layout(0, 0, 150, 100);
assertEquals((100 - 0) / 2, mScrollViewRegular.getMaxScrollAmount());
}
@UiThreadTest
@Test
public void testAddView() {
TextView child0 = new TextView(mActivity);
mScrollViewRegular.addView(child0);
assertSame(child0, mScrollViewRegular.getChildAt(0));
assertEquals(1, mScrollViewRegular.getChildCount());
TextView child1 = new TextView(mActivity);
try {
mScrollViewRegular.addView(child1);
fail("ScrollView can host only one direct child");
} catch (IllegalStateException e) {
// expected
}
assertEquals(1, mScrollViewRegular.getChildCount());
}
@UiThreadTest
@Test
public void testAddViewWithIndex() {
TextView child0 = new TextView(mActivity);
mScrollViewRegular.addView(child0, 0);
assertSame(child0, mScrollViewRegular.getChildAt(0));
assertEquals(1, mScrollViewRegular.getChildCount());
TextView child1 = new TextView(mActivity);
try {
mScrollViewRegular.addView(child1, 1);
fail("ScrollView can host only one direct child");
} catch (IllegalStateException e) {
// expected
}
assertEquals(1, mScrollViewRegular.getChildCount());
mScrollViewRegular.removeAllViews();
mScrollViewRegular = new ScrollView(mActivity);
mScrollViewRegular.addView(child0, -1);
assertSame(child0, mScrollViewRegular.getChildAt(0));
assertEquals(1, mScrollViewRegular.getChildCount());
child1 = new TextView(mActivity);
try {
mScrollViewRegular.addView(child1, -1);
fail("ScrollView can host only one direct child");
} catch (IllegalStateException e) {
// expected
}
assertEquals(1, mScrollViewRegular.getChildCount());
mScrollViewRegular.removeAllViews();
mScrollViewRegular = new ScrollView(mActivity);
try {
mScrollViewRegular.addView(child0, 1);
fail("ScrollView can host only one direct child");
} catch (IndexOutOfBoundsException e) {
// expected
}
}
@UiThreadTest
@Test
public void testAddViewWithLayoutParams() {
TextView child0 = new TextView(mActivity);
mScrollViewRegular.addView(child0, new ViewGroup.LayoutParams(200, 100));
assertSame(child0, mScrollViewRegular.getChildAt(0));
assertEquals(200, child0.getLayoutParams().width);
assertEquals(100, child0.getLayoutParams().height);
assertEquals(1, mScrollViewRegular.getChildCount());
TextView child1 = new TextView(mActivity);
try {
mScrollViewRegular.addView(child1, new ViewGroup.LayoutParams(200, 100));
fail("ScrollView can host only one direct child");
} catch (IllegalStateException e) {
// expected
}
assertEquals(1, mScrollViewRegular.getChildCount());
mScrollViewRegular.removeAllViews();
mScrollViewRegular = new ScrollView(mActivity);
child0 = new TextView(mActivity);
try {
mScrollViewRegular.addView(child0, null);
fail("The LayoutParams should not be null!");
} catch (NullPointerException e) {
// expected
}
}
@UiThreadTest
@Test
public void testAddViewWithIndexAndLayoutParams() {
TextView child0 = new TextView(mActivity);
mScrollViewRegular.addView(child0, 0, new ViewGroup.LayoutParams(200, 100));
assertSame(child0, mScrollViewRegular.getChildAt(0));
assertEquals(200, child0.getLayoutParams().width);
assertEquals(100, child0.getLayoutParams().height);
assertEquals(1, mScrollViewRegular.getChildCount());
TextView child1 = new TextView(mActivity);
try {
mScrollViewRegular.addView(child1, 0, new ViewGroup.LayoutParams(200, 100));
fail("ScrollView can host only one direct child");
} catch (IllegalStateException e) {
// expected
}
assertEquals(1, mScrollViewRegular.getChildCount());
mScrollViewRegular.removeAllViews();
child0 = new TextView(mActivity);
try {
mScrollViewRegular.addView(child0, null);
fail("The LayoutParams should not be null!");
} catch (NullPointerException e) {
// expected
}
mScrollViewRegular.removeAllViews();
mScrollViewRegular.addView(child0, -1, new ViewGroup.LayoutParams(300, 150));
assertSame(child0, mScrollViewRegular.getChildAt(0));
assertEquals(300, child0.getLayoutParams().width);
assertEquals(150, child0.getLayoutParams().height);
assertEquals(1, mScrollViewRegular.getChildCount());
child1 = new TextView(mActivity);
try {
mScrollViewRegular.addView(child1, -1, new ViewGroup.LayoutParams(200, 100));
fail("ScrollView can host only one direct child");
} catch (IllegalStateException e) {
// expected
}
assertEquals(1, mScrollViewRegular.getChildCount());
mScrollViewRegular.removeAllViews();
try {
mScrollViewRegular.addView(child0, 1, new ViewGroup.LayoutParams(200, 100));
fail("ScrollView can host only one direct child");
} catch (IndexOutOfBoundsException e) {
// expected
}
}
@UiThreadTest
@Test
public void testAccessFillViewport() {
assertFalse(mScrollViewRegular.isFillViewport());
mScrollViewRegular.layout(0, 0, 100, 100);
assertFalse(mScrollViewRegular.isLayoutRequested());
mScrollViewRegular.setFillViewport(false);
assertFalse(mScrollViewRegular.isFillViewport());
assertFalse(mScrollViewRegular.isLayoutRequested());
mScrollViewRegular.setFillViewport(true);
assertTrue(mScrollViewRegular.isFillViewport());
assertTrue(mScrollViewRegular.isLayoutRequested());
mScrollViewRegular.layout(0, 0, 100, 100);
assertFalse(mScrollViewRegular.isLayoutRequested());
mScrollViewRegular.setFillViewport(false);
assertFalse(mScrollViewRegular.isFillViewport());
assertTrue(mScrollViewRegular.isLayoutRequested());
}
@Test
public void testAccessSmoothScrollingEnabled() throws Throwable {
assertTrue(mScrollViewCustom.isSmoothScrollingEnabled());
// scroll immediately
mScrollViewCustom.setSmoothScrollingEnabled(false);
assertFalse(mScrollViewCustom.isSmoothScrollingEnabled());
mActivityRule.runOnUiThread(() -> mScrollViewCustom.fullScroll(View.FOCUS_DOWN));
assertEquals(mScrollBottom, mScrollViewCustom.getScrollY(), TOLERANCE);
mActivityRule.runOnUiThread(() -> mScrollViewCustom.fullScroll(View.FOCUS_UP));
assertEquals(0, mScrollViewCustom.getScrollY());
// smooth scroll
mScrollViewCustom.setSmoothScrollingEnabled(true);
assertTrue(mScrollViewCustom.isSmoothScrollingEnabled());
mActivityRule.runOnUiThread(() -> mScrollViewCustom.fullScroll(View.FOCUS_DOWN));
pollingCheckSmoothScrolling(0, 0, 0, mScrollBottom);
assertEquals(mScrollBottom, mScrollViewCustom.getScrollY(), TOLERANCE);
mActivityRule.runOnUiThread(() -> mScrollViewCustom.fullScroll(View.FOCUS_UP));
pollingCheckSmoothScrolling(0, 0, mScrollBottom, 0);
assertEquals(0, mScrollViewCustom.getScrollY());
}
@UiThreadTest
@Test
public void testMeasureChild() {
MyView child = new MyView(mActivity);
child.setBackgroundDrawable(null);
child.setPadding(0, 0, 0, 0);
child.setMinimumHeight(30);
child.setLayoutParams(new ViewGroup.LayoutParams(100, 100));
child.measure(MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY));
assertEquals(100, child.getMeasuredHeight());
assertEquals(100, child.getMeasuredWidth());
mScrollViewCustomEmpty.measureChild(child,
MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY));
assertEquals(30, child.getMeasuredHeight());
assertEquals(100, child.getMeasuredWidth());
}
@UiThreadTest
@Test
public void testMeasureChildWithMargins() {
MyView child = new MyView(mActivity);
child.setBackgroundDrawable(null);
child.setPadding(0, 0, 0, 0);
child.setMinimumHeight(30);
child.setLayoutParams(new ViewGroup.MarginLayoutParams(100, 100));
child.measure(MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY));
assertEquals(100, child.getMeasuredHeight());
assertEquals(100, child.getMeasuredWidth());
mScrollViewCustomEmpty.measureChildWithMargins(child,
MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY), 5,
MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY), 5);
assertEquals(30, child.getMeasuredHeight());
assertEquals(100, child.getMeasuredWidth());
}
@UiThreadTest
@Test
public void testMeasureSpecs() {
MyView child = spy(new MyView(mActivity));
mScrollViewCustomEmpty.addView(child);
mScrollViewCustomEmpty.measureChild(child,
MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY));
verify(child).onMeasure(
eq(MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY)),
eq(MeasureSpec.makeMeasureSpec(100, MeasureSpec.UNSPECIFIED)));
}
@UiThreadTest
@Test
public void testMeasureSpecsWithPadding() {
MyView child = spy(new MyView(mActivity));
mScrollViewCustomEmpty.setPadding(3, 5, 7, 11);
mScrollViewCustomEmpty.addView(child);
mScrollViewCustomEmpty.measureChild(child,
MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY));
verify(child).onMeasure(
eq(MeasureSpec.makeMeasureSpec(140, MeasureSpec.EXACTLY)),
eq(MeasureSpec.makeMeasureSpec(84, MeasureSpec.UNSPECIFIED)));
}
@UiThreadTest
@Test
public void testMeasureSpecsWithMargins() {
MyView child = spy(new MyView(mActivity));
mScrollViewCustomEmpty.addView(child);
mScrollViewCustomEmpty.measureChildWithMargins(child,
MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY), 20,
MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY), 15);
verify(child).onMeasure(
eq(MeasureSpec.makeMeasureSpec(130, MeasureSpec.EXACTLY)),
eq(MeasureSpec.makeMeasureSpec(85, MeasureSpec.UNSPECIFIED)));
}
@UiThreadTest
@Test
public void testMeasureSpecsWithMarginsAndPadding() {
MyView child = spy(new MyView(mActivity));
mScrollViewCustomEmpty.setPadding(3, 5, 7, 11);
mScrollViewCustomEmpty.addView(child);
mScrollViewCustomEmpty.measureChildWithMargins(child,
MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY), 20,
MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY), 15);
verify(child).onMeasure(
eq(MeasureSpec.makeMeasureSpec(120, MeasureSpec.EXACTLY)),
eq(MeasureSpec.makeMeasureSpec(69, MeasureSpec.UNSPECIFIED)));
}
@UiThreadTest
@Test
public void testMeasureSpecsWithMarginsAndNoHintWidth() {
MyView child = spy(new MyView(mActivity));
mScrollViewCustomEmpty.addView(child);
mScrollViewCustomEmpty.measureChildWithMargins(child,
MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY), 20,
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), 15);
verify(child).onMeasure(
eq(MeasureSpec.makeMeasureSpec(130, MeasureSpec.EXACTLY)),
eq(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)));
}
@UiThreadTest
@Test
public void testFillViewport() {
mScrollViewRegular.setFillViewport(true);
MyView child = new MyView(mActivity);
child.setLayoutParams(new ViewGroup.LayoutParams(100, 100));
mScrollViewRegular.addView(child);
mScrollViewRegular.measure(
MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY));
assertEquals(150, child.getMeasuredHeight());
assertEquals(100, child.getMeasuredWidth());
mScrollViewRegular.layout(0, 0, 100, 150);
assertEquals(0, child.getTop());
}
@UiThreadTest
@Test
public void testFillViewportWithScrollViewPadding() {
mScrollViewRegular.setFillViewport(true);
mScrollViewRegular.setPadding(3, 10, 5, 7);
MyView child = new MyView(mActivity);
child.setLayoutParams(new ViewGroup.LayoutParams(10,10));
child.setDesiredHeight(30);
mScrollViewRegular.addView(child);
mScrollViewRegular.measure(
MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY));
assertEquals(133, child.getMeasuredHeight());
assertEquals(10, child.getMeasuredWidth());
mScrollViewRegular.layout(0, 0, 100, 150);
assertEquals(10, child.getTop());
}
@UiThreadTest
@Test
public void testFillViewportWithChildMargins() {
mScrollViewRegular.setFillViewport(true);
MyView child = new MyView(mActivity);
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(10, 10);
lp.leftMargin = 3;
lp.topMargin = 10;
lp.rightMargin = 5;
lp.bottomMargin = 7;
child.setDesiredHeight(30);
child.setLayoutParams(lp);
mScrollViewRegular.addView(child);
mScrollViewRegular.measure(MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY));
assertEquals(133, child.getMeasuredHeight());
assertEquals(10, child.getMeasuredWidth());
mScrollViewRegular.layout(0, 0, 100, 150);
assertEquals(10, child.getTop());
}
@UiThreadTest
@Test
public void testFillViewportWithScrollViewPaddingAlreadyFills() {
mScrollViewRegular.setFillViewport(true);
mScrollViewRegular.setPadding(3, 10, 5, 7);
MyView child = new MyView(mActivity);
child.setDesiredHeight(175);
mScrollViewRegular.addView(child);
mScrollViewRegular.measure(MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY));
assertEquals(92, child.getMeasuredWidth());
assertEquals(175, child.getMeasuredHeight());
mScrollViewRegular.layout(0, 0, 100, 150);
assertEquals(10, child.getTop());
}
@UiThreadTest
@Test
public void testFillViewportWithChildMarginsAlreadyFills() {
mScrollViewRegular.setFillViewport(true);
MyView child = new MyView(mActivity);
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
lp.leftMargin = 3;
lp.topMargin = 10;
lp.rightMargin = 5;
lp.bottomMargin = 7;
child.setLayoutParams(lp);
child.setDesiredHeight(175);
mScrollViewRegular.addView(child);
mScrollViewRegular.measure(MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY));
assertEquals(92, child.getMeasuredWidth());
assertEquals(175, child.getMeasuredHeight());
mScrollViewRegular.layout(0, 0, 100, 150);
assertEquals(10, child.getTop());
}
@UiThreadTest
@Test
public void testPageScroll() {
mScrollViewCustom.setSmoothScrollingEnabled(false);
assertEquals(0, mScrollViewCustom.getScrollY());
assertTrue(mScrollViewCustom.pageScroll(View.FOCUS_DOWN));
assertEquals(mPageHeight, mScrollViewCustom.getScrollY(), TOLERANCE);
assertTrue(mScrollViewCustom.pageScroll(View.FOCUS_DOWN));
assertEquals(mPageHeight * 2, mScrollViewCustom.getScrollY(), TOLERANCE);
mScrollViewCustom.scrollTo(mPageWidth, mScrollBottom);
assertFalse(mScrollViewCustom.pageScroll(View.FOCUS_DOWN));
assertEquals(mScrollBottom, mScrollViewCustom.getScrollY(), TOLERANCE);
assertTrue(mScrollViewCustom.pageScroll(View.FOCUS_UP));
assertEquals(mScrollBottom - mPageHeight, mScrollViewCustom.getScrollY(), TOLERANCE);
assertTrue(mScrollViewCustom.pageScroll(View.FOCUS_UP));
assertEquals(mScrollBottom -mPageHeight * 2, mScrollViewCustom.getScrollY(), TOLERANCE);
mScrollViewCustom.scrollTo(mPageWidth, 0);
assertFalse(mScrollViewCustom.pageScroll(View.FOCUS_UP));
assertEquals(0, mScrollViewCustom.getScrollY());
}
@UiThreadTest
@Test
public void testFullScroll() {
mScrollViewCustom.setSmoothScrollingEnabled(false);
assertEquals(0, mScrollViewCustom.getScrollY());
assertTrue(mScrollViewCustom.fullScroll(View.FOCUS_DOWN));
assertEquals(mScrollBottom, mScrollViewCustom.getScrollY());
assertFalse(mScrollViewCustom.fullScroll(View.FOCUS_DOWN));
assertEquals(mScrollBottom, mScrollViewCustom.getScrollY());
assertTrue(mScrollViewCustom.fullScroll(View.FOCUS_UP));
assertEquals(0, mScrollViewCustom.getScrollY());
assertFalse(mScrollViewCustom.fullScroll(View.FOCUS_UP));
assertEquals(0, mScrollViewCustom.getScrollY());
}
@UiThreadTest
@Test
public void testArrowScroll() {
mScrollViewCustom.setSmoothScrollingEnabled(false);
assertEquals(0, mScrollViewCustom.getScrollY());
int y = mScrollViewCustom.getScrollY();
while (mScrollBottom != y) {
assertTrue(mScrollViewCustom.arrowScroll(View.FOCUS_DOWN));
assertTrue(y <= mScrollViewCustom.getScrollY());
y = mScrollViewCustom.getScrollY();
}
assertFalse(mScrollViewCustom.arrowScroll(View.FOCUS_DOWN));
assertEquals(mScrollBottom, mScrollViewCustom.getScrollY());
y = mScrollViewCustom.getScrollY();
while (0 != y) {
assertTrue(mScrollViewCustom.arrowScroll(View.FOCUS_UP));
assertTrue(y >= mScrollViewCustom.getScrollY());
y = mScrollViewCustom.getScrollY();
}
assertFalse(mScrollViewCustom.arrowScroll(View.FOCUS_UP));
assertEquals(0, mScrollViewCustom.getScrollY());
}
@Test
public void testSmoothScrollBy() throws Throwable {
assertEquals(0, mScrollViewCustom.getScrollX());
assertEquals(0, mScrollViewCustom.getScrollY());
mActivityRule.runOnUiThread(
() -> mScrollViewCustom.smoothScrollBy(mScrollRight, mScrollBottom));
// smoothScrollBy doesn't scroll in X
pollingCheckSmoothScrolling(0, 0, 0, mScrollBottom);
assertEquals(0, mScrollViewCustom.getScrollX());
assertEquals(mScrollBottom, mScrollViewCustom.getScrollY());
mActivityRule.runOnUiThread(
() -> mScrollViewCustom.smoothScrollBy(-mScrollRight, -mScrollBottom));
pollingCheckSmoothScrolling(mScrollRight, 0, mScrollBottom, 0);
assertEquals(0, mScrollViewCustom.getScrollX());
assertEquals(0, mScrollViewCustom.getScrollY());
}
@Test
public void testSmoothScrollTo() throws Throwable {
assertEquals(0, mScrollViewCustom.getScrollX());
assertEquals(0, mScrollViewCustom.getScrollY());
mActivityRule.runOnUiThread(
() -> mScrollViewCustom.smoothScrollTo(mScrollRight, mScrollBottom));
// smoothScrollTo doesn't scroll in X
pollingCheckSmoothScrolling(0, 0, 0, mScrollBottom);
assertEquals(0, mScrollViewCustom.getScrollX());
assertEquals(mScrollBottom, mScrollViewCustom.getScrollY());
mActivityRule.runOnUiThread(
() -> mScrollViewCustom.smoothScrollTo(mPageWidth, mPageHeight));
pollingCheckSmoothScrolling(0, 0, mScrollBottom, mPageHeight);
assertEquals(0, mScrollViewCustom.getScrollX());
assertEquals(mPageHeight, mScrollViewCustom.getScrollY());
}
@UiThreadTest
@Test
public void testComputeScrollDeltaToGetChildRectOnScreen() {
mScrollViewCustom.setSmoothScrollingEnabled(false);
int edge = mScrollViewCustom.getVerticalFadingEdgeLength();
// Rect's height is smaller than scroll view
Rect rect = new Rect(0, 0, 0, 0);
assertEquals(0,
((MyScrollView) mScrollViewCustom).computeScrollDeltaToGetChildRectOnScreen(rect));
rect = new Rect(0, edge, 0, mPageHeight);
assertEquals(0,
((MyScrollView) mScrollViewCustom).computeScrollDeltaToGetChildRectOnScreen(rect));
mScrollViewCustom.scrollTo(0, 0);
rect = new Rect(0, edge + 1, 0, mPageHeight);
assertEquals(edge,
((MyScrollView) mScrollViewCustom).computeScrollDeltaToGetChildRectOnScreen(rect));
}
@UiThreadTest
@Test
public void testComputeVerticalScrollRange() {
assertTrue(mScrollViewCustom.getChildCount() > 0);
assertEquals(mItemHeight * ITEM_COUNT,
((MyScrollView) mScrollViewCustom).computeVerticalScrollRange(), TOLERANCE);
MyScrollView myScrollView = new MyScrollView(mActivity);
assertEquals(0, myScrollView.getChildCount());
assertEquals(0, myScrollView.computeVerticalScrollRange());
}
@UiThreadTest
@Test
public void testRequestChildFocus() {
mScrollViewCustom.setSmoothScrollingEnabled(false);
View firstChild = mScrollViewCustom.findViewById(R.id.first_child);
View lastChild = mScrollViewCustom.findViewById(R.id.last_child);
firstChild.requestFocus();
int scrollY = mScrollViewCustom.getScrollY();
mScrollViewCustom.requestChildFocus(lastChild, lastChild);
// check scrolling to the child which wants focus
assertTrue(mScrollViewCustom.getScrollY() > scrollY);
scrollY = mScrollViewCustom.getScrollY();
mScrollViewCustom.requestChildFocus(firstChild, firstChild);
// check scrolling to the child which wants focus
assertTrue(mScrollViewCustom.getScrollY() < scrollY);
}
@UiThreadTest
@Test
public void testRequestChildRectangleOnScreen() {
mScrollViewCustom.setSmoothScrollingEnabled(false);
mScrollViewCustom.setVerticalFadingEdgeEnabled(true);
int edge = mScrollViewCustom.getVerticalFadingEdgeLength();
View child = mScrollViewCustom.findViewById(R.id.first_child);
int orgRectSize = (int)(10 * mActivity.getResources().getDisplayMetrics().density);
final Rect originalRect = new Rect(0, 0, orgRectSize, orgRectSize);
final Rect newRect = new Rect(mItemWidth - orgRectSize, mItemHeight - orgRectSize,
mItemWidth, mItemHeight);
assertFalse(mScrollViewCustom.requestChildRectangleOnScreen(child, originalRect, true));
assertEquals(0, mScrollViewCustom.getScrollX());
assertEquals(0, mScrollViewCustom.getScrollY());
assertTrue(mScrollViewCustom.requestChildRectangleOnScreen(child, newRect, true));
assertEquals(0, mScrollViewCustom.getScrollX());
assertEquals(edge, mScrollViewCustom.getScrollY());
}
@UiThreadTest
@Test
public void testRequestLayout() {
mScrollViewCustom.requestLayout();
assertTrue(mScrollViewCustom.isLayoutRequested());
}
@Test
public void testFling() throws Throwable {
mScrollViewCustom.setSmoothScrollingEnabled(true);
assertEquals(0, mScrollViewCustom.getScrollY());
// fling towards bottom
mActivityRule.runOnUiThread(() -> mScrollViewCustom.fling(2000));
pollingCheckFling(0, true);
final int currentY = mScrollViewCustom.getScrollY();
// fling towards top
mActivityRule.runOnUiThread(() -> mScrollViewCustom.fling(-2000));
pollingCheckFling(currentY, false);
}
@UiThreadTest
@Test
public void testScrollTo() {
mScrollViewCustom.setSmoothScrollingEnabled(false);
mScrollViewCustom.scrollTo(10, 10);
assertEquals(10, mScrollViewCustom.getScrollY());
assertEquals(10, mScrollViewCustom.getScrollX());
mScrollViewCustom.scrollTo(mPageWidth, mPageHeight);
assertEquals(mPageHeight, mScrollViewCustom.getScrollY());
assertEquals(mPageWidth, mScrollViewCustom.getScrollX());
mScrollViewCustom.scrollTo(mScrollRight, mScrollBottom);
assertEquals(mScrollBottom, mScrollViewCustom.getScrollY());
assertEquals(mScrollRight, mScrollViewCustom.getScrollX());
// reach the top and left
mScrollViewCustom.scrollTo(-10, -10);
assertEquals(0, mScrollViewCustom.getScrollY());
assertEquals(0, mScrollViewCustom.getScrollX());
}
@UiThreadTest
@Test
public void testGetVerticalFadingEdgeStrengths() {
MyScrollView myScrollViewCustom = (MyScrollView) mScrollViewCustom;
assertTrue(myScrollViewCustom.getChildCount() > 0);
assertTrue(myScrollViewCustom.getTopFadingEdgeStrength() <= 1.0f);
assertTrue(myScrollViewCustom.getTopFadingEdgeStrength() >= 0.0f);
assertTrue(myScrollViewCustom.getBottomFadingEdgeStrength() <= 1.0f);
assertTrue(myScrollViewCustom.getBottomFadingEdgeStrength() >= 0.0f);
MyScrollView myScrollView = new MyScrollView(mActivity);
assertEquals(0, myScrollView.getChildCount());
assertTrue(myScrollView.getTopFadingEdgeStrength() <= 1.0f);
assertTrue(myScrollView.getTopFadingEdgeStrength() >= 0.0f);
assertTrue(myScrollView.getBottomFadingEdgeStrength() <= 1.0f);
assertTrue(myScrollView.getBottomFadingEdgeStrength() >= 0.0f);
}
private boolean isInRange(int current, int from, int to) {
if (from < to) {
return current >= from && current <= to;
}
return current <= from && current >= to;
}
private void pollingCheckSmoothScrolling(final int fromX, final int toX,
final int fromY, final int toY) {
if (fromX == toX && fromY == toY) {
return;
}
if (fromY != toY) {
PollingCheck.waitFor(() -> isInRange(mScrollViewCustom.getScrollY(), fromY, toY));
}
if (fromX != toX) {
PollingCheck.waitFor(() -> isInRange(mScrollViewCustom.getScrollX(), fromX, toX));
}
PollingCheck.waitFor(
() -> toX == mScrollViewCustom.getScrollX()
&& toY == mScrollViewCustom.getScrollY());
}
private void pollingCheckFling(final int startPosition, final boolean movingDown) {
PollingCheck.waitFor(() -> {
if (movingDown) {
return mScrollViewCustom.getScrollY() > startPosition;
}
return mScrollViewCustom.getScrollY() < startPosition;
});
final int[] previousScrollY = new int[] { mScrollViewCustom.getScrollY() };
PollingCheck.waitFor(() -> {
if (mScrollViewCustom.getScrollY() == previousScrollY[0]) {
return true;
} else {
previousScrollY[0] = mScrollViewCustom.getScrollY();
return false;
}
});
}
public static class MyView extends View {
// measure in this height if set
private Integer mDesiredHeight;
public MyView(Context context) {
super(context);
}
public void setDesiredHeight(Integer desiredHeight) {
mDesiredHeight = desiredHeight;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (mDesiredHeight != null) {
int mode = MeasureSpec.getMode(heightMeasureSpec);
int size = MeasureSpec.getSize(heightMeasureSpec);
int newHeight = size;
if (mode == MeasureSpec.AT_MOST) {
newHeight = Math.max(size, mDesiredHeight);
} else if (mode == MeasureSpec.UNSPECIFIED) {
newHeight = mDesiredHeight;
}
setMeasuredDimension(getMeasuredWidth(), newHeight);
}
}
}
public static class MyScrollView extends ScrollView {
public MyScrollView(Context context) {
super(context);
}
public MyScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyScrollView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected int computeScrollDeltaToGetChildRectOnScreen(Rect rect) {
return super.computeScrollDeltaToGetChildRectOnScreen(rect);
}
@Override
protected int computeVerticalScrollRange() {
return super.computeVerticalScrollRange();
}
@Override
protected float getBottomFadingEdgeStrength() {
return super.getBottomFadingEdgeStrength();
}
@Override
protected float getTopFadingEdgeStrength() {
return super.getTopFadingEdgeStrength();
}
@Override
protected void measureChild(View c, int pWidthMeasureSpec, int pHeightMeasureSpec) {
super.measureChild(c, pWidthMeasureSpec, pHeightMeasureSpec);
}
@Override
protected void measureChildWithMargins(View child, int parentWidthMeasureSpec,
int widthUsed, int parentHeightMeasureSpec, int heightUsed) {
super.measureChildWithMargins(child, parentWidthMeasureSpec, widthUsed,
parentHeightMeasureSpec, heightUsed);
}
}
}