1e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer/* 2e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer * Copyright 2018 The Android Open Source Project 3e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer * 4e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer * Licensed under the Apache License, Version 2.0 (the "License"); 5e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer * you may not use this file except in compliance with the License. 6e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer * You may obtain a copy of the License at 7e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer * 8e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer * http://www.apache.org/licenses/LICENSE-2.0 9e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer * 10e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer * Unless required by applicable law or agreed to in writing, software 11e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer * distributed under the License is distributed on an "AS IS" BASIS, 12e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer * See the License for the specific language governing permissions and 14e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer * limitations under the License. 15e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer */ 16e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer 17e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischerpackage androidx.webkit; 18e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer 19e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischerimport android.graphics.Bitmap; 20e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischerimport android.net.Uri; 21e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischerimport android.support.test.filters.MediumTest; 22e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischerimport android.support.test.runner.AndroidJUnit4; 23e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischerimport android.webkit.ValueCallback; 24e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischerimport android.webkit.WebResourceRequest; 25e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischerimport android.webkit.WebResourceResponse; 26e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischerimport android.webkit.WebView; 27e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischerimport android.webkit.WebViewClient; 28e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer 29e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischerimport org.junit.Assert; 30e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischerimport org.junit.Assume; 31e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischerimport org.junit.Before; 32e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischerimport org.junit.Test; 33e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischerimport org.junit.runner.RunWith; 34e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer 35e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischerimport java.util.HashMap; 36e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischerimport java.util.Map; 37e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischerimport java.util.concurrent.CountDownLatch; 38e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischerimport java.util.concurrent.TimeUnit; 39e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer 40e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer@MediumTest 41e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer@RunWith(AndroidJUnit4.class) 42e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischerpublic class WebViewClientCompatTest { 43e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer private WebViewOnUiThread mWebViewOnUiThread; 44e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer 45e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer private static final long TEST_TIMEOUT = 20000L; 46e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer private static final String TEST_URL = "http://www.example.com/"; 47e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer private static final String TEST_SAFE_BROWSING_URL = 48e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer "chrome://safe-browsing/match?type=malware"; 49e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer 50e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer @Before 51e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer public void setUp() { 52e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer mWebViewOnUiThread = new WebViewOnUiThread(); 53e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer } 54e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer 55e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer @Test 56e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer public void testShouldOverrideUrlLoadingDefault() { 57e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer // This never calls into chromium, so we don't need to do any feature checks. 58e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer 59e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer final MockWebViewClient webViewClient = new MockWebViewClient(); 60e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer 61e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer // Create any valid WebResourceRequest, the return values don't matter much. 62e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer final WebResourceRequest resourceRequest = new WebResourceRequest() { 63e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer @Override 64e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer public Uri getUrl() { 65e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer return Uri.parse(TEST_URL); 66e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer } 67e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer 68e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer @Override 69e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer public boolean isForMainFrame() { 70e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer return false; 71e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer } 72e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer 73e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer @Override 74e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer public boolean isRedirect() { 75e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer return false; 76e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer } 77e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer 78e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer @Override 79e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer public boolean hasGesture() { 80e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer return false; 81e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer } 82e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer 83e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer @Override 84e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer public String getMethod() { 85e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer return "GET"; 86e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer } 87e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer 88e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer @Override 89e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer public Map<String, String> getRequestHeaders() { 90e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer return new HashMap<String, String>(); 91e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer } 92e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer }; 93e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer 94e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer Assert.assertFalse(webViewClient.shouldOverrideUrlLoading( 95e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer mWebViewOnUiThread.getWebViewOnCurrentThread(), resourceRequest)); 96e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer } 97e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer 98e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer @Test 99e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer public void testShouldOverrideUrlLoading() throws InterruptedException { 100e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer Assume.assumeTrue( 101e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer WebViewFeature.isFeatureSupported(WebViewFeature.SHOULD_OVERRIDE_WITH_REDIRECTS)); 102e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer Assume.assumeTrue( 103e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer WebViewFeature.isFeatureSupported(WebViewFeature.WEB_RESOURCE_REQUEST_IS_REDIRECT)); 104e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer 105e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer String data = "<html><body>" 106e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer + "<a href=\"" + TEST_URL + "\" id=\"link\">new page</a>" 107e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer + "</body></html>"; 108e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer mWebViewOnUiThread.loadDataAndWaitForCompletion(data, "text/html", null); 109302ebcc433c33d90c81a2c4db3993233b348808fNate Fischer final CountDownLatch pageFinishedLatch = new CountDownLatch(1); 110302ebcc433c33d90c81a2c4db3993233b348808fNate Fischer final MockWebViewClient webViewClient = new MockWebViewClient() { 111302ebcc433c33d90c81a2c4db3993233b348808fNate Fischer @Override 112302ebcc433c33d90c81a2c4db3993233b348808fNate Fischer public void onPageFinished(WebView view, String url) { 113302ebcc433c33d90c81a2c4db3993233b348808fNate Fischer super.onPageFinished(view, url); 114302ebcc433c33d90c81a2c4db3993233b348808fNate Fischer pageFinishedLatch.countDown(); 115302ebcc433c33d90c81a2c4db3993233b348808fNate Fischer } 116302ebcc433c33d90c81a2c4db3993233b348808fNate Fischer }; 117302ebcc433c33d90c81a2c4db3993233b348808fNate Fischer mWebViewOnUiThread.setWebViewClient(webViewClient); 118302ebcc433c33d90c81a2c4db3993233b348808fNate Fischer mWebViewOnUiThread.getSettings().setJavaScriptEnabled(true); 119e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer clickOnLinkUsingJs("link", mWebViewOnUiThread); 120302ebcc433c33d90c81a2c4db3993233b348808fNate Fischer pageFinishedLatch.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS); 121e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer Assert.assertEquals(TEST_URL, 122e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer webViewClient.getLastShouldOverrideResourceRequest().getUrl().toString()); 123e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer 124e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer WebResourceRequest request = webViewClient.getLastShouldOverrideResourceRequest(); 125e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer Assert.assertNotNull(request); 126e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer Assert.assertTrue(request.isForMainFrame()); 127e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer Assert.assertFalse(WebResourceRequestCompat.isRedirect(request)); 128e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer Assert.assertFalse(request.hasGesture()); 129e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer } 130e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer 131e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer private void clickOnLinkUsingJs(final String linkId, WebViewOnUiThread webViewOnUiThread) 132e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer throws InterruptedException { 133e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer final CountDownLatch callbackLatch = new CountDownLatch(1); 134e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer ValueCallback<String> callback = new ValueCallback<String>() { 135e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer @Override 136e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer public void onReceiveValue(String value) { 137e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer callbackLatch.countDown(); 138e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer } 139e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer }; 140e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer webViewOnUiThread.evaluateJavascript( 141e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer "document.getElementById('" + linkId + "').click();" 142e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer + "console.log('element with id [" + linkId + "] clicked');", callback); 143e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer Assert.assertTrue(callbackLatch.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS)); 144e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer } 145e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer 146e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer @Test 147e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer public void testOnReceivedError() throws Exception { 148e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer Assume.assumeTrue( 149e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer WebViewFeature.isFeatureSupported(WebViewFeature.RECEIVE_WEB_RESOURCE_ERROR)); 150e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer Assume.assumeTrue( 151e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer WebViewFeature.isFeatureSupported(WebViewFeature.WEB_RESOURCE_ERROR_GET_CODE)); 152e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer 153e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer final MockWebViewClient webViewClient = new MockWebViewClient(); 154e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer mWebViewOnUiThread.setWebViewClient(webViewClient); 155e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer 156e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer String wrongUri = "invalidscheme://some/resource"; 157e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer Assert.assertNull(webViewClient.getOnReceivedResourceError()); 158e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer mWebViewOnUiThread.loadUrlAndWaitForCompletion(wrongUri); 159e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer Assert.assertNotNull(webViewClient.getOnReceivedResourceError()); 160e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer Assert.assertEquals(WebViewClient.ERROR_UNSUPPORTED_SCHEME, 161e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer webViewClient.getOnReceivedResourceError().getErrorCode()); 162e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer } 163e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer 164e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer @Test 165e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer public void testOnReceivedErrorForSubresource() throws Exception { 166e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer Assume.assumeTrue( 167e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer WebViewFeature.isFeatureSupported(WebViewFeature.RECEIVE_WEB_RESOURCE_ERROR)); 168e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer 169e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer final MockWebViewClient webViewClient = new MockWebViewClient(); 170e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer mWebViewOnUiThread.setWebViewClient(webViewClient); 171e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer 172e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer Assert.assertNull(webViewClient.getOnReceivedResourceError()); 173e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer String data = "<html>" 174e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer + " <body>" 175e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer + " <img src=\"invalidscheme://some/resource\" />" 176e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer + " </body>" 177e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer + "</html>"; 178e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer 179e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer mWebViewOnUiThread.loadDataAndWaitForCompletion(data, "text/html", null); 180e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer Assert.assertNotNull(webViewClient.getOnReceivedResourceError()); 181e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer Assert.assertEquals(WebViewClient.ERROR_UNSUPPORTED_SCHEME, 182e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer webViewClient.getOnReceivedResourceError().getErrorCode()); 183e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer } 184e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer 185e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer @Test 186d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer public void testOnSafeBrowsingHitBackToSafety() throws Throwable { 187e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer Assume.assumeTrue(WebViewFeature.isFeatureSupported(WebViewFeature.SAFE_BROWSING_HIT)); 188e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer Assume.assumeTrue(WebViewFeature.isFeatureSupported(WebViewFeature.SAFE_BROWSING_ENABLE)); 189d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer Assume.assumeTrue(WebViewFeature.isFeatureSupported( 190d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer WebViewFeature.SAFE_BROWSING_RESPONSE_BACK_TO_SAFETY)); 191e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer Assume.assumeTrue( 192e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer WebViewFeature.isFeatureSupported(WebViewFeature.WEB_RESOURCE_ERROR_GET_CODE)); 193e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer 194e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer final SafeBrowsingBackToSafetyClient backToSafetyWebViewClient = 195e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer new SafeBrowsingBackToSafetyClient(); 196e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer mWebViewOnUiThread.setWebViewClient(backToSafetyWebViewClient); 197e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer WebSettingsCompat.setSafeBrowsingEnabled(mWebViewOnUiThread.getSettings(), true); 198e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer 199e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer // Load any page 200e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer String data = "<html><body>some safe page</body></html>"; 201e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer mWebViewOnUiThread.loadDataAndWaitForCompletion(data, "text/html", null); 202e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer final String originalUrl = mWebViewOnUiThread.getUrl(); 203e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer 204d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer enableSafeBrowsingAndLoadUnsafePage(backToSafetyWebViewClient); 205d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer 206d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer // Back to safety should produce a network error 207d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer Assert.assertNotNull(backToSafetyWebViewClient.getOnReceivedResourceError()); 208d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer Assert.assertEquals(WebViewClient.ERROR_UNSAFE_RESOURCE, 209d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer backToSafetyWebViewClient.getOnReceivedResourceError().getErrorCode()); 210d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer 211d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer // Check that we actually navigated backward 212d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer Assert.assertEquals(originalUrl, mWebViewOnUiThread.getUrl()); 213d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer } 214d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer 215d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer @Test 216d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer public void testOnSafeBrowsingHitProceed() throws Throwable { 217d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer Assume.assumeTrue(WebViewFeature.isFeatureSupported(WebViewFeature.SAFE_BROWSING_HIT)); 218d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer Assume.assumeTrue(WebViewFeature.isFeatureSupported(WebViewFeature.SAFE_BROWSING_ENABLE)); 219d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer Assume.assumeTrue(WebViewFeature.isFeatureSupported( 220d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer WebViewFeature.SAFE_BROWSING_RESPONSE_PROCEED)); 221e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer 222e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer final SafeBrowsingProceedClient proceedWebViewClient = new SafeBrowsingProceedClient(); 223e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer mWebViewOnUiThread.setWebViewClient(proceedWebViewClient); 224d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer WebSettingsCompat.setSafeBrowsingEnabled(mWebViewOnUiThread.getSettings(), true); 225e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer 226d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer // Load any page 227d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer String data = "<html><body>some safe page</body></html>"; 228d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer mWebViewOnUiThread.loadDataAndWaitForCompletion(data, "text/html", null); 229e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer 230d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer enableSafeBrowsingAndLoadUnsafePage(proceedWebViewClient); 231e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer 232d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer // Check that we actually proceeded 233d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer Assert.assertEquals(TEST_SAFE_BROWSING_URL, mWebViewOnUiThread.getUrl()); 234d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer } 235d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer 236d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer private void enableSafeBrowsingAndLoadUnsafePage(SafeBrowsingClient client) throws Throwable { 237d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer // Note: Safe Browsing depends on user opt-in as well, so we can't assume it's actually 238d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer // enabled. #getSafeBrowsingEnabled will tell us the true state of whether Safe Browsing is 239d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer // enabled. 240d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer boolean deviceSupportsSafeBrowsing = 241d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer WebSettingsCompat.getSafeBrowsingEnabled(mWebViewOnUiThread.getSettings()); 242d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer Assume.assumeTrue(deviceSupportsSafeBrowsing); 243d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer 244d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer Assert.assertNull(client.getOnReceivedResourceError()); 245d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer mWebViewOnUiThread.loadUrlAndWaitForCompletion(TEST_SAFE_BROWSING_URL); 246d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer 247d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer Assert.assertEquals(TEST_SAFE_BROWSING_URL, 248d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer client.getOnSafeBrowsingHitRequest().getUrl().toString()); 249d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer Assert.assertTrue(client.getOnSafeBrowsingHitRequest().isForMainFrame()); 250e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer } 251e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer 252e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer @Test 253e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer public void testOnPageCommitVisibleCalled() throws Exception { 254e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer Assume.assumeTrue(WebViewFeature.isFeatureSupported(WebViewFeature.VISUAL_STATE_CALLBACK)); 255e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer 256e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer final CountDownLatch callbackLatch = new CountDownLatch(1); 257e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer 258e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer mWebViewOnUiThread.setWebViewClient(new WebViewClientCompat() { 259e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer @Override 260e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer public void onPageCommitVisible(WebView view, String url) { 261e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer Assert.assertEquals(url, "about:blank"); 262e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer callbackLatch.countDown(); 263e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer } 264e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer }); 265e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer 266e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer mWebViewOnUiThread.loadUrl("about:blank"); 267e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer Assert.assertTrue(callbackLatch.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS)); 268e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer } 269e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer 270e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer private class MockWebViewClient extends WebViewOnUiThread.WaitForLoadedClient { 271e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer private boolean mOnPageStartedCalled; 272e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer private boolean mOnPageFinishedCalled; 273e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer private boolean mOnLoadResourceCalled; 274e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer private WebResourceErrorCompat mOnReceivedResourceError; 275e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer private WebResourceResponse mOnReceivedHttpError; 276e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer private WebResourceRequest mLastShouldOverrideResourceRequest; 277e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer 278e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer MockWebViewClient() { 279e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer super(mWebViewOnUiThread); 280e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer } 281e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer 282e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer public WebResourceErrorCompat getOnReceivedResourceError() { 283e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer return mOnReceivedResourceError; 284e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer } 285e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer 286e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer public WebResourceResponse getOnReceivedHttpError() { 287e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer return mOnReceivedHttpError; 288e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer } 289e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer 290e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer public WebResourceRequest getLastShouldOverrideResourceRequest() { 291e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer return mLastShouldOverrideResourceRequest; 292e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer } 293e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer 294e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer @Override 295e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer public void onPageStarted(WebView view, String url, Bitmap favicon) { 296e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer super.onPageStarted(view, url, favicon); 297e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer mOnPageStartedCalled = true; 298e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer } 299e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer 300e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer @Override 301e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer public void onPageFinished(WebView view, String url) { 302e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer super.onPageFinished(view, url); 303e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer Assert.assertTrue(mOnPageStartedCalled); 304e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer Assert.assertTrue(mOnLoadResourceCalled); 305e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer mOnPageFinishedCalled = true; 306e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer } 307e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer 308e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer @Override 309e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer public void onLoadResource(WebView view, String url) { 310e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer super.onLoadResource(view, url); 311e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer Assert.assertTrue(mOnPageStartedCalled); 312e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer mOnLoadResourceCalled = true; 313e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer } 314e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer 315e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer @Override 316e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer @SuppressWarnings("deprecation") 317e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer public void onReceivedError(WebView view, int errorCode, 318e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer String description, String failingUrl) { 319e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer // This can be called if a test runs for a WebView which does not support the {@link 320e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer // WebViewFeature#RECEIVE_WEB_RESOURCE_ERROR} feature. 321e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer } 322e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer 323e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer @Override 324e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer public void onReceivedError(WebView view, WebResourceRequest request, 325e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer WebResourceErrorCompat error) { 326e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer mOnReceivedResourceError = error; 327e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer } 328e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer 329e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer @Override 330e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer public void onReceivedHttpError(WebView view, WebResourceRequest request, 331e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer WebResourceResponse errorResponse) { 332e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer super.onReceivedHttpError(view, request, errorResponse); 333e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer mOnReceivedHttpError = errorResponse; 334e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer } 335e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer 336e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer @Override 337e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer @SuppressWarnings("deprecation") 338e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer public boolean shouldOverrideUrlLoading(WebView view, String url) { 339e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer // This can be called if a test runs for a WebView which does not support the {@link 340e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer // WebViewFeature#SHOULD_OVERRIDE_WITH_REDIRECTS} feature. 341e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer return false; 342e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer } 343e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer 344e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer @Override 345e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { 346e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer mLastShouldOverrideResourceRequest = request; 347e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer return false; 348e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer } 349e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer } 350e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer 351d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer private class SafeBrowsingClient extends MockWebViewClient { 352e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer private WebResourceRequest mOnSafeBrowsingHitRequest; 353e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer private int mOnSafeBrowsingHitThreatType; 354e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer 355e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer public WebResourceRequest getOnSafeBrowsingHitRequest() { 356e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer return mOnSafeBrowsingHitRequest; 357e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer } 358e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer 359d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer public void setOnSafeBrowsingHitRequest(WebResourceRequest request) { 360d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer mOnSafeBrowsingHitRequest = request; 361d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer } 362d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer 363e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer public int getOnSafeBrowsingHitThreatType() { 364e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer return mOnSafeBrowsingHitThreatType; 365e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer } 366e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer 367d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer public void setOnSafeBrowsingHitThreatType(int type) { 368d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer mOnSafeBrowsingHitThreatType = type; 369d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer } 370d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer } 371d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer 372d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer private class SafeBrowsingBackToSafetyClient extends SafeBrowsingClient { 373e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer @Override 374e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer public void onSafeBrowsingHit(WebView view, WebResourceRequest request, 375e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer int threatType, SafeBrowsingResponseCompat response) { 376e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer // Immediately go back to safety to return the network error code 377d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer setOnSafeBrowsingHitRequest(request); 378d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer setOnSafeBrowsingHitThreatType(threatType); 379e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer response.backToSafety(/* report */ true); 380e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer } 381e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer } 382e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer 383d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer private class SafeBrowsingProceedClient extends SafeBrowsingClient { 384e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer @Override 385e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer public void onSafeBrowsingHit(WebView view, WebResourceRequest request, 386e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer int threatType, SafeBrowsingResponseCompat response) { 387e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer // Proceed through Safe Browsing warnings 388d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer setOnSafeBrowsingHitRequest(request); 389d2cb2ed027d1e90e87f7bd9413f73bafef6ef7c8Nate Fischer setOnSafeBrowsingHitThreatType(threatType); 390e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer response.proceed(/* report */ true); 391e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer } 392e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer } 393e7734de3cf9236fbba6af94873d9ada4a4a89af1Nate Fischer} 394