EMMA Coverage Report (generated Tue Aug 20 10:07:21 PDT 2013)
[all classes][org.chromium.android_webview.test]

COVERAGE SUMMARY FOR SOURCE FILE [AndroidScrollIntegrationTest.java]

nameclass, %method, %block, %line, %
AndroidScrollIntegrationTest.java100% (17/17)100% (61/61)98%  (1433/1468)98%  (265.5/272)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class AndroidScrollIntegrationTest$6100% (1/1)100% (2/2)76%  (51/67)50%  (4/8)
isSatisfied (): boolean 100% (1/1)67%  (33/49)42%  (3/7)
AndroidScrollIntegrationTest$6 (AndroidScrollIntegrationTest, AwContents, Tes... 100% (1/1)100% (18/18)100% (1/1)
     
class AndroidScrollIntegrationTest$OverScrollByCallbackHelper100% (1/1)100% (6/6)79%  (37/47)88%  (8/9)
getDeltaX (): int 100% (1/1)67%  (8/12)78%  (1.6/2)
getDeltaY (): int 100% (1/1)67%  (8/12)78%  (1.6/2)
<static initializer> 100% (1/1)75%  (6/8)75%  (0.8/1)
AndroidScrollIntegrationTest$OverScrollByCallbackHelper (): void 100% (1/1)100% (3/3)100% (1/1)
AndroidScrollIntegrationTest$OverScrollByCallbackHelper (AndroidScrollIntegra... 100% (1/1)100% (3/3)100% (1/1)
notifyCalled (int, int): void 100% (1/1)100% (9/9)100% (4/4)
     
class AndroidScrollIntegrationTest$11100% (1/1)100% (2/2)92%  (24/26)95%  (3.8/4)
run (): void 100% (1/1)88%  (15/17)94%  (2.8/3)
AndroidScrollIntegrationTest$11 (AndroidScrollIntegrationTest, AndroidScrollI... 100% (1/1)100% (9/9)100% (1/1)
     
class AndroidScrollIntegrationTest$9100% (1/1)100% (2/2)96%  (46/48)98%  (6.9/7)
run (): void 100% (1/1)95%  (37/39)98%  (5.9/6)
AndroidScrollIntegrationTest$9 (AndroidScrollIntegrationTest, AndroidScrollIn... 100% (1/1)100% (9/9)100% (1/1)
     
class AndroidScrollIntegrationTest100% (1/1)100% (20/20)99%  (965/970)99%  (202.9/204)
testTouchScrollCanBeAlteredByUi (): void 100% (1/1)98%  (96/98)100% (24/24)
testNoSpuriousOverScrolls (): void 100% (1/1)98%  (57/58)94%  (15/16)
testOverScrollX (): void 100% (1/1)98%  (57/58)100% (14/14)
testOverScrollY (): void 100% (1/1)98%  (57/58)100% (14/14)
AndroidScrollIntegrationTest (): void 100% (1/1)100% (3/3)100% (2/2)
assertScrollInJs (AwContents, TestAwContentsClient, int, int): void 100% (1/1)100% (25/25)100% (4/4)
assertScrollOnMainSync (AndroidScrollIntegrationTest$ScrollTestContainerView,... 100% (1/1)100% (11/11)100% (2/2)
checkScrollOnMainSync (AndroidScrollIntegrationTest$ScrollTestContainerView, ... 100% (1/1)100% (19/19)100% (3/3)
createTestDependencyFactory (): AwTestBase$TestDependencyFactory 100% (1/1)100% (5/5)100% (1/1)
loadTestPageAndWaitForFirstFrame (AndroidScrollIntegrationTest$ScrollTestCont... 100% (1/1)100% (37/37)100% (7/7)
makeTestPage (String, String, String): String 100% (1/1)100% (61/61)100% (6/6)
scrollToOnMainSync (View, int, int): void 100% (1/1)100% (11/11)100% (2/2)
setMaxScrollOnMainSync (AndroidScrollIntegrationTest$ScrollTestContainerView,... 100% (1/1)100% (11/11)100% (2/2)
testFlingScroll (): void 100% (1/1)100% (50/50)100% (11/11)
testJsScrollCanBeAlteredByUi (): void 100% (1/1)100% (90/90)100% (20/20)
testJsScrollReflectedInUi (): void 100% (1/1)100% (82/82)100% (15/15)
testPageDown (): void 100% (1/1)100% (64/64)100% (14/14)
testPageUp (): void 100% (1/1)100% (72/72)100% (17/17)
testScrollToBottomAtPageScaleX0dot5 (): void 100% (1/1)100% (60/60)100% (14/14)
testUiScrollReflectedInJs (): void 100% (1/1)100% (97/97)100% (16/16)
     
class AndroidScrollIntegrationTest$1100% (1/1)100% (2/2)100% (11/11)100% (2/2)
AndroidScrollIntegrationTest$1 (AndroidScrollIntegrationTest): void 100% (1/1)100% (6/6)100% (1/1)
createAwTestContainerView (AwTestRunnerActivity): AwTestContainerView 100% (1/1)100% (5/5)100% (1/1)
     
class AndroidScrollIntegrationTest$10100% (1/1)100% (2/2)100% (16/16)100% (3/3)
AndroidScrollIntegrationTest$10 (AndroidScrollIntegrationTest, AndroidScrollI... 100% (1/1)100% (9/9)100% (1/1)
run (): void 100% (1/1)100% (7/7)100% (2/2)
     
class AndroidScrollIntegrationTest$12100% (1/1)100% (2/2)100% (19/19)100% (2/2)
AndroidScrollIntegrationTest$12 (AndroidScrollIntegrationTest, AndroidScrollI... 100% (1/1)100% (9/9)100% (1/1)
call (): Integer 100% (1/1)100% (10/10)100% (1/1)
     
class AndroidScrollIntegrationTest$13100% (1/1)100% (2/2)100% (16/16)100% (3/3)
AndroidScrollIntegrationTest$13 (AndroidScrollIntegrationTest, AndroidScrollI... 100% (1/1)100% (9/9)100% (1/1)
run (): void 100% (1/1)100% (7/7)100% (2/2)
     
class AndroidScrollIntegrationTest$14100% (1/1)100% (2/2)100% (16/16)100% (3/3)
AndroidScrollIntegrationTest$14 (AndroidScrollIntegrationTest, AndroidScrollI... 100% (1/1)100% (9/9)100% (1/1)
run (): void 100% (1/1)100% (7/7)100% (2/2)
     
class AndroidScrollIntegrationTest$2100% (1/1)100% (2/2)100% (23/23)100% (3/3)
AndroidScrollIntegrationTest$2 (AndroidScrollIntegrationTest, View, int, int)... 100% (1/1)100% (15/15)100% (1/1)
run (): void 100% (1/1)100% (8/8)100% (2/2)
     
class AndroidScrollIntegrationTest$3100% (1/1)100% (2/2)100% (26/26)100% (4/4)
AndroidScrollIntegrationTest$3 (AndroidScrollIntegrationTest, AndroidScrollIn... 100% (1/1)100% (15/15)100% (1/1)
run (): void 100% (1/1)100% (11/11)100% (3/3)
     
class AndroidScrollIntegrationTest$4100% (1/1)100% (2/2)100% (37/37)100% (3/3)
AndroidScrollIntegrationTest$4 (AndroidScrollIntegrationTest, AtomicBoolean, ... 100% (1/1)100% (18/18)100% (1/1)
run (): void 100% (1/1)100% (19/19)100% (2/2)
     
class AndroidScrollIntegrationTest$5100% (1/1)100% (2/2)100% (28/28)100% (4/4)
AndroidScrollIntegrationTest$5 (AndroidScrollIntegrationTest, int, AndroidScr... 100% (1/1)100% (15/15)100% (1/1)
run (): void 100% (1/1)100% (13/13)100% (3/3)
     
class AndroidScrollIntegrationTest$7100% (1/1)100% (2/2)100% (20/20)100% (3/3)
AndroidScrollIntegrationTest$7 (AndroidScrollIntegrationTest, JavascriptEvent... 100% (1/1)100% (12/12)100% (1/1)
run (): void 100% (1/1)100% (8/8)100% (2/2)
     
class AndroidScrollIntegrationTest$8100% (1/1)100% (2/2)100% (20/20)100% (3/3)
AndroidScrollIntegrationTest$8 (AndroidScrollIntegrationTest, JavascriptEvent... 100% (1/1)100% (12/12)100% (1/1)
run (): void 100% (1/1)100% (8/8)100% (2/2)
     
class AndroidScrollIntegrationTest$ScrollTestContainerView100% (1/1)100% (7/7)100% (78/78)100% (21/21)
AndroidScrollIntegrationTest$ScrollTestContainerView (Context): void 100% (1/1)100% (21/21)100% (6/6)
getOnScrollToCallbackHelper (): CallbackHelper 100% (1/1)100% (3/3)100% (1/1)
getOverScrollByCallbackHelper (): AndroidScrollIntegrationTest$OverScrollByCa... 100% (1/1)100% (3/3)100% (1/1)
overScrollBy (int, int, int, int, int, int, int, int, boolean): boolean 100% (1/1)100% (17/17)100% (2/2)
scrollTo (int, int): void 100% (1/1)100% (26/26)100% (7/7)
setMaxScrollX (int): void 100% (1/1)100% (4/4)100% (2/2)
setMaxScrollY (int): void 100% (1/1)100% (4/4)100% (2/2)

1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4 
5package org.chromium.android_webview.test;
6 
7import android.content.Context;
8import android.test.suitebuilder.annotation.SmallTest;
9import android.util.Log;
10import android.view.Gravity;
11import android.view.View;
12 
13import org.chromium.android_webview.AwContents;
14import org.chromium.android_webview.AwContentsClient;
15import org.chromium.android_webview.test.util.AwTestTouchUtils;
16import org.chromium.android_webview.test.util.CommonResources;
17import org.chromium.android_webview.test.util.JavascriptEventObserver;
18import org.chromium.base.test.util.DisabledTest;
19import org.chromium.base.test.util.Feature;
20import org.chromium.content.browser.ContentViewCore;
21import org.chromium.content.browser.test.util.CallbackHelper;
22import org.chromium.content.browser.test.util.Criteria;
23import org.chromium.content.browser.test.util.CriteriaHelper;
24import org.chromium.ui.gfx.DeviceDisplayInfo;
25 
26import java.util.concurrent.Callable;
27import java.util.concurrent.CountDownLatch;
28import java.util.concurrent.atomic.AtomicBoolean;
29 
30/**
31 * Integration tests for synchronous scrolling.
32 */
33public class AndroidScrollIntegrationTest extends AwTestBase {
34    private static final int SCROLL_OFFSET_PROPAGATION_TIMEOUT_MS = 6 * 1000;
35 
36    private static class OverScrollByCallbackHelper extends CallbackHelper {
37        int mDeltaX;
38        int mDeltaY;
39 
40        public int getDeltaX() {
41            assert getCallCount() > 0;
42            return mDeltaX;
43        }
44 
45        public int getDeltaY() {
46            assert getCallCount() > 0;
47            return mDeltaY;
48        }
49 
50        public void notifyCalled(int deltaX, int deltaY) {
51            mDeltaX = deltaX;
52            mDeltaY = deltaY;
53            notifyCalled();
54        }
55    }
56 
57    private static class ScrollTestContainerView extends AwTestContainerView {
58        private int mMaxScrollXPix = -1;
59        private int mMaxScrollYPix = -1;
60 
61        private CallbackHelper mOnScrollToCallbackHelper = new CallbackHelper();
62        private OverScrollByCallbackHelper mOverScrollByCallbackHelper =
63            new OverScrollByCallbackHelper();
64 
65        public ScrollTestContainerView(Context context) {
66            super(context);
67        }
68 
69        public CallbackHelper getOnScrollToCallbackHelper() {
70            return mOnScrollToCallbackHelper;
71        }
72 
73        public OverScrollByCallbackHelper getOverScrollByCallbackHelper() {
74            return mOverScrollByCallbackHelper;
75        }
76 
77        public void setMaxScrollX(int maxScrollXPix) {
78            mMaxScrollXPix = maxScrollXPix;
79        }
80 
81        public void setMaxScrollY(int maxScrollYPix) {
82            mMaxScrollYPix = maxScrollYPix;
83        }
84 
85        @Override
86        protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY,
87                     int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY,
88                     boolean isTouchEvent) {
89            mOverScrollByCallbackHelper.notifyCalled(deltaX, deltaY);
90            return super.overScrollBy(deltaX, deltaY, scrollX, scrollY,
91                     scrollRangeX, scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent);
92        }
93 
94        @Override
95        public void scrollTo(int x, int y) {
96            if (mMaxScrollXPix != -1)
97                x = Math.min(mMaxScrollXPix, x);
98            if (mMaxScrollYPix != -1)
99                y = Math.min(mMaxScrollYPix, y);
100            super.scrollTo(x, y);
101            mOnScrollToCallbackHelper.notifyCalled();
102        }
103    }
104 
105    @Override
106    protected TestDependencyFactory createTestDependencyFactory() {
107        return new TestDependencyFactory() {
108            @Override
109            public AwTestContainerView createAwTestContainerView(AwTestRunnerActivity activity) {
110                return new ScrollTestContainerView(activity);
111            }
112        };
113    }
114 
115    private static final String TEST_PAGE_COMMON_HEADERS =
116        "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"> " +
117        "<style type=\"text/css\"> " +
118        "   div { " +
119        "      width:1000px; " +
120        "      height:10000px; " +
121        "      background-color: blue; " +
122        "   } " +
123        "</style> ";
124    private static final String TEST_PAGE_COMMON_CONTENT = "<div>test div</div> ";
125 
126    private String makeTestPage(String onscrollObserver, String firstFrameObserver,
127            String extraContent) {
128        String content = TEST_PAGE_COMMON_CONTENT + extraContent;
129        if (onscrollObserver != null) {
130            content +=
131            "<script> " +
132            "   window.onscroll = function(oEvent) { " +
133            "       " + onscrollObserver + ".notifyJava(); " +
134            "   } " +
135            "</script>";
136        }
137        if (firstFrameObserver != null) {
138            content +=
139            "<script> " +
140            "   window.framesToIgnore = 10; " +
141            "   window.onAnimationFrame = function(timestamp) { " +
142            "     if (window.framesToIgnore == 0) { " +
143            "         " + firstFrameObserver + ".notifyJava(); " +
144            "     } else {" +
145            "       window.framesToIgnore -= 1; " +
146            "       window.requestAnimationFrame(window.onAnimationFrame); " +
147            "     } " +
148            "   }; " +
149            "   window.requestAnimationFrame(window.onAnimationFrame); " +
150            "</script>";
151        }
152        return CommonResources.makeHtmlPageFrom(TEST_PAGE_COMMON_HEADERS, content);
153    }
154 
155    private void scrollToOnMainSync(final View view, final int xPix, final int yPix) {
156        getInstrumentation().runOnMainSync(new Runnable() {
157            @Override
158            public void run() {
159                view.scrollTo(xPix, yPix);
160            }
161        });
162    }
163 
164    private void setMaxScrollOnMainSync(final ScrollTestContainerView testContainerView,
165            final int maxScrollXPix, final int maxScrollYPix) {
166        getInstrumentation().runOnMainSync(new Runnable() {
167            @Override
168            public void run() {
169                testContainerView.setMaxScrollX(maxScrollXPix);
170                testContainerView.setMaxScrollY(maxScrollYPix);
171            }
172        });
173    }
174 
175    private boolean checkScrollOnMainSync(final ScrollTestContainerView testContainerView,
176            final int scrollXPix, final int scrollYPix) {
177        final AtomicBoolean equal = new AtomicBoolean(false);
178        getInstrumentation().runOnMainSync(new Runnable() {
179            @Override
180            public void run() {
181                equal.set((scrollXPix == testContainerView.getScrollX()) &&
182                    (scrollYPix == testContainerView.getScrollY()));
183            }
184        });
185        return equal.get();
186    }
187 
188    private void assertScrollOnMainSync(final ScrollTestContainerView testContainerView,
189            final int scrollXPix, final int scrollYPix) {
190        getInstrumentation().runOnMainSync(new Runnable() {
191            @Override
192            public void run() {
193                assertEquals(scrollXPix, testContainerView.getScrollX());
194                assertEquals(scrollYPix, testContainerView.getScrollY());
195            }
196        });
197    }
198 
199    private void assertScrollInJs(final AwContents awContents,
200            final TestAwContentsClient contentsClient,
201            final int xCss, final int yCss) throws Exception {
202        String x = executeJavaScriptAndWaitForResult(awContents, contentsClient, "window.scrollX");
203        String y = executeJavaScriptAndWaitForResult(awContents, contentsClient, "window.scrollY");
204 
205        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
206                @Override
207                public boolean isSatisfied() {
208                    try {
209                        String x = executeJavaScriptAndWaitForResult(awContents, contentsClient,
210                            "window.scrollX");
211                        String y = executeJavaScriptAndWaitForResult(awContents, contentsClient,
212                            "window.scrollY");
213                        return (Integer.toString(xCss).equals(x) &&
214                            Integer.toString(yCss).equals(y));
215                    } catch (Throwable t) {
216                        t.printStackTrace();
217                        fail("Failed to get window.scroll(X/Y): " + t.toString());
218                        return false;
219                    }
220                }
221            }, WAIT_TIMEOUT_SECONDS * 1000, CHECK_INTERVAL));
222    }
223 
224    private void loadTestPageAndWaitForFirstFrame(final ScrollTestContainerView testContainerView,
225            final TestAwContentsClient contentsClient,
226            final String onscrollObserverName, final String extraContent) throws Exception {
227        final JavascriptEventObserver firstFrameObserver = new JavascriptEventObserver();
228        final String firstFrameObserverName = "firstFrameObserver";
229        enableJavaScriptOnUiThread(testContainerView.getAwContents());
230 
231        getInstrumentation().runOnMainSync(new Runnable() {
232            @Override
233            public void run() {
234                firstFrameObserver.register(testContainerView.getContentViewCore(),
235                    firstFrameObserverName);
236            }
237        });
238 
239        loadDataSync(testContainerView.getAwContents(), contentsClient.getOnPageFinishedHelper(),
240                makeTestPage(onscrollObserverName, firstFrameObserverName, extraContent),
241                "text/html", false);
242 
243        // We wait for "a couple" of frames for the active tree in CC to stabilize and for pending
244        // tree activations to stop clobbering the root scroll layer's scroll offset. This wait
245        // doesn't strictly guarantee that but there isn't a good alternative and this seems to
246        // work fine.
247        firstFrameObserver.waitForEvent(WAIT_TIMEOUT_SECONDS * 1000);
248    }
249 
250    @SmallTest
251    @Feature({"AndroidWebView"})
252    public void testUiScrollReflectedInJs() throws Throwable {
253        final TestAwContentsClient contentsClient = new TestAwContentsClient();
254        final ScrollTestContainerView testContainerView =
255            (ScrollTestContainerView) createAwTestContainerViewOnMainSync(contentsClient);
256        enableJavaScriptOnUiThread(testContainerView.getAwContents());
257 
258        final double deviceDIPScale =
259            DeviceDisplayInfo.create(testContainerView.getContext()).getDIPScale();
260        final int targetScrollXCss = 233;
261        final int targetScrollYCss = 322;
262        final int targetScrollXPix = (int) Math.round(targetScrollXCss * deviceDIPScale);
263        final int targetScrollYPix = (int) Math.round(targetScrollYCss * deviceDIPScale);
264        final JavascriptEventObserver onscrollObserver = new JavascriptEventObserver();
265 
266        Log.w("AndroidScrollIntegrationTest", String.format("scroll in Js (%d, %d) -> (%d, %d)",
267                    targetScrollXCss, targetScrollYCss, targetScrollXPix, targetScrollYPix));
268 
269        getInstrumentation().runOnMainSync(new Runnable() {
270            @Override
271            public void run() {
272                onscrollObserver.register(testContainerView.getContentViewCore(),
273                    "onscrollObserver");
274            }
275        });
276 
277        loadTestPageAndWaitForFirstFrame(testContainerView, contentsClient, "onscrollObserver", "");
278 
279        scrollToOnMainSync(testContainerView, targetScrollXPix, targetScrollYPix);
280 
281        onscrollObserver.waitForEvent(SCROLL_OFFSET_PROPAGATION_TIMEOUT_MS);
282        assertScrollInJs(testContainerView.getAwContents(), contentsClient,
283                targetScrollXCss, targetScrollYCss);
284    }
285 
286    @SmallTest
287    @Feature({"AndroidWebView"})
288    public void testJsScrollReflectedInUi() throws Throwable {
289        final TestAwContentsClient contentsClient = new TestAwContentsClient();
290        final ScrollTestContainerView testContainerView =
291            (ScrollTestContainerView) createAwTestContainerViewOnMainSync(contentsClient);
292        enableJavaScriptOnUiThread(testContainerView.getAwContents());
293 
294        final double deviceDIPScale =
295            DeviceDisplayInfo.create(testContainerView.getContext()).getDIPScale();
296        final int targetScrollXCss = 132;
297        final int targetScrollYCss = 243;
298        final int targetScrollXPix = (int) Math.round(targetScrollXCss * deviceDIPScale);
299        final int targetScrollYPix = (int) Math.round(targetScrollYCss * deviceDIPScale);
300 
301        loadDataSync(testContainerView.getAwContents(), contentsClient.getOnPageFinishedHelper(),
302                makeTestPage(null, null, ""), "text/html", false);
303 
304        final CallbackHelper onScrollToCallbackHelper =
305            testContainerView.getOnScrollToCallbackHelper();
306        final int scrollToCallCount = onScrollToCallbackHelper.getCallCount();
307        executeJavaScriptAndWaitForResult(testContainerView.getAwContents(), contentsClient,
308                String.format("window.scrollTo(%d, %d);", targetScrollXCss, targetScrollYCss));
309        onScrollToCallbackHelper.waitForCallback(scrollToCallCount);
310 
311        assertScrollOnMainSync(testContainerView, targetScrollXPix, targetScrollYPix);
312    }
313 
314    @SmallTest
315    @Feature({"AndroidWebView"})
316    public void testJsScrollCanBeAlteredByUi() throws Throwable {
317        final TestAwContentsClient contentsClient = new TestAwContentsClient();
318        final ScrollTestContainerView testContainerView =
319            (ScrollTestContainerView) createAwTestContainerViewOnMainSync(contentsClient);
320        enableJavaScriptOnUiThread(testContainerView.getAwContents());
321 
322        final double deviceDIPScale =
323            DeviceDisplayInfo.create(testContainerView.getContext()).getDIPScale();
324        final int targetScrollXCss = 132;
325        final int targetScrollYCss = 243;
326        final int targetScrollXPix = (int) Math.round(targetScrollXCss * deviceDIPScale);
327        final int targetScrollYPix = (int) Math.round(targetScrollYCss * deviceDIPScale);
328 
329        final int maxScrollXCss = 101;
330        final int maxScrollYCss = 201;
331        final int maxScrollXPix = (int) Math.round(maxScrollXCss * deviceDIPScale);
332        final int maxScrollYPix = (int) Math.round(maxScrollYCss * deviceDIPScale);
333 
334        loadDataSync(testContainerView.getAwContents(), contentsClient.getOnPageFinishedHelper(),
335                makeTestPage(null, null, ""), "text/html", false);
336 
337        setMaxScrollOnMainSync(testContainerView, maxScrollXPix, maxScrollYPix);
338 
339        final CallbackHelper onScrollToCallbackHelper =
340            testContainerView.getOnScrollToCallbackHelper();
341        final int scrollToCallCount = onScrollToCallbackHelper.getCallCount();
342        executeJavaScriptAndWaitForResult(testContainerView.getAwContents(), contentsClient,
343                "window.scrollTo(" + targetScrollXCss + "," + targetScrollYCss + ")");
344        onScrollToCallbackHelper.waitForCallback(scrollToCallCount);
345 
346        assertScrollOnMainSync(testContainerView, maxScrollXPix, maxScrollYPix);
347    }
348 
349    @SmallTest
350    @Feature({"AndroidWebView"})
351    public void testTouchScrollCanBeAlteredByUi() throws Throwable {
352        final TestAwContentsClient contentsClient = new TestAwContentsClient();
353        final ScrollTestContainerView testContainerView =
354            (ScrollTestContainerView) createAwTestContainerViewOnMainSync(contentsClient);
355        enableJavaScriptOnUiThread(testContainerView.getAwContents());
356 
357        final int dragSteps = 10;
358        final int dragStepSize = 24;
359        // Watch out when modifying - if the y or x delta aren't big enough vertical or horizontal
360        // scroll snapping will kick in.
361        final int targetScrollXPix = dragStepSize * dragSteps;
362        final int targetScrollYPix = dragStepSize * dragSteps;
363 
364        final double deviceDIPScale =
365            DeviceDisplayInfo.create(testContainerView.getContext()).getDIPScale();
366        final int maxScrollXPix = 101;
367        final int maxScrollYPix = 211;
368        // Make sure we can't hit these values simply as a result of scrolling.
369        assert (maxScrollXPix % dragStepSize) != 0;
370        assert (maxScrollYPix % dragStepSize) != 0;
371        final int maxScrollXCss = (int) Math.round(maxScrollXPix / deviceDIPScale);
372        final int maxScrollYCss = (int) Math.round(maxScrollYPix / deviceDIPScale);
373 
374        setMaxScrollOnMainSync(testContainerView, maxScrollXPix, maxScrollYPix);
375 
376        loadTestPageAndWaitForFirstFrame(testContainerView, contentsClient, null, "");
377 
378        final CallbackHelper onScrollToCallbackHelper =
379            testContainerView.getOnScrollToCallbackHelper();
380        final int scrollToCallCount = onScrollToCallbackHelper.getCallCount();
381        AwTestTouchUtils.dragCompleteView(testContainerView,
382                0, -targetScrollXPix, // these need to be negative as we're scrolling down.
383                0, -targetScrollYPix,
384                dragSteps,
385                null /* completionLatch */);
386 
387        for (int i = 1; i <= dragSteps; ++i) {
388            onScrollToCallbackHelper.waitForCallback(scrollToCallCount, i);
389            if (checkScrollOnMainSync(testContainerView, maxScrollXPix, maxScrollYPix))
390                break;
391        }
392 
393        assertScrollOnMainSync(testContainerView, maxScrollXPix, maxScrollYPix);
394        assertScrollInJs(testContainerView.getAwContents(), contentsClient,
395                maxScrollXCss, maxScrollYCss);
396    }
397 
398    @SmallTest
399    @Feature({"AndroidWebView"})
400    public void testNoSpuriousOverScrolls() throws Throwable {
401        final TestAwContentsClient contentsClient = new TestAwContentsClient();
402        final ScrollTestContainerView testContainerView =
403            (ScrollTestContainerView) createAwTestContainerViewOnMainSync(contentsClient);
404        enableJavaScriptOnUiThread(testContainerView.getAwContents());
405 
406        final int dragSteps = 1;
407        final int targetScrollYPix = 24;
408 
409        setMaxScrollOnMainSync(testContainerView, 0, 0);
410 
411        loadTestPageAndWaitForFirstFrame(testContainerView, contentsClient, null, "");
412 
413        final CallbackHelper onScrollToCallbackHelper =
414            testContainerView.getOnScrollToCallbackHelper();
415        final int scrollToCallCount = onScrollToCallbackHelper.getCallCount();
416        CountDownLatch scrollingCompleteLatch = new CountDownLatch(1);
417        AwTestTouchUtils.dragCompleteView(testContainerView,
418                0, 0, // these need to be negative as we're scrolling down.
419                0, -targetScrollYPix,
420                dragSteps,
421                scrollingCompleteLatch);
422        try {
423            scrollingCompleteLatch.await();
424        } catch (InterruptedException ex) {
425            // ignore
426        }
427        assertEquals(scrollToCallCount + 1, onScrollToCallbackHelper.getCallCount());
428    }
429 
430    @SmallTest
431    @Feature({"AndroidWebView"})
432    public void testOverScrollX() throws Throwable {
433        final TestAwContentsClient contentsClient = new TestAwContentsClient();
434        final ScrollTestContainerView testContainerView =
435            (ScrollTestContainerView) createAwTestContainerViewOnMainSync(contentsClient);
436        final OverScrollByCallbackHelper overScrollByCallbackHelper =
437            testContainerView.getOverScrollByCallbackHelper();
438        enableJavaScriptOnUiThread(testContainerView.getAwContents());
439 
440        final int overScrollDeltaX = 30;
441        final int oneStep = 1;
442 
443        loadTestPageAndWaitForFirstFrame(testContainerView, contentsClient, null, "");
444 
445        // Scroll separately in different dimensions because of vertical/horizontal scroll
446        // snap.
447        final int overScrollCallCount = overScrollByCallbackHelper.getCallCount();
448        AwTestTouchUtils.dragCompleteView(testContainerView,
449                0, overScrollDeltaX,
450                0, 0,
451                oneStep,
452                null /* completionLatch */);
453        overScrollByCallbackHelper.waitForCallback(overScrollCallCount);
454        // Unfortunately the gesture detector seems to 'eat' some number of pixels. For now
455        // checking that the value is < 0 (overscroll is reported as negative values) will have to
456        // do.
457        assertTrue(0 > overScrollByCallbackHelper.getDeltaX());
458        assertEquals(0, overScrollByCallbackHelper.getDeltaY());
459 
460        assertScrollOnMainSync(testContainerView, 0, 0);
461    }
462 
463    @SmallTest
464    @Feature({"AndroidWebView"})
465    public void testOverScrollY() throws Throwable {
466        final TestAwContentsClient contentsClient = new TestAwContentsClient();
467        final ScrollTestContainerView testContainerView =
468            (ScrollTestContainerView) createAwTestContainerViewOnMainSync(contentsClient);
469        final OverScrollByCallbackHelper overScrollByCallbackHelper =
470            testContainerView.getOverScrollByCallbackHelper();
471        enableJavaScriptOnUiThread(testContainerView.getAwContents());
472 
473        final int overScrollDeltaY = 30;
474        final int oneStep = 1;
475 
476        loadTestPageAndWaitForFirstFrame(testContainerView, contentsClient, null, "");
477 
478        int overScrollCallCount = overScrollByCallbackHelper.getCallCount();
479        AwTestTouchUtils.dragCompleteView(testContainerView,
480                0, 0,
481                0, overScrollDeltaY,
482                oneStep,
483                null /* completionLatch */);
484        overScrollByCallbackHelper.waitForCallback(overScrollCallCount);
485        assertEquals(0, overScrollByCallbackHelper.getDeltaX());
486        assertTrue(0 > overScrollByCallbackHelper.getDeltaY());
487 
488        assertScrollOnMainSync(testContainerView, 0, 0);
489    }
490 
491    @SmallTest
492    @Feature({"AndroidWebView"})
493    public void testScrollToBottomAtPageScaleX0dot5() throws Throwable {
494        // The idea behind this test is to check that scrolling to the bottom on ther renderer side
495        // results in the view also reporting as being scrolled to the bottom.
496        final TestAwContentsClient contentsClient = new TestAwContentsClient();
497        final ScrollTestContainerView testContainerView =
498            (ScrollTestContainerView) createAwTestContainerViewOnMainSync(contentsClient);
499        enableJavaScriptOnUiThread(testContainerView.getAwContents());
500 
501        final int targetScrollXCss = 1000;
502        final int targetScrollYCss = 10000;
503 
504        final String pageHeaders =
505            "<meta name=\"viewport\" content=\"width=device-width, initial-scale=0.6\"> " +
506            "<style type=\"text/css\"> " +
507            "   div { " +
508            "      width:1000px; " +
509            "      height:10000px; " +
510            "      background-color: blue; " +
511            "   } " +
512            "   body { " +
513            "      margin: 0px; " +
514            "      padding: 0px; " +
515            "   } " +
516            "</style> ";
517 
518        loadDataSync(testContainerView.getAwContents(), contentsClient.getOnPageFinishedHelper(),
519                CommonResources.makeHtmlPageFrom(pageHeaders, TEST_PAGE_COMMON_CONTENT),
520                "text/html", false);
521 
522        final double deviceDIPScale =
523            DeviceDisplayInfo.create(testContainerView.getContext()).getDIPScale();
524 
525        final CallbackHelper onScrollToCallbackHelper =
526            testContainerView.getOnScrollToCallbackHelper();
527        final int scrollToCallCount = onScrollToCallbackHelper.getCallCount();
528        executeJavaScriptAndWaitForResult(testContainerView.getAwContents(), contentsClient,
529                "window.scrollTo(" + targetScrollXCss + "," + targetScrollYCss + ")");
530        onScrollToCallbackHelper.waitForCallback(scrollToCallCount);
531 
532        getInstrumentation().runOnMainSync(new Runnable() {
533            @Override
534            public void run() {
535                AwContents awContents = testContainerView.getAwContents();
536                int maxHorizontal = awContents.computeHorizontalScrollRange() -
537                                testContainerView.getWidth();
538                int maxVertical = awContents.computeVerticalScrollRange() -
539                                testContainerView.getHeight();
540                // Due to rounding going from CSS -> physical pixels it is possible that more than
541                // one physical pixels corespond to one CSS pixel, which is why we can't do a
542                // simple equality test here.
543                assertTrue(maxHorizontal - awContents.computeHorizontalScrollOffset() < 3);
544                assertTrue(maxVertical - awContents.computeVerticalScrollOffset() < 3);
545            }
546        });
547    }
548 
549    @SmallTest
550    @Feature({"AndroidWebView"})
551    public void testFlingScroll() throws Throwable {
552        final TestAwContentsClient contentsClient = new TestAwContentsClient();
553        final ScrollTestContainerView testContainerView =
554            (ScrollTestContainerView) createAwTestContainerViewOnMainSync(contentsClient);
555        enableJavaScriptOnUiThread(testContainerView.getAwContents());
556 
557        loadTestPageAndWaitForFirstFrame(testContainerView, contentsClient, null, "");
558 
559        assertScrollOnMainSync(testContainerView, 0, 0);
560 
561        final CallbackHelper onScrollToCallbackHelper =
562            testContainerView.getOnScrollToCallbackHelper();
563        final int scrollToCallCount = onScrollToCallbackHelper.getCallCount();
564 
565        getInstrumentation().runOnMainSync(new Runnable() {
566            @Override
567            public void run() {
568                testContainerView.getAwContents().flingScroll(1000, 1000);
569            }
570        });
571 
572        onScrollToCallbackHelper.waitForCallback(scrollToCallCount);
573 
574        getInstrumentation().runOnMainSync(new Runnable() {
575            @Override
576            public void run() {
577                assertTrue(testContainerView.getScrollX() > 0);
578                assertTrue(testContainerView.getScrollY() > 0);
579            }
580        });
581    }
582 
583    @SmallTest
584    @Feature({"AndroidWebView"})
585    public void testPageDown() throws Throwable {
586        final TestAwContentsClient contentsClient = new TestAwContentsClient();
587        final ScrollTestContainerView testContainerView =
588            (ScrollTestContainerView) createAwTestContainerViewOnMainSync(contentsClient);
589        enableJavaScriptOnUiThread(testContainerView.getAwContents());
590 
591        loadTestPageAndWaitForFirstFrame(testContainerView, contentsClient, null, "");
592 
593        assertScrollOnMainSync(testContainerView, 0, 0);
594 
595        final int maxScrollYPix = runTestOnUiThreadAndGetResult(new Callable<Integer>() {
596            @Override
597            public Integer call() {
598                return (testContainerView.getAwContents().computeVerticalScrollRange() -
599                    testContainerView.getHeight());
600            }
601        });
602 
603        final CallbackHelper onScrollToCallbackHelper =
604            testContainerView.getOnScrollToCallbackHelper();
605        final int scrollToCallCount = onScrollToCallbackHelper.getCallCount();
606 
607        getInstrumentation().runOnMainSync(new Runnable() {
608            @Override
609            public void run() {
610                testContainerView.getAwContents().pageDown(true);
611            }
612        });
613 
614        // Wait for the animation to hit the bottom of the page.
615        for (int i = 1; ; ++i) {
616            onScrollToCallbackHelper.waitForCallback(scrollToCallCount, i);
617            if (checkScrollOnMainSync(testContainerView, 0, maxScrollYPix))
618                break;
619        }
620    }
621 
622    @SmallTest
623    @Feature({"AndroidWebView"})
624    public void testPageUp() throws Throwable {
625        final TestAwContentsClient contentsClient = new TestAwContentsClient();
626        final ScrollTestContainerView testContainerView =
627            (ScrollTestContainerView) createAwTestContainerViewOnMainSync(contentsClient);
628        enableJavaScriptOnUiThread(testContainerView.getAwContents());
629 
630        final double deviceDIPScale =
631            DeviceDisplayInfo.create(testContainerView.getContext()).getDIPScale();
632        final int targetScrollYCss = 243;
633        final int targetScrollYPix = (int) Math.round(targetScrollYCss * deviceDIPScale);
634 
635        loadTestPageAndWaitForFirstFrame(testContainerView, contentsClient, null, "");
636 
637        assertScrollOnMainSync(testContainerView, 0, 0);
638 
639        scrollToOnMainSync(testContainerView, 0, targetScrollYPix);
640 
641        final CallbackHelper onScrollToCallbackHelper =
642            testContainerView.getOnScrollToCallbackHelper();
643        final int scrollToCallCount = onScrollToCallbackHelper.getCallCount();
644 
645        getInstrumentation().runOnMainSync(new Runnable() {
646            @Override
647            public void run() {
648                testContainerView.getAwContents().pageUp(true);
649            }
650        });
651 
652        // Wait for the animation to hit the bottom of the page.
653        for (int i = 1; ; ++i) {
654            onScrollToCallbackHelper.waitForCallback(scrollToCallCount, i);
655            if (checkScrollOnMainSync(testContainerView, 0, 0))
656                break;
657        }
658    }
659}

[all classes][org.chromium.android_webview.test]
EMMA 2.0.5312 (C) Vladimir Roubtsov