diff options
author | mkosiba@chromium.org <mkosiba@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-07-08 18:13:12 +0000 |
---|---|---|
committer | mkosiba@chromium.org <mkosiba@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-07-08 18:13:12 +0000 |
commit | bf9d877ca8f02120cf040cea79a3acecf3be3c2a (patch) | |
tree | e69f87a7d70bf714850418d9a5fe0a19b9d23f37 /android_webview/javatests | |
parent | 6c3bdc27e46edc1ae148293268cf8f98a5f69018 (diff) | |
download | chromium_src-bf9d877ca8f02120cf040cea79a3acecf3be3c2a.zip chromium_src-bf9d877ca8f02120cf040cea79a3acecf3be3c2a.tar.gz chromium_src-bf9d877ca8f02120cf040cea79a3acecf3be3c2a.tar.bz2 |
[android] Hook up overscrolling to the android_webview layer.
This plumbs the DidOverScroll notification from the content layer to the
android_webview layer and hooks it up to the View.overScrollBy method.
BUG=178399
TEST=AndroidWebViewTest (AndroidScrollIntegrationTest)
ran through Android trybots and win/linux/mac compile.
NOTRY=true
Review URL: https://chromiumcodereview.appspot.com/18717002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@210386 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'android_webview/javatests')
3 files changed, 398 insertions, 13 deletions
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AndroidScrollIntegrationTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AndroidScrollIntegrationTest.java index 0039080..9767f2b 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/AndroidScrollIntegrationTest.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/AndroidScrollIntegrationTest.java @@ -19,6 +19,8 @@ import org.chromium.base.test.util.DisabledTest; import org.chromium.base.test.util.Feature; import org.chromium.content.browser.ContentViewCore; import org.chromium.content.browser.test.util.CallbackHelper; +import org.chromium.content.browser.test.util.Criteria; +import org.chromium.content.browser.test.util.CriteriaHelper; import org.chromium.ui.gfx.DeviceDisplayInfo; import java.util.concurrent.atomic.AtomicBoolean; @@ -27,14 +29,36 @@ import java.util.concurrent.atomic.AtomicBoolean; * Integration tests for synchronous scrolling. */ public class AndroidScrollIntegrationTest extends AwTestBase { + private static final int SCROLL_OFFSET_PROPAGATION_TIMEOUT_MS = 6 * 1000; - public static final int SCROLL_OFFSET_PROPAGATION_TIMEOUT_MS = 6 * 1000; + private static class OverScrollByCallbackHelper extends CallbackHelper { + int mDeltaX; + int mDeltaY; + + public int getDeltaX() { + assert getCallCount() > 0; + return mDeltaX; + } + + public int getDeltaY() { + assert getCallCount() > 0; + return mDeltaY; + } + + public void notifyCalled(int deltaX, int deltaY) { + mDeltaX = deltaX; + mDeltaY = deltaY; + notifyCalled(); + } + } private static class ScrollTestContainerView extends AwTestContainerView { private int mMaxScrollXPix = -1; private int mMaxScrollYPix = -1; private CallbackHelper mOnScrollToCallbackHelper = new CallbackHelper(); + private OverScrollByCallbackHelper mOverScrollByCallbackHelper = + new OverScrollByCallbackHelper(); public ScrollTestContainerView(Context context) { super(context); @@ -44,6 +68,10 @@ public class AndroidScrollIntegrationTest extends AwTestBase { return mOnScrollToCallbackHelper; } + public OverScrollByCallbackHelper getOverScrollByCallbackHelper() { + return mOverScrollByCallbackHelper; + } + public void setMaxScrollX(int maxScrollXPix) { mMaxScrollXPix = maxScrollXPix; } @@ -53,6 +81,15 @@ public class AndroidScrollIntegrationTest extends AwTestBase { } @Override + protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, + int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, + boolean isTouchEvent) { + mOverScrollByCallbackHelper.notifyCalled(deltaX, deltaY); + return super.overScrollBy(deltaX, deltaY, scrollX, scrollY, + scrollRangeX, scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent); + } + + @Override public void scrollTo(int x, int y) { if (mMaxScrollXPix != -1) x = Math.min(mMaxScrollXPix, x); @@ -154,12 +191,29 @@ public class AndroidScrollIntegrationTest extends AwTestBase { }); } - private void assertScrollInJs(AwContents awContents, TestAwContentsClient contentsClient, - int xCss, int yCss) throws Exception { + private void assertScrollInJs(final AwContents awContents, + final TestAwContentsClient contentsClient, + final int xCss, final int yCss) throws Exception { String x = executeJavaScriptAndWaitForResult(awContents, contentsClient, "window.scrollX"); String y = executeJavaScriptAndWaitForResult(awContents, contentsClient, "window.scrollY"); - assertEquals(Integer.toString(xCss), x); - assertEquals(Integer.toString(yCss), y); + + assertTrue(CriteriaHelper.pollForCriteria(new Criteria() { + @Override + public boolean isSatisfied() { + try { + String x = executeJavaScriptAndWaitForResult(awContents, contentsClient, + "window.scrollX"); + String y = executeJavaScriptAndWaitForResult(awContents, contentsClient, + "window.scrollY"); + return (Integer.toString(xCss).equals(x) && + Integer.toString(yCss).equals(y)); + } catch (Throwable t) { + t.printStackTrace(); + fail("Failed to get window.scroll(X/Y): " + t.toString()); + return false; + } + } + }, WAIT_TIMEOUT_SECONDS * 1000, CHECK_INTERVAL)); } private void loadTestPageAndWaitForFirstFrame(final ScrollTestContainerView testContainerView, @@ -177,10 +231,6 @@ public class AndroidScrollIntegrationTest extends AwTestBase { } }); - // After page load the view's scroll offset will be reset back to (0, 0) at least once. We - // set the initial scroll offset to something different so we can observe that. - scrollToOnMainSync(testContainerView, 10, 10); - loadDataSync(testContainerView.getAwContents(), contentsClient.getOnPageFinishedHelper(), makeTestPage(onscrollObserverName, firstFrameObserverName), "text/html", false); @@ -189,8 +239,6 @@ public class AndroidScrollIntegrationTest extends AwTestBase { // doesn't strictly guarantee that but there isn't a good alternative and this seems to // work fine. firstFrameObserver.waitForEvent(WAIT_TIMEOUT_SECONDS * 1000); - // This is just to double-check that the animation frame waiting code didn't exit too soon. - assertScrollOnMainSync(testContainerView, 0, 0); } @SmallTest @@ -339,4 +387,63 @@ public class AndroidScrollIntegrationTest extends AwTestBase { assertScrollInJs(testContainerView.getAwContents(), contentsClient, maxScrollXCss, maxScrollYCss); } + + @SmallTest + @Feature({"AndroidWebView"}) + public void testOverScrollX() throws Throwable { + final TestAwContentsClient contentsClient = new TestAwContentsClient(); + final ScrollTestContainerView testContainerView = + (ScrollTestContainerView) createAwTestContainerViewOnMainSync(contentsClient); + final OverScrollByCallbackHelper overScrollByCallbackHelper = + testContainerView.getOverScrollByCallbackHelper(); + enableJavaScriptOnUiThread(testContainerView.getAwContents()); + + final int overScrollDeltaX = 30; + final int oneStep = 1; + + loadTestPageAndWaitForFirstFrame(testContainerView, contentsClient, null); + + // Scroll separately in different dimensions because of vertical/horizontal scroll + // snap. + final int overScrollCallCount = overScrollByCallbackHelper.getCallCount(); + AwTestTouchUtils.dragCompleteView(testContainerView, + 0, overScrollDeltaX, + 0, 0, + oneStep); + overScrollByCallbackHelper.waitForCallback(overScrollCallCount); + // Unfortunately the gesture detector seems to 'eat' some number of pixels. For now + // checking that the value is < 0 (overscroll is reported as negative values) will have to + // do. + assertTrue(0 > overScrollByCallbackHelper.getDeltaX()); + assertEquals(0, overScrollByCallbackHelper.getDeltaY()); + + assertScrollOnMainSync(testContainerView, 0, 0); + } + + @SmallTest + @Feature({"AndroidWebView"}) + public void testOverScrollY() throws Throwable { + final TestAwContentsClient contentsClient = new TestAwContentsClient(); + final ScrollTestContainerView testContainerView = + (ScrollTestContainerView) createAwTestContainerViewOnMainSync(contentsClient); + final OverScrollByCallbackHelper overScrollByCallbackHelper = + testContainerView.getOverScrollByCallbackHelper(); + enableJavaScriptOnUiThread(testContainerView.getAwContents()); + + final int overScrollDeltaY = 30; + final int oneStep = 1; + + loadTestPageAndWaitForFirstFrame(testContainerView, contentsClient, null); + + int overScrollCallCount = overScrollByCallbackHelper.getCallCount(); + AwTestTouchUtils.dragCompleteView(testContainerView, + 0, 0, + 0, overScrollDeltaY, + oneStep); + overScrollByCallbackHelper.waitForCallback(overScrollCallCount); + assertEquals(0, overScrollByCallbackHelper.getDeltaX()); + assertTrue(0 > overScrollByCallbackHelper.getDeltaY()); + + assertScrollOnMainSync(testContainerView, 0, 0); + } } diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwScrollOffsetManagerTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwScrollOffsetManagerTest.java new file mode 100644 index 0000000..b29d606 --- /dev/null +++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwScrollOffsetManagerTest.java @@ -0,0 +1,278 @@ +// 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.view.View; +import android.view.View.MeasureSpec; +import android.test.InstrumentationTestCase; +import android.test.suitebuilder.annotation.SmallTest; + +import org.chromium.android_webview.AwScrollOffsetManager; + +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; + + 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; + } + + @Override + public void overScrollContainerViewBy(int deltaX, int deltaY, int scrollX, int scrollY, + int scrollRangeX, int scrollRangeY) { + 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; + } + } + + 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); + } + + public void testWhenContentSizeMatchesView() { + TestScrollOffsetManagerDelegate delegate = new TestScrollOffsetManagerDelegate(); + AwScrollOffsetManager offsetManager = new AwScrollOffsetManager(delegate); + + final int width = 132; + final int height = 212; + final int scrollX = 11; + final int scrollY = 13; + + offsetManager.setContentSize(width, height); + 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 = 61; + private static final int MAX_VERTICAL_OFFSET = 42; + private static final int CONTENT_WIDTH = VIEW_WIDTH + MAX_HORIZONTAL_OFFSET; + private static final int CONTENT_HEIGHT = VIEW_HEIGHT + MAX_VERTICAL_OFFSET; + + public void testScrollRangeAndMaxOffset() { + TestScrollOffsetManagerDelegate delegate = new TestScrollOffsetManagerDelegate(); + AwScrollOffsetManager offsetManager = new AwScrollOffsetManager(delegate); + + offsetManager.setContentSize(CONTENT_WIDTH, CONTENT_HEIGHT); + 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()); + } + + 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; + } + }; + AwScrollOffsetManager offsetManager = new AwScrollOffsetManager(delegate); + + offsetManager.setContentSize(CONTENT_WIDTH, CONTENT_HEIGHT); + offsetManager.setContainerViewSize(VIEW_WIDTH, VIEW_HEIGHT); + + offsetManager.onContainerViewOverScrolled(0, 0, false, false); + assertEquals(overrideScrollX, delegate.getNativeScrollX()); + assertEquals(overrideScrollY, delegate.getNativeScrollY()); + } + + public void testDelegateOverridenScrollsDontExceedBounds() { + final int overrideScrollX = 222; + final int overrideScrollY = 333; + TestScrollOffsetManagerDelegate delegate = new TestScrollOffsetManagerDelegate() { + @Override + public int getContainerViewScrollX() { + return overrideScrollX; + } + + @Override + public int getContainerViewScrollY() { + return overrideScrollY; + } + }; + AwScrollOffsetManager offsetManager = new AwScrollOffsetManager(delegate); + + offsetManager.setContentSize(CONTENT_WIDTH, CONTENT_HEIGHT); + offsetManager.setContainerViewSize(VIEW_WIDTH, VIEW_HEIGHT); + + offsetManager.onContainerViewOverScrolled(0, 0, false, false); + assertEquals(MAX_HORIZONTAL_OFFSET, delegate.getNativeScrollX()); + assertEquals(MAX_VERTICAL_OFFSET, delegate.getNativeScrollY()); + } + + public void testScrollContainerViewTo() { + TestScrollOffsetManagerDelegate delegate = new TestScrollOffsetManagerDelegate(); + AwScrollOffsetManager offsetManager = new AwScrollOffsetManager(delegate); + + final int scrollX = 31; + final int scrollY = 41; + + offsetManager.setContentSize(CONTENT_WIDTH, CONTENT_HEIGHT); + 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()); + } + + public void testOnContainerViewOverScrolled() { + TestScrollOffsetManagerDelegate delegate = new TestScrollOffsetManagerDelegate(); + AwScrollOffsetManager offsetManager = new AwScrollOffsetManager(delegate); + + final int scrollX = 31; + final int scrollY = 41; + + offsetManager.setContentSize(CONTENT_WIDTH, CONTENT_HEIGHT); + 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()); + } +} diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwTestBase.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwTestBase.java index da078d2..0bb148e 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/AwTestBase.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwTestBase.java @@ -32,8 +32,8 @@ import java.util.concurrent.atomic.AtomicReference; */ public class AwTestBase extends ActivityInstrumentationTestCase2<AwTestRunnerActivity> { - protected final static int WAIT_TIMEOUT_SECONDS = 15; - private static final int CHECK_INTERVAL = 100; + protected static final int WAIT_TIMEOUT_SECONDS = 15; + protected static final int CHECK_INTERVAL = 100; public AwTestBase() { super(AwTestRunnerActivity.class); |