1 /* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.webkit.cts; 18 19 import android.cts.util.EvaluateJsResultPollingCheck; 20 import android.cts.util.PollingCheck; 21 import android.graphics.Bitmap; 22 import android.os.Message; 23 import android.test.ActivityInstrumentationTestCase2; 24 import android.view.KeyEvent; 25 import android.view.ViewGroup; 26 import android.webkit.HttpAuthHandler; 27 import android.webkit.ValueCallback; 28 import android.webkit.WebChromeClient; 29 import android.webkit.WebSettings; 30 import android.webkit.WebView; 31 import android.webkit.WebViewClient; 32 import android.webkit.cts.WebViewOnUiThread.WaitForLoadedClient; 33 34 35 public class WebViewClientTest extends ActivityInstrumentationTestCase2<WebViewStubActivity> { 36 private static final long TEST_TIMEOUT = 5000; 37 private static final String TEST_URL = "http://foo.com/"; 38 39 private WebViewOnUiThread mOnUiThread; 40 private CtsTestServer mWebServer; 41 42 public WebViewClientTest() { 43 super("com.android.cts.stub", WebViewStubActivity.class); 44 } 45 46 @Override 47 protected void setUp() throws Exception { 48 super.setUp(); 49 final WebViewStubActivity activity = getActivity(); 50 new PollingCheck(TEST_TIMEOUT) { 51 @Override 52 protected boolean check() { 53 return activity.hasWindowFocus(); 54 } 55 }.run(); 56 mOnUiThread = new WebViewOnUiThread(this, activity.getWebView()); 57 } 58 59 @Override 60 protected void tearDown() throws Exception { 61 mOnUiThread.cleanUp(); 62 if (mWebServer != null) { 63 mWebServer.shutdown(); 64 } 65 super.tearDown(); 66 } 67 68 // Verify that the shouldoverrideurlloading is false by default 69 public void testShouldOverrideUrlLoadingDefault() { 70 final WebViewClient webViewClient = new WebViewClient(); 71 assertFalse(webViewClient.shouldOverrideUrlLoading(mOnUiThread.getWebView(), null)); 72 } 73 74 // Verify shouldoverrideurlloading called on top level navigation 75 public void testShouldOverrideUrlLoading() { 76 final MockWebViewClient webViewClient = new MockWebViewClient(); 77 mOnUiThread.setWebViewClient(webViewClient); 78 mOnUiThread.getSettings().setJavaScriptEnabled(true); 79 String data = "<html><body>" + 80 "<a href=\"" + TEST_URL + "\" id=\"link\">new page</a>" + 81 "</body></html>"; 82 mOnUiThread.loadDataAndWaitForCompletion(data, "text/html", null); 83 clickOnLinkUsingJs("link"); 84 assertEquals(TEST_URL, webViewClient.getLastShouldOverrideUrl()); 85 } 86 87 // Verify shouldoverrideurlloading called on webview called via onCreateWindow 88 public void testShouldOverrideUrlLoadingOnCreateWindow() throws Exception { 89 mWebServer = new CtsTestServer(getActivity()); 90 // WebViewClient for main window 91 final MockWebViewClient mainWebViewClient = new MockWebViewClient(); 92 // WebViewClient for child window 93 final MockWebViewClient childWebViewClient = new MockWebViewClient(); 94 mOnUiThread.setWebViewClient(mainWebViewClient); 95 mOnUiThread.getSettings().setJavaScriptEnabled(true); 96 mOnUiThread.getSettings().setJavaScriptCanOpenWindowsAutomatically(true); 97 mOnUiThread.getSettings().setSupportMultipleWindows(true); 98 mOnUiThread.setWebChromeClient(new WebChromeClient() { 99 @Override 100 public boolean onCreateWindow( 101 WebView view, boolean isDialog, boolean isUserGesture, Message resultMsg) { 102 WebView.WebViewTransport transport = (WebView.WebViewTransport) resultMsg.obj; 103 WebView childWebView = new WebView(view.getContext()); 104 childWebView.setWebViewClient(childWebViewClient); 105 childWebView.getSettings().setJavaScriptEnabled(true); 106 transport.setWebView(childWebView); 107 getActivity().addContentView(childWebView, new ViewGroup.LayoutParams( 108 ViewGroup.LayoutParams.FILL_PARENT, 109 ViewGroup.LayoutParams.WRAP_CONTENT)); 110 resultMsg.sendToTarget(); 111 return true; 112 } 113 }); 114 mOnUiThread.loadUrl(mWebServer.getAssetUrl(TestHtmlConstants.BLANK_TAG_URL)); 115 116 new PollingCheck(TEST_TIMEOUT) { 117 @Override 118 protected boolean check() { 119 return childWebViewClient.hasOnPageFinishedCalled(); 120 } 121 }.run(); 122 assertEquals(mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL), 123 childWebViewClient.getLastShouldOverrideUrl()); 124 } 125 126 private void clickOnLinkUsingJs(final String linkId) { 127 EvaluateJsResultPollingCheck jsResult = new EvaluateJsResultPollingCheck("null"); 128 mOnUiThread.evaluateJavascript( 129 "document.getElementById('" + linkId + "').click();" + 130 "console.log('element with id [" + linkId + "] clicked');", jsResult); 131 jsResult.run(); 132 } 133 134 public void testLoadPage() throws Exception { 135 final MockWebViewClient webViewClient = new MockWebViewClient(); 136 mOnUiThread.setWebViewClient(webViewClient); 137 mWebServer = new CtsTestServer(getActivity()); 138 String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL); 139 140 assertFalse(webViewClient.hasOnPageStartedCalled()); 141 assertFalse(webViewClient.hasOnLoadResourceCalled()); 142 assertFalse(webViewClient.hasOnPageFinishedCalled()); 143 mOnUiThread.loadUrlAndWaitForCompletion(url); 144 145 new PollingCheck(TEST_TIMEOUT) { 146 @Override 147 protected boolean check() { 148 return webViewClient.hasOnPageStartedCalled(); 149 } 150 }.run(); 151 152 new PollingCheck(TEST_TIMEOUT) { 153 @Override 154 protected boolean check() { 155 return webViewClient.hasOnLoadResourceCalled(); 156 } 157 }.run(); 158 159 new PollingCheck(TEST_TIMEOUT) { 160 @Override 161 protected boolean check() { 162 return webViewClient.hasOnPageFinishedCalled(); 163 } 164 }.run(); 165 } 166 167 public void testOnReceivedError() throws Exception { 168 final MockWebViewClient webViewClient = new MockWebViewClient(); 169 mOnUiThread.setWebViewClient(webViewClient); 170 171 String wrongUri = "invalidscheme://some/resource"; 172 assertEquals(0, webViewClient.hasOnReceivedErrorCode()); 173 mOnUiThread.loadUrlAndWaitForCompletion(wrongUri); 174 assertEquals(WebViewClient.ERROR_UNSUPPORTED_SCHEME, 175 webViewClient.hasOnReceivedErrorCode()); 176 } 177 178 public void testOnFormResubmission() throws Exception { 179 final MockWebViewClient webViewClient = new MockWebViewClient(); 180 mOnUiThread.setWebViewClient(webViewClient); 181 final WebSettings settings = mOnUiThread.getSettings(); 182 settings.setJavaScriptEnabled(true); 183 mWebServer = new CtsTestServer(getActivity()); 184 185 assertFalse(webViewClient.hasOnFormResubmissionCalled()); 186 String url = mWebServer.getAssetUrl(TestHtmlConstants.JS_FORM_URL); 187 // this loads a form, which automatically posts itself 188 mOnUiThread.loadUrlAndWaitForCompletion(url); 189 // wait for JavaScript to post the form 190 mOnUiThread.waitForLoadCompletion(); 191 // the URL should have changed when the form was posted 192 assertFalse(url.equals(mOnUiThread.getUrl())); 193 // reloading the current URL should trigger the callback 194 mOnUiThread.reload(); 195 new PollingCheck(TEST_TIMEOUT) { 196 @Override 197 protected boolean check() { 198 return webViewClient.hasOnFormResubmissionCalled(); 199 } 200 }.run(); 201 } 202 203 public void testDoUpdateVisitedHistory() throws Exception { 204 final MockWebViewClient webViewClient = new MockWebViewClient(); 205 mOnUiThread.setWebViewClient(webViewClient); 206 mWebServer = new CtsTestServer(getActivity()); 207 208 assertFalse(webViewClient.hasDoUpdateVisitedHistoryCalled()); 209 String url1 = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL); 210 String url2 = mWebServer.getAssetUrl(TestHtmlConstants.BR_TAG_URL); 211 mOnUiThread.loadUrlAndWaitForCompletion(url1); 212 mOnUiThread.loadUrlAndWaitForCompletion(url2); 213 new PollingCheck(TEST_TIMEOUT) { 214 @Override 215 protected boolean check() { 216 return webViewClient.hasDoUpdateVisitedHistoryCalled(); 217 } 218 }.run(); 219 } 220 221 public void testOnReceivedHttpAuthRequest() throws Exception { 222 final MockWebViewClient webViewClient = new MockWebViewClient(); 223 mOnUiThread.setWebViewClient(webViewClient); 224 mWebServer = new CtsTestServer(getActivity()); 225 226 assertFalse(webViewClient.hasOnReceivedHttpAuthRequestCalled()); 227 String url = mWebServer.getAuthAssetUrl(TestHtmlConstants.EMBEDDED_IMG_URL); 228 mOnUiThread.loadUrlAndWaitForCompletion(url); 229 assertTrue(webViewClient.hasOnReceivedHttpAuthRequestCalled()); 230 } 231 232 public void testShouldOverrideKeyEvent() { 233 final MockWebViewClient webViewClient = new MockWebViewClient(); 234 mOnUiThread.setWebViewClient(webViewClient); 235 236 assertFalse(webViewClient.shouldOverrideKeyEvent(mOnUiThread.getWebView(), null)); 237 } 238 239 public void testOnUnhandledKeyEvent() throws Throwable { 240 requireLoadedPage(); 241 final MockWebViewClient webViewClient = new MockWebViewClient(); 242 mOnUiThread.setWebViewClient(webViewClient); 243 244 mOnUiThread.requestFocus(); 245 getInstrumentation().waitForIdleSync(); 246 247 assertFalse(webViewClient.hasOnUnhandledKeyEventCalled()); 248 sendKeys(KeyEvent.KEYCODE_1); 249 250 new PollingCheck(TEST_TIMEOUT) { 251 @Override 252 protected boolean check() { 253 return webViewClient.hasOnUnhandledKeyEventCalled(); 254 } 255 }.run(); 256 } 257 258 public void testOnScaleChanged() throws Throwable { 259 final MockWebViewClient webViewClient = new MockWebViewClient(); 260 mOnUiThread.setWebViewClient(webViewClient); 261 mWebServer = new CtsTestServer(getActivity()); 262 263 assertFalse(webViewClient.hasOnScaleChangedCalled()); 264 String url1 = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL); 265 mOnUiThread.loadUrlAndWaitForCompletion(url1); 266 267 mOnUiThread.zoomIn(); 268 new PollingCheck(TEST_TIMEOUT) { 269 @Override 270 protected boolean check() { 271 return webViewClient.hasOnScaleChangedCalled(); 272 } 273 }.run(); 274 } 275 276 private void requireLoadedPage() throws Throwable { 277 mOnUiThread.loadUrlAndWaitForCompletion("about:blank"); 278 } 279 280 private class MockWebViewClient extends WaitForLoadedClient { 281 private boolean mOnPageStartedCalled; 282 private boolean mOnPageFinishedCalled; 283 private boolean mOnLoadResourceCalled; 284 private int mOnReceivedErrorCode; 285 private boolean mOnFormResubmissionCalled; 286 private boolean mDoUpdateVisitedHistoryCalled; 287 private boolean mOnReceivedHttpAuthRequestCalled; 288 private boolean mOnUnhandledKeyEventCalled; 289 private boolean mOnScaleChangedCalled; 290 private String mLastShouldOverrideUrl; 291 292 public MockWebViewClient() { 293 super(mOnUiThread); 294 } 295 296 public boolean hasOnPageStartedCalled() { 297 return mOnPageStartedCalled; 298 } 299 300 public boolean hasOnPageFinishedCalled() { 301 return mOnPageFinishedCalled; 302 } 303 304 public boolean hasOnLoadResourceCalled() { 305 return mOnLoadResourceCalled; 306 } 307 308 public int hasOnReceivedErrorCode() { 309 return mOnReceivedErrorCode; 310 } 311 312 public boolean hasOnFormResubmissionCalled() { 313 return mOnFormResubmissionCalled; 314 } 315 316 public boolean hasDoUpdateVisitedHistoryCalled() { 317 return mDoUpdateVisitedHistoryCalled; 318 } 319 320 public boolean hasOnReceivedHttpAuthRequestCalled() { 321 return mOnReceivedHttpAuthRequestCalled; 322 } 323 324 public boolean hasOnUnhandledKeyEventCalled() { 325 return mOnUnhandledKeyEventCalled; 326 } 327 328 public boolean hasOnScaleChangedCalled() { 329 return mOnScaleChangedCalled; 330 } 331 332 public String getLastShouldOverrideUrl() { 333 return mLastShouldOverrideUrl; 334 } 335 336 @Override 337 public void onPageStarted(WebView view, String url, Bitmap favicon) { 338 super.onPageStarted(view, url, favicon); 339 mOnPageStartedCalled = true; 340 } 341 342 @Override 343 public void onPageFinished(WebView view, String url) { 344 super.onPageFinished(view, url); 345 assertTrue(mOnPageStartedCalled); 346 assertTrue(mOnLoadResourceCalled); 347 mOnPageFinishedCalled = true; 348 } 349 350 @Override 351 public void onLoadResource(WebView view, String url) { 352 super.onLoadResource(view, url); 353 assertTrue(mOnPageStartedCalled); 354 mOnLoadResourceCalled = true; 355 } 356 357 @Override 358 public void onReceivedError(WebView view, int errorCode, 359 String description, String failingUrl) { 360 super.onReceivedError(view, errorCode, description, failingUrl); 361 mOnReceivedErrorCode = errorCode; 362 } 363 364 @Override 365 public void onFormResubmission(WebView view, Message dontResend, Message resend) { 366 mOnFormResubmissionCalled = true; 367 dontResend.sendToTarget(); 368 } 369 370 @Override 371 public void doUpdateVisitedHistory(WebView view, String url, boolean isReload) { 372 super.doUpdateVisitedHistory(view, url, isReload); 373 mDoUpdateVisitedHistoryCalled = true; 374 } 375 376 @Override 377 public void onReceivedHttpAuthRequest(WebView view, 378 HttpAuthHandler handler, String host, String realm) { 379 super.onReceivedHttpAuthRequest(view, handler, host, realm); 380 mOnReceivedHttpAuthRequestCalled = true; 381 } 382 383 @Override 384 public void onUnhandledKeyEvent(WebView view, KeyEvent event) { 385 super.onUnhandledKeyEvent(view, event); 386 mOnUnhandledKeyEventCalled = true; 387 } 388 389 @Override 390 public void onScaleChanged(WebView view, float oldScale, float newScale) { 391 super.onScaleChanged(view, oldScale, newScale); 392 mOnScaleChangedCalled = true; 393 } 394 395 @Override 396 public boolean shouldOverrideUrlLoading(WebView view, String url) { 397 mLastShouldOverrideUrl = url; 398 return false; 399 } 400 } 401 } 402