blob: 4fd2de4f802eee5cd79a35681437d67b52dcf208 [file] [log] [blame]
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.android_webview.test;
import android.graphics.Rect;
import android.test.InstrumentationTestCase;
import android.test.suitebuilder.annotation.SmallTest;
import android.widget.OverScroller;
import org.chromium.android_webview.AwScrollOffsetManager;
import org.chromium.base.test.util.Feature;
public class AwScrollOffsetManagerTest extends InstrumentationTestCase {
private static class TestScrollOffsetManagerDelegate implements AwScrollOffsetManager.Delegate {
private int mOverScrollDeltaX;
private int mOverScrollDeltaY;
private int mOverScrollCallCount;
private int mScrollX;
private int mScrollY;
private int mNativeScrollX;
private int mNativeScrollY;
private int mInvalidateCount;
public int getOverScrollDeltaX() {
return mOverScrollDeltaX;
}
public int getOverScrollDeltaY() {
return mOverScrollDeltaY;
}
public int getOverScrollCallCount() {
return mOverScrollCallCount;
}
public int getScrollX() {
return mScrollX;
}
public int getScrollY() {
return mScrollY;
}
public int getNativeScrollX() {
return mNativeScrollX;
}
public int getNativeScrollY() {
return mNativeScrollY;
}
public int getInvalidateCount() {
return mInvalidateCount;
}
@Override
public void overScrollContainerViewBy(int deltaX, int deltaY, int scrollX, int scrollY,
int scrollRangeX, int scrollRangeY, boolean isTouchEvent) {
mOverScrollDeltaX = deltaX;
mOverScrollDeltaY = deltaY;
mOverScrollCallCount += 1;
}
@Override
public void scrollContainerViewTo(int x, int y) {
mScrollX = x;
mScrollY = y;
}
@Override
public void scrollNativeTo(int x, int y) {
mNativeScrollX = x;
mNativeScrollY = y;
}
@Override
public int getContainerViewScrollX() {
return mScrollX;
}
@Override
public int getContainerViewScrollY() {
return mScrollY;
}
@Override
public void invalidate() {
mInvalidateCount += 1;
}
}
private void simulateScrolling(AwScrollOffsetManager offsetManager,
TestScrollOffsetManagerDelegate delegate, int scrollX, int scrollY) {
// Scrolling is a two-phase action. First we ask the manager to scroll
int callCount = delegate.getOverScrollCallCount();
offsetManager.scrollContainerViewTo(scrollX, scrollY);
// The manager then asks the delegate to overscroll the view.
assertEquals(callCount + 1, delegate.getOverScrollCallCount());
assertEquals(scrollX, delegate.getOverScrollDeltaX() + delegate.getScrollX());
assertEquals(scrollY, delegate.getOverScrollDeltaY() + delegate.getScrollY());
// As a response to that the menager expects the view to call back with the new scroll.
offsetManager.onContainerViewOverScrolled(scrollX, scrollY, false, false);
}
private void simlateOverScrollPropagation(AwScrollOffsetManager offsetManager,
TestScrollOffsetManagerDelegate delegate) {
assertTrue(delegate.getOverScrollCallCount() > 0);
offsetManager.onContainerViewOverScrolled(
delegate.getOverScrollDeltaX() + delegate.getScrollX(),
delegate.getOverScrollDeltaY() + delegate.getScrollY(), false, false);
}
@SmallTest
@Feature({"AndroidWebView"})
public void testWhenContentSizeMatchesView() {
TestScrollOffsetManagerDelegate delegate = new TestScrollOffsetManagerDelegate();
OverScroller scroller = new OverScroller(getInstrumentation().getContext());
AwScrollOffsetManager offsetManager = new AwScrollOffsetManager(delegate, scroller);
final int width = 132;
final int height = 212;
final int scrollX = 11;
final int scrollY = 13;
offsetManager.setMaxScrollOffset(0, 0);
offsetManager.setContainerViewSize(width, height);
assertEquals(width, offsetManager.computeHorizontalScrollRange());
assertEquals(height, offsetManager.computeVerticalScrollRange());
// Since the view size and contents size are equal no scrolling should be possible.
assertEquals(0, offsetManager.computeMaximumHorizontalScrollOffset());
assertEquals(0, offsetManager.computeMaximumVerticalScrollOffset());
// Scrolling should generate overscroll but not update the scroll offset.
simulateScrolling(offsetManager, delegate, scrollX, scrollY);
assertEquals(scrollX, delegate.getOverScrollDeltaX());
assertEquals(scrollY, delegate.getOverScrollDeltaY());
assertEquals(0, delegate.getScrollX());
assertEquals(0, delegate.getScrollY());
assertEquals(0, delegate.getNativeScrollX());
assertEquals(0, delegate.getNativeScrollY());
// Scrolling to 0,0 should result in no deltas.
simulateScrolling(offsetManager, delegate, 0, 0);
assertEquals(0, delegate.getOverScrollDeltaX());
assertEquals(0, delegate.getOverScrollDeltaY());
// Negative scrolling should result in negative deltas but no scroll offset update.
simulateScrolling(offsetManager, delegate, -scrollX, -scrollY);
assertEquals(-scrollX, delegate.getOverScrollDeltaX());
assertEquals(-scrollY, delegate.getOverScrollDeltaY());
assertEquals(0, delegate.getScrollX());
assertEquals(0, delegate.getScrollY());
assertEquals(0, delegate.getNativeScrollX());
assertEquals(0, delegate.getNativeScrollY());
}
private static final int VIEW_WIDTH = 211;
private static final int VIEW_HEIGHT = 312;
private static final int MAX_HORIZONTAL_OFFSET = 757;
private static final int MAX_VERTICAL_OFFSET = 127;
private static final int CONTENT_WIDTH = VIEW_WIDTH + MAX_HORIZONTAL_OFFSET;
private static final int CONTENT_HEIGHT = VIEW_HEIGHT + MAX_VERTICAL_OFFSET;
@SmallTest
@Feature({"AndroidWebView"})
public void testScrollRangeAndMaxOffset() {
TestScrollOffsetManagerDelegate delegate = new TestScrollOffsetManagerDelegate();
OverScroller scroller = new OverScroller(getInstrumentation().getContext());
AwScrollOffsetManager offsetManager = new AwScrollOffsetManager(delegate, scroller);
offsetManager.setMaxScrollOffset(MAX_HORIZONTAL_OFFSET, MAX_VERTICAL_OFFSET);
offsetManager.setContainerViewSize(VIEW_WIDTH, VIEW_HEIGHT);
assertEquals(CONTENT_WIDTH, offsetManager.computeHorizontalScrollRange());
assertEquals(CONTENT_HEIGHT, offsetManager.computeVerticalScrollRange());
assertEquals(MAX_HORIZONTAL_OFFSET, offsetManager.computeMaximumHorizontalScrollOffset());
assertEquals(MAX_VERTICAL_OFFSET, offsetManager.computeMaximumVerticalScrollOffset());
// Scrolling beyond the maximum should be clamped.
final int scrollX = MAX_HORIZONTAL_OFFSET + 10;
final int scrollY = MAX_VERTICAL_OFFSET + 11;
simulateScrolling(offsetManager, delegate, scrollX, scrollY);
assertEquals(scrollX, delegate.getOverScrollDeltaX());
assertEquals(scrollY, delegate.getOverScrollDeltaY());
assertEquals(MAX_HORIZONTAL_OFFSET, delegate.getScrollX());
assertEquals(MAX_VERTICAL_OFFSET, delegate.getScrollY());
assertEquals(MAX_HORIZONTAL_OFFSET, delegate.getNativeScrollX());
assertEquals(MAX_VERTICAL_OFFSET, delegate.getNativeScrollY());
// Scrolling to negative coordinates should be clamped back to 0,0.
simulateScrolling(offsetManager, delegate, -scrollX, -scrollY);
assertEquals(0, delegate.getScrollX());
assertEquals(0, delegate.getScrollY());
assertEquals(0, delegate.getNativeScrollX());
assertEquals(0, delegate.getNativeScrollY());
// The onScrollChanged method is callable by third party code and should also be clamped
offsetManager.onContainerViewScrollChanged(scrollX, scrollY);
assertEquals(MAX_HORIZONTAL_OFFSET, delegate.getNativeScrollX());
assertEquals(MAX_VERTICAL_OFFSET, delegate.getNativeScrollY());
offsetManager.onContainerViewScrollChanged(-scrollX, -scrollY);
assertEquals(0, delegate.getNativeScrollX());
assertEquals(0, delegate.getNativeScrollY());
}
@SmallTest
@Feature({"AndroidWebView"})
public void testDelegateCanOverrideScroll() {
final int overrideScrollX = 10;
final int overrideScrollY = 10;
TestScrollOffsetManagerDelegate delegate = new TestScrollOffsetManagerDelegate() {
@Override
public int getContainerViewScrollX() {
return overrideScrollX;
}
@Override
public int getContainerViewScrollY() {
return overrideScrollY;
}
};
OverScroller scroller = new OverScroller(getInstrumentation().getContext());
AwScrollOffsetManager offsetManager = new AwScrollOffsetManager(delegate, scroller);
offsetManager.setMaxScrollOffset(MAX_HORIZONTAL_OFFSET, MAX_VERTICAL_OFFSET);
offsetManager.setContainerViewSize(VIEW_WIDTH, VIEW_HEIGHT);
offsetManager.onContainerViewOverScrolled(0, 0, false, false);
assertEquals(overrideScrollX, delegate.getNativeScrollX());
assertEquals(overrideScrollY, delegate.getNativeScrollY());
}
@SmallTest
@Feature({"AndroidWebView"})
public void testDelegateOverridenScrollsDontExceedBounds() {
final int overrideScrollX = MAX_HORIZONTAL_OFFSET + 10;
final int overrideScrollY = MAX_VERTICAL_OFFSET + 20;
TestScrollOffsetManagerDelegate delegate = new TestScrollOffsetManagerDelegate() {
@Override
public int getContainerViewScrollX() {
return overrideScrollX;
}
@Override
public int getContainerViewScrollY() {
return overrideScrollY;
}
};
OverScroller scroller = new OverScroller(getInstrumentation().getContext());
AwScrollOffsetManager offsetManager = new AwScrollOffsetManager(delegate, scroller);
offsetManager.setMaxScrollOffset(MAX_HORIZONTAL_OFFSET, MAX_VERTICAL_OFFSET);
offsetManager.setContainerViewSize(VIEW_WIDTH, VIEW_HEIGHT);
offsetManager.onContainerViewOverScrolled(0, 0, false, false);
assertEquals(MAX_HORIZONTAL_OFFSET, delegate.getNativeScrollX());
assertEquals(MAX_VERTICAL_OFFSET, delegate.getNativeScrollY());
}
@SmallTest
@Feature({"AndroidWebView"})
public void testScrollContainerViewTo() {
TestScrollOffsetManagerDelegate delegate = new TestScrollOffsetManagerDelegate();
OverScroller scroller = new OverScroller(getInstrumentation().getContext());
AwScrollOffsetManager offsetManager = new AwScrollOffsetManager(delegate, scroller);
final int scrollX = 31;
final int scrollY = 41;
offsetManager.setMaxScrollOffset(MAX_HORIZONTAL_OFFSET, MAX_VERTICAL_OFFSET);
offsetManager.setContainerViewSize(VIEW_WIDTH, VIEW_HEIGHT);
assertEquals(0, delegate.getOverScrollDeltaX());
assertEquals(0, delegate.getOverScrollDeltaY());
int callCount = delegate.getOverScrollCallCount();
offsetManager.scrollContainerViewTo(scrollX, scrollY);
assertEquals(callCount + 1, delegate.getOverScrollCallCount());
assertEquals(scrollX, delegate.getOverScrollDeltaX());
assertEquals(scrollY, delegate.getOverScrollDeltaY());
}
@SmallTest
@Feature({"AndroidWebView"})
public void testOnContainerViewOverScrolled() {
TestScrollOffsetManagerDelegate delegate = new TestScrollOffsetManagerDelegate();
OverScroller scroller = new OverScroller(getInstrumentation().getContext());
AwScrollOffsetManager offsetManager = new AwScrollOffsetManager(delegate, scroller);
final int scrollX = 31;
final int scrollY = 41;
offsetManager.setMaxScrollOffset(MAX_HORIZONTAL_OFFSET, MAX_VERTICAL_OFFSET);
offsetManager.setContainerViewSize(VIEW_WIDTH, VIEW_HEIGHT);
assertEquals(0, delegate.getScrollX());
assertEquals(0, delegate.getScrollY());
assertEquals(0, delegate.getNativeScrollX());
assertEquals(0, delegate.getNativeScrollY());
offsetManager.onContainerViewOverScrolled(scrollX, scrollY, false, false);
assertEquals(scrollX, delegate.getScrollX());
assertEquals(scrollY, delegate.getScrollY());
assertEquals(scrollX, delegate.getNativeScrollX());
assertEquals(scrollY, delegate.getNativeScrollY());
}
@SmallTest
@Feature({"AndroidWebView"})
public void testDefersScrollUntilTouchEnd() {
TestScrollOffsetManagerDelegate delegate = new TestScrollOffsetManagerDelegate();
OverScroller scroller = new OverScroller(getInstrumentation().getContext());
AwScrollOffsetManager offsetManager = new AwScrollOffsetManager(delegate, scroller);
final int scrollX = 31;
final int scrollY = 41;
offsetManager.setMaxScrollOffset(MAX_HORIZONTAL_OFFSET, MAX_VERTICAL_OFFSET);
offsetManager.setContainerViewSize(VIEW_WIDTH, VIEW_HEIGHT);
offsetManager.setProcessingTouchEvent(true);
offsetManager.onContainerViewOverScrolled(scrollX, scrollY, false, false);
assertEquals(scrollX, delegate.getScrollX());
assertEquals(scrollY, delegate.getScrollY());
assertEquals(0, delegate.getNativeScrollX());
assertEquals(0, delegate.getNativeScrollY());
offsetManager.setProcessingTouchEvent(false);
assertEquals(scrollX, delegate.getScrollX());
assertEquals(scrollY, delegate.getScrollY());
assertEquals(scrollX, delegate.getNativeScrollX());
assertEquals(scrollY, delegate.getNativeScrollY());
}
@SmallTest
@Feature({"AndroidWebView"})
public void testFlingScroll() {
TestScrollOffsetManagerDelegate delegate = new TestScrollOffsetManagerDelegate();
OverScroller scroller = new OverScroller(getInstrumentation().getContext());
AwScrollOffsetManager offsetManager = new AwScrollOffsetManager(delegate, scroller);
offsetManager.flingScroll(0, 101);
assertTrue(!scroller.isFinished());
assertTrue(delegate.getInvalidateCount() == 1);
assertEquals(101, (int) scroller.getCurrVelocity());
offsetManager.flingScroll(111, 0);
assertTrue(!scroller.isFinished());
assertTrue(delegate.getInvalidateCount() == 2);
assertEquals(111, (int) scroller.getCurrVelocity());
}
@SmallTest
@Feature({"AndroidWebView"})
public void testRequestChildRectangleOnScreenDontScrollIfAlreadyThere() {
TestScrollOffsetManagerDelegate delegate = new TestScrollOffsetManagerDelegate();
OverScroller scroller = new OverScroller(getInstrumentation().getContext());
AwScrollOffsetManager offsetManager = new AwScrollOffsetManager(delegate, scroller);
offsetManager.setMaxScrollOffset(MAX_HORIZONTAL_OFFSET, MAX_VERTICAL_OFFSET);
offsetManager.setContainerViewSize(VIEW_WIDTH, VIEW_HEIGHT);
offsetManager.requestChildRectangleOnScreen(0, 0,
new Rect(0, 0, VIEW_WIDTH / 4, VIEW_HEIGHT / 4), true);
assertEquals(0, delegate.getOverScrollDeltaX());
assertEquals(0, delegate.getOverScrollDeltaY());
assertEquals(0, delegate.getScrollX());
assertEquals(0, delegate.getScrollY());
offsetManager.requestChildRectangleOnScreen(3 * VIEW_WIDTH / 4, 3 * VIEW_HEIGHT / 4,
new Rect(0, 0, VIEW_WIDTH / 4, VIEW_HEIGHT / 4), true);
assertEquals(0, delegate.getOverScrollDeltaX());
assertEquals(0, delegate.getOverScrollDeltaY());
assertEquals(0, delegate.getScrollX());
assertEquals(0, delegate.getScrollY());
}
@SmallTest
@Feature({"AndroidWebView"})
public void testRequestChildRectangleOnScreenScrollToBottom() {
TestScrollOffsetManagerDelegate delegate = new TestScrollOffsetManagerDelegate();
OverScroller scroller = new OverScroller(getInstrumentation().getContext());
AwScrollOffsetManager offsetManager = new AwScrollOffsetManager(delegate, scroller);
final int rectWidth = 2;
final int rectHeight = 3;
offsetManager.setMaxScrollOffset(MAX_HORIZONTAL_OFFSET, MAX_VERTICAL_OFFSET);
offsetManager.setContainerViewSize(VIEW_WIDTH, VIEW_HEIGHT);
offsetManager.requestChildRectangleOnScreen(CONTENT_WIDTH - rectWidth,
CONTENT_HEIGHT - rectHeight, new Rect(0, 0, rectWidth, rectHeight), true);
simlateOverScrollPropagation(offsetManager, delegate);
assertEquals(MAX_HORIZONTAL_OFFSET, delegate.getOverScrollDeltaX());
assertEquals(CONTENT_HEIGHT - rectHeight - VIEW_HEIGHT / 3, delegate.getOverScrollDeltaY());
assertEquals(MAX_HORIZONTAL_OFFSET, delegate.getScrollX());
assertEquals(MAX_VERTICAL_OFFSET, delegate.getScrollY());
}
@SmallTest
@Feature({"AndroidWebView"})
public void testRequestChildRectangleOnScreenScrollToBottomLargeRect() {
TestScrollOffsetManagerDelegate delegate = new TestScrollOffsetManagerDelegate();
OverScroller scroller = new OverScroller(getInstrumentation().getContext());
AwScrollOffsetManager offsetManager = new AwScrollOffsetManager(delegate, scroller);
final int rectWidth = VIEW_WIDTH;
final int rectHeight = VIEW_HEIGHT;
offsetManager.setMaxScrollOffset(MAX_HORIZONTAL_OFFSET, MAX_VERTICAL_OFFSET);
offsetManager.setContainerViewSize(VIEW_WIDTH, VIEW_HEIGHT);
offsetManager.requestChildRectangleOnScreen(CONTENT_WIDTH - rectWidth,
CONTENT_HEIGHT - rectHeight, new Rect(0, 0, rectWidth, rectHeight), true);
simlateOverScrollPropagation(offsetManager, delegate);
assertEquals(MAX_HORIZONTAL_OFFSET, delegate.getOverScrollDeltaX());
assertEquals(MAX_VERTICAL_OFFSET, delegate.getOverScrollDeltaY());
assertEquals(MAX_HORIZONTAL_OFFSET, delegate.getScrollX());
assertEquals(MAX_VERTICAL_OFFSET, delegate.getScrollY());
}
@SmallTest
@Feature({"AndroidWebView"})
public void testRequestChildRectangleOnScreenScrollToTop() {
TestScrollOffsetManagerDelegate delegate = new TestScrollOffsetManagerDelegate();
OverScroller scroller = new OverScroller(getInstrumentation().getContext());
AwScrollOffsetManager offsetManager = new AwScrollOffsetManager(delegate, scroller);
final int rectWidth = 2;
final int rectHeight = 3;
offsetManager.setMaxScrollOffset(MAX_HORIZONTAL_OFFSET, MAX_VERTICAL_OFFSET);
offsetManager.setContainerViewSize(VIEW_WIDTH, VIEW_HEIGHT);
simulateScrolling(offsetManager, delegate,
CONTENT_WIDTH - VIEW_WIDTH, CONTENT_HEIGHT - VIEW_HEIGHT);
offsetManager.requestChildRectangleOnScreen(0, 0,
new Rect(0, 0, rectWidth, rectHeight), true);
simlateOverScrollPropagation(offsetManager, delegate);
assertEquals(-CONTENT_WIDTH + VIEW_WIDTH, delegate.getOverScrollDeltaX());
assertEquals(-CONTENT_HEIGHT + VIEW_HEIGHT, delegate.getOverScrollDeltaY());
assertEquals(0, delegate.getScrollX());
assertEquals(0, delegate.getScrollX());
}
}