ContentViewScrollingTest.java revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
1// Copyright 2012 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.content.browser;
6
7import android.content.res.Configuration;
8import android.graphics.Canvas;
9import android.os.SystemClock;
10import android.test.suitebuilder.annotation.SmallTest;
11import android.view.KeyEvent;
12import android.view.MotionEvent;
13import android.view.View;
14
15import org.chromium.base.test.util.Feature;
16import org.chromium.base.test.util.UrlUtils;
17import org.chromium.content.browser.ContentViewCore.InternalAccessDelegate;
18import org.chromium.content.browser.test.util.Criteria;
19import org.chromium.content.browser.test.util.CriteriaHelper;
20import org.chromium.content_shell_apk.ContentShellTestBase;
21
22/**
23 * Tests that we can scroll and fling a ContentView running inside ContentShell.
24 */
25public class ContentViewScrollingTest extends ContentShellTestBase {
26
27    private static final String LARGE_PAGE = UrlUtils.encodeHtmlDataUri(
28            "<html><head>" +
29            "<meta name=\"viewport\" content=\"width=device-width, " +
30            "initial-scale=2.0, maximum-scale=2.0\" />" +
31            "<style>body { width: 5000px; height: 5000px; }</style></head>" +
32            "<body>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</body>" +
33            "</html>");
34
35    /**
36     * InternalAccessDelegate to ensure AccessibilityEvent notifications (Eg:TYPE_VIEW_SCROLLED)
37     * are being sent properly on scrolling a page.
38     */
39    static class TestInternalAccessDelegate implements InternalAccessDelegate {
40
41        private boolean mScrollChanged;
42        private final Object mLock = new Object();
43
44
45
46        @Override
47        public boolean drawChild(Canvas canvas, View child, long drawingTime) {
48            return false;
49        }
50
51        @Override
52        public boolean super_onKeyUp(int keyCode, KeyEvent event) {
53            return false;
54        }
55
56        @Override
57        public boolean super_dispatchKeyEventPreIme(KeyEvent event) {
58            return false;
59        }
60
61        @Override
62        public boolean super_dispatchKeyEvent(KeyEvent event) {
63            return false;
64        }
65
66        @Override
67        public boolean super_onGenericMotionEvent(MotionEvent event) {
68            return false;
69        }
70
71        @Override
72        public void super_onConfigurationChanged(Configuration newConfig) {
73        }
74
75        @Override
76        public void onScrollChanged(int lPix, int tPix, int oldlPix, int oldtPix) {
77            synchronized (mLock) {
78                mScrollChanged = true;
79            }
80        }
81
82        @Override
83        public boolean awakenScrollBars() {
84            return false;
85        }
86
87        @Override
88        public boolean super_awakenScrollBars(int startDelay, boolean invalidate) {
89            return false;
90        }
91
92        /**
93         * @return Whether OnScrollChanged() has been called.
94         */
95        public boolean isScrollChanged() {
96            synchronized (mLock) {
97                return mScrollChanged;
98            }
99        }
100    }
101
102    private void assertWaitForScroll(final boolean hugLeft, final boolean hugTop)
103            throws InterruptedException {
104        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
105            @Override
106            public boolean isSatisfied() {
107                // Scrolling and flinging don't result in exact coordinates.
108                final int minThreshold = 5;
109                final int maxThreshold = 100;
110
111                boolean xCorrect = hugLeft ?
112                        getContentViewCore().getNativeScrollXForTest() < minThreshold :
113                        getContentViewCore().getNativeScrollXForTest() > maxThreshold;
114                boolean yCorrect = hugTop ?
115                        getContentViewCore().getNativeScrollYForTest() < minThreshold :
116                        getContentViewCore().getNativeScrollYForTest() > maxThreshold;
117                return xCorrect && yCorrect;
118            }
119        }));
120    }
121
122    private void fling(final int vx, final int vy) throws Throwable {
123        runTestOnUiThread(new Runnable() {
124            @Override
125            public void run() {
126                getContentViewCore().flingForTest(SystemClock.uptimeMillis(), 0, 0, vx, vy);
127            }
128        });
129    }
130
131    private void scrollTo(final int x, final int y) throws Throwable {
132        runTestOnUiThread(new Runnable() {
133            @Override
134            public void run() {
135                getContentViewCore().getContainerView().scrollTo(x, y);
136            }
137        });
138    }
139
140    @Override
141    protected void setUp() throws Exception {
142        super.setUp();
143
144        launchContentShellWithUrl(LARGE_PAGE);
145        assertTrue("Page failed to load", waitForActiveShellToBeDoneLoading());
146        assertWaitForPageScaleFactorMatch(2.0f);
147
148        assertEquals(0, getContentViewCore().getNativeScrollXForTest());
149        assertEquals(0, getContentViewCore().getNativeScrollYForTest());
150    }
151
152    @SmallTest
153    @Feature({"Main"})
154    public void testFling() throws Throwable {
155        // Scaling the initial velocity by the device scale factor ensures that
156        // it's of sufficient magnitude for all displays densities.
157        float deviceScaleFactor =
158                getInstrumentation().getTargetContext().getResources().getDisplayMetrics().density;
159        int velocity = (int) (1000 * deviceScaleFactor);
160
161        // Vertical fling to lower-left.
162        fling(0, -velocity);
163        assertWaitForScroll(true, false);
164
165        // Horizontal fling to lower-right.
166        fling(-velocity, 0);
167        assertWaitForScroll(false, false);
168
169        // Vertical fling to upper-right.
170        fling(0, velocity);
171        assertWaitForScroll(false, true);
172
173        // Horizontal fling to top-left.
174        fling(velocity, 0);
175        assertWaitForScroll(true, true);
176
177        // Diagonal fling to bottom-right.
178        fling(-velocity, -velocity);
179        assertWaitForScroll(false, false);
180    }
181
182    @SmallTest
183    @RerunWithUpdatedContainerView
184    @Feature({"Main"})
185    public void testScroll() throws Throwable {
186        // Vertical scroll to lower-left.
187        scrollTo(0, 2500);
188        assertWaitForScroll(true, false);
189
190        // Horizontal scroll to lower-right.
191        scrollTo(2500, 2500);
192        assertWaitForScroll(false, false);
193
194        // Vertical scroll to upper-right.
195        scrollTo(2500, 0);
196        assertWaitForScroll(false, true);
197
198        // Horizontal scroll to top-left.
199        scrollTo(0, 0);
200        assertWaitForScroll(true, true);
201
202        // Diagonal scroll to bottom-right.
203        scrollTo(2500, 2500);
204        assertWaitForScroll(false, false);
205    }
206
207    /**
208     * To ensure the device properly responds to bounds-exceeding scrolls, e.g., overscroll
209     * effects are properly initialized.
210     */
211    @SmallTest
212    @RerunWithUpdatedContainerView
213    @Feature({"Main"})
214    public void testOverScroll() throws Throwable {
215        // Overscroll lower-left.
216        scrollTo(-10000, 10000);
217        assertWaitForScroll(true, false);
218
219        // Overscroll lower-right.
220        scrollTo(10000, 10000);
221        assertWaitForScroll(false, false);
222
223        // Overscroll upper-right.
224        scrollTo(10000, -10000);
225        assertWaitForScroll(false, true);
226
227        // Overscroll top-left.
228        scrollTo(-10000, -10000);
229        assertWaitForScroll(true, true);
230
231        // Diagonal overscroll lower-right.
232        scrollTo(10000, 10000);
233        assertWaitForScroll(false, false);
234    }
235
236    /**
237     * To ensure the AccessibilityEvent notifications (Eg:TYPE_VIEW_SCROLLED) are being sent
238     * properly on scrolling a page.
239     */
240    @SmallTest
241    @RerunWithUpdatedContainerView
242    @Feature({"Main"})
243    public void testOnScrollChanged() throws Throwable {
244        final int scrollToX = getContentViewCore().getNativeScrollXForTest() + 2500;
245        final int scrollToY = getContentViewCore().getNativeScrollYForTest() + 2500;
246        final TestInternalAccessDelegate containerViewInternals = new TestInternalAccessDelegate();
247        runTestOnUiThread(new Runnable() {
248            @Override
249            public void run() {
250                getContentViewCore().setContainerViewInternals(containerViewInternals);
251            }
252        });
253        scrollTo(scrollToX, scrollToY);
254        assertWaitForScroll(false, false);
255        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
256            @Override
257            public boolean isSatisfied() {
258                return containerViewInternals.isScrollChanged();
259            }
260        }));
261    }
262}
263