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