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 5 package org.chromium.content.browser; 6 7 import android.content.res.Configuration; 8 import android.graphics.Canvas; 9 import android.os.SystemClock; 10 import android.test.suitebuilder.annotation.SmallTest; 11 import android.view.KeyEvent; 12 import android.view.MotionEvent; 13 import android.view.View; 14 15 import org.chromium.base.test.util.Feature; 16 import org.chromium.base.test.util.UrlUtils; 17 import org.chromium.content.browser.ContentViewCore.InternalAccessDelegate; 18 import org.chromium.content.browser.test.util.Criteria; 19 import org.chromium.content.browser.test.util.CriteriaHelper; 20 import org.chromium.content_shell_apk.ContentShellTestBase; 21 22 /* 23 * Tests that we can scroll and fling a ContentView running inside ContentShell. 24 */ 25 public 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 MIN_THRESHOLD = 5; 109 final int MAX_THRESHOLD = 100; 110 111 boolean xCorrect = hugLeft ? 112 getContentViewCore().getNativeScrollXForTest() < MIN_THRESHOLD : 113 getContentViewCore().getNativeScrollXForTest() > MAX_THRESHOLD; 114 boolean yCorrect = hugTop ? 115 getContentViewCore().getNativeScrollYForTest() < MIN_THRESHOLD : 116 getContentViewCore().getNativeScrollYForTest() > MAX_THRESHOLD; 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 getContentView().fling(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 getContentView().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 // Vertical fling to lower-left. 156 fling(0, -1000); 157 assertWaitForScroll(true, false); 158 159 // Horizontal fling to lower-right. 160 fling(-1000, 0); 161 assertWaitForScroll(false, false); 162 163 // Vertical fling to upper-right. 164 fling(0, 1000); 165 assertWaitForScroll(false, true); 166 167 // Horizontal fling to top-left. 168 fling(1000, 0); 169 assertWaitForScroll(true, true); 170 171 // Diagonal fling to bottom-right. 172 fling(-1000, -1000); 173 assertWaitForScroll(false, false); 174 } 175 176 @SmallTest 177 @Feature({"Main"}) 178 public void testScroll() throws Throwable { 179 // Vertical scroll to lower-left. 180 scrollTo(0, 2500); 181 assertWaitForScroll(true, false); 182 183 // Horizontal scroll to lower-right. 184 scrollTo(2500, 2500); 185 assertWaitForScroll(false, false); 186 187 // Vertical scroll to upper-right. 188 scrollTo(2500, 0); 189 assertWaitForScroll(false, true); 190 191 // Horizontal scroll to top-left. 192 scrollTo(0, 0); 193 assertWaitForScroll(true, true); 194 195 // Diagonal scroll to bottom-right. 196 scrollTo(2500, 2500); 197 assertWaitForScroll(false, false); 198 } 199 200 /** 201 * To ensure the AccessibilityEvent notifications (Eg:TYPE_VIEW_SCROLLED) are being sent 202 * properly on scrolling a page. 203 */ 204 @SmallTest 205 @Feature({"Main"}) 206 public void testOnScrollChanged() throws Throwable { 207 final int scrollToX = 2500; 208 final int scrollToY = 2500; 209 final TestInternalAccessDelegate containerViewInternals = new TestInternalAccessDelegate(); 210 runTestOnUiThread(new Runnable() { 211 @Override 212 public void run() { 213 getContentViewCore().setContainerViewInternals(containerViewInternals); 214 } 215 }); 216 scrollTo(scrollToX, scrollToY); 217 assertWaitForScroll(false, false); 218 assertTrue(CriteriaHelper.pollForCriteria(new Criteria() { 219 @Override 220 public boolean isSatisfied() { 221 return containerViewInternals.isScrollChanged(); 222 } 223 })); 224 } 225 } 226