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.NullWebViewUtils;
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.ViewGroup;
25 import android.webkit.JsPromptResult;
26 import android.webkit.JsResult;
27 import android.webkit.WebIconDatabase;
28 import android.webkit.WebSettings;
29 import android.webkit.WebView;
30 import android.webkit.cts.WebViewOnUiThread.WaitForProgressClient;
31 
32 public class WebChromeClientTest extends ActivityInstrumentationTestCase2<WebViewCtsActivity> {
33     private static final long TEST_TIMEOUT = 5000L;
34 
35     private CtsTestServer mWebServer;
36     private WebIconDatabase mIconDb;
37     private WebViewOnUiThread mOnUiThread;
38     private boolean mBlockWindowCreationSync;
39     private boolean mBlockWindowCreationAsync;
40 
WebChromeClientTest()41     public WebChromeClientTest() {
42         super(WebViewCtsActivity.class);
43     }
44 
45     @Override
setUp()46     protected void setUp() throws Exception {
47         super.setUp();
48         WebView webview = getActivity().getWebView();
49         if (webview != null) {
50             mOnUiThread = new WebViewOnUiThread(this, webview);
51         }
52         mWebServer = new CtsTestServer(getActivity());
53     }
54 
55     @Override
tearDown()56     protected void tearDown() throws Exception {
57         if (mOnUiThread != null) {
58             mOnUiThread.cleanUp();
59         }
60         if (mWebServer != null) {
61             mWebServer.shutdown();
62         }
63         if (mIconDb != null) {
64             mIconDb.removeAllIcons();
65             mIconDb.close();
66         }
67         super.tearDown();
68     }
69 
testOnProgressChanged()70     public void testOnProgressChanged() {
71         if (!NullWebViewUtils.isWebViewAvailable()) {
72             return;
73         }
74         final MockWebChromeClient webChromeClient = new MockWebChromeClient();
75         mOnUiThread.setWebChromeClient(webChromeClient);
76 
77         assertFalse(webChromeClient.hadOnProgressChanged());
78         String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
79         mOnUiThread.loadUrlAndWaitForCompletion(url);
80 
81         new PollingCheck(TEST_TIMEOUT) {
82             @Override
83             protected boolean check() {
84                 return webChromeClient.hadOnProgressChanged();
85             }
86         }.run();
87     }
88 
testOnReceivedTitle()89     public void testOnReceivedTitle() throws Exception {
90         if (!NullWebViewUtils.isWebViewAvailable()) {
91             return;
92         }
93         final MockWebChromeClient webChromeClient = new MockWebChromeClient();
94         mOnUiThread.setWebChromeClient(webChromeClient);
95 
96         assertFalse(webChromeClient.hadOnReceivedTitle());
97         String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
98         mOnUiThread.loadUrlAndWaitForCompletion(url);
99 
100         new PollingCheck(TEST_TIMEOUT) {
101             @Override
102             protected boolean check() {
103                 return webChromeClient.hadOnReceivedTitle();
104             }
105         }.run();
106         assertTrue(webChromeClient.hadOnReceivedTitle());
107         assertEquals(TestHtmlConstants.HELLO_WORLD_TITLE, webChromeClient.getPageTitle());
108     }
109 
testOnReceivedIcon()110     public void testOnReceivedIcon() throws Throwable {
111         if (!NullWebViewUtils.isWebViewAvailable()) {
112             return;
113         }
114         final MockWebChromeClient webChromeClient = new MockWebChromeClient();
115         mOnUiThread.setWebChromeClient(webChromeClient);
116 
117         runTestOnUiThread(new Runnable() {
118             @Override
119             public void run() {
120                 // getInstance must run on the UI thread
121                 mIconDb = WebIconDatabase.getInstance();
122                 String dbPath = getActivity().getFilesDir().toString() + "/icons";
123                 mIconDb.open(dbPath);
124             }
125         });
126         getInstrumentation().waitForIdleSync();
127         Thread.sleep(100); // Wait for open to be received on the icon db thread.
128 
129         assertFalse(webChromeClient.hadOnReceivedIcon());
130         assertNull(mOnUiThread.getFavicon());
131 
132         String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
133         mOnUiThread.loadUrlAndWaitForCompletion(url);
134 
135         new PollingCheck(TEST_TIMEOUT) {
136             @Override
137             protected boolean check() {
138                 return webChromeClient.hadOnReceivedIcon();
139             }
140         }.run();
141         assertNotNull(mOnUiThread.getFavicon());
142     }
143 
runWindowTest(boolean expectWindowClose)144     public void runWindowTest(boolean expectWindowClose) throws Exception {
145         final MockWebChromeClient webChromeClient = new MockWebChromeClient();
146         mOnUiThread.setWebChromeClient(webChromeClient);
147 
148         final WebSettings settings = mOnUiThread.getSettings();
149         settings.setJavaScriptEnabled(true);
150         settings.setJavaScriptCanOpenWindowsAutomatically(true);
151         settings.setSupportMultipleWindows(true);
152 
153         assertFalse(webChromeClient.hadOnCreateWindow());
154 
155         // Load a page that opens a child window and sets a timeout after which the child
156         // will be closed.
157         mOnUiThread.loadUrlAndWaitForCompletion(mWebServer.
158                 getAssetUrl(TestHtmlConstants.JS_WINDOW_URL));
159 
160         new PollingCheck(TEST_TIMEOUT) {
161             @Override
162             protected boolean check() {
163                 return webChromeClient.hadOnCreateWindow();
164             }
165         }.run();
166 
167         if (expectWindowClose) {
168             new PollingCheck(TEST_TIMEOUT) {
169                 @Override
170                 protected boolean check() {
171                     return webChromeClient.hadOnCloseWindow();
172                 }
173             }.run();
174         } else {
175             assertFalse(webChromeClient.hadOnCloseWindow());
176         }
177     }
testWindows()178     public void testWindows() throws Exception {
179         if (!NullWebViewUtils.isWebViewAvailable()) {
180             return;
181         }
182         runWindowTest(true);
183     }
184 
testBlockWindowsSync()185     public void testBlockWindowsSync() throws Exception {
186         if (!NullWebViewUtils.isWebViewAvailable()) {
187             return;
188         }
189         mBlockWindowCreationSync = true;
190         runWindowTest(false);
191     }
192 
testBlockWindowsAsync()193     public void testBlockWindowsAsync() throws Exception {
194         if (!NullWebViewUtils.isWebViewAvailable()) {
195             return;
196         }
197         mBlockWindowCreationAsync = true;
198         runWindowTest(false);
199     }
200 
testOnJsBeforeUnloadIsCalled()201     public void testOnJsBeforeUnloadIsCalled() throws Exception {
202         if (!NullWebViewUtils.isWebViewAvailable()) {
203             return;
204         }
205         final MockWebChromeClient webChromeClient = new MockWebChromeClient();
206         mOnUiThread.setWebChromeClient(webChromeClient);
207 
208         final WebSettings settings = mOnUiThread.getSettings();
209         settings.setJavaScriptEnabled(true);
210         settings.setJavaScriptCanOpenWindowsAutomatically(true);
211 
212         assertFalse(webChromeClient.hadOnJsBeforeUnload());
213 
214         mOnUiThread.loadUrlAndWaitForCompletion(mWebServer.getAssetUrl(TestHtmlConstants.JS_UNLOAD_URL));
215         // unload should trigger when we try to navigate away
216         mOnUiThread.loadUrlAndWaitForCompletion(mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL));
217 
218         new PollingCheck(TEST_TIMEOUT) {
219             @Override
220             protected boolean check() {
221                 return webChromeClient.hadOnJsBeforeUnload();
222             }
223         }.run();
224     }
225 
testOnJsAlert()226     public void testOnJsAlert() throws Exception {
227         if (!NullWebViewUtils.isWebViewAvailable()) {
228             return;
229         }
230         final MockWebChromeClient webChromeClient = new MockWebChromeClient();
231         mOnUiThread.setWebChromeClient(webChromeClient);
232 
233         final WebSettings settings = mOnUiThread.getSettings();
234         settings.setJavaScriptEnabled(true);
235         settings.setJavaScriptCanOpenWindowsAutomatically(true);
236 
237         assertFalse(webChromeClient.hadOnJsAlert());
238 
239         String url = mWebServer.getAssetUrl(TestHtmlConstants.JS_ALERT_URL);
240         mOnUiThread.loadUrlAndWaitForCompletion(url);
241 
242         new PollingCheck(TEST_TIMEOUT) {
243             @Override
244             protected boolean check() {
245                 return webChromeClient.hadOnJsAlert();
246             }
247         }.run();
248         assertEquals(webChromeClient.getMessage(), "testOnJsAlert");
249     }
250 
testOnJsConfirm()251     public void testOnJsConfirm() throws Exception {
252         if (!NullWebViewUtils.isWebViewAvailable()) {
253             return;
254         }
255         final MockWebChromeClient webChromeClient = new MockWebChromeClient();
256         mOnUiThread.setWebChromeClient(webChromeClient);
257 
258         final WebSettings settings = mOnUiThread.getSettings();
259         settings.setJavaScriptEnabled(true);
260         settings.setJavaScriptCanOpenWindowsAutomatically(true);
261 
262         assertFalse(webChromeClient.hadOnJsConfirm());
263 
264         String url = mWebServer.getAssetUrl(TestHtmlConstants.JS_CONFIRM_URL);
265         mOnUiThread.loadUrlAndWaitForCompletion(url);
266 
267         new PollingCheck(TEST_TIMEOUT) {
268             @Override
269             protected boolean check() {
270                 return webChromeClient.hadOnJsConfirm();
271             }
272         }.run();
273         assertEquals(webChromeClient.getMessage(), "testOnJsConfirm");
274     }
275 
testOnJsPrompt()276     public void testOnJsPrompt() throws Exception {
277         if (!NullWebViewUtils.isWebViewAvailable()) {
278             return;
279         }
280         final MockWebChromeClient webChromeClient = new MockWebChromeClient();
281         mOnUiThread.setWebChromeClient(webChromeClient);
282 
283         final WebSettings settings = mOnUiThread.getSettings();
284         settings.setJavaScriptEnabled(true);
285         settings.setJavaScriptCanOpenWindowsAutomatically(true);
286 
287         assertFalse(webChromeClient.hadOnJsPrompt());
288 
289         final String promptResult = "CTS";
290         webChromeClient.setPromptResult(promptResult);
291         String url = mWebServer.getAssetUrl(TestHtmlConstants.JS_PROMPT_URL);
292         mOnUiThread.loadUrlAndWaitForCompletion(url);
293 
294         new PollingCheck(TEST_TIMEOUT) {
295             @Override
296             protected boolean check() {
297                 return webChromeClient.hadOnJsPrompt();
298             }
299         }.run();
300         // the result returned by the client gets set as the page title
301         new PollingCheck(TEST_TIMEOUT) {
302             @Override
303             protected boolean check() {
304                 return mOnUiThread.getTitle().equals(promptResult);
305             }
306         }.run();
307         assertEquals(webChromeClient.getMessage(), "testOnJsPrompt");
308     }
309 
310     private class MockWebChromeClient extends WaitForProgressClient {
311         private boolean mHadOnProgressChanged;
312         private boolean mHadOnReceivedTitle;
313         private String mPageTitle;
314         private boolean mHadOnJsAlert;
315         private boolean mHadOnJsConfirm;
316         private boolean mHadOnJsPrompt;
317         private boolean mHadOnJsBeforeUnload;
318         private String mMessage;
319         private String mPromptResult;
320         private boolean mHadOnCloseWindow;
321         private boolean mHadOnCreateWindow;
322         private boolean mHadOnRequestFocus;
323         private boolean mHadOnReceivedIcon;
324 
MockWebChromeClient()325         public MockWebChromeClient() {
326             super(mOnUiThread);
327         }
328 
setPromptResult(String promptResult)329         public void setPromptResult(String promptResult) {
330             mPromptResult = promptResult;
331         }
332 
hadOnProgressChanged()333         public boolean hadOnProgressChanged() {
334             return mHadOnProgressChanged;
335         }
336 
hadOnReceivedTitle()337         public boolean hadOnReceivedTitle() {
338             return mHadOnReceivedTitle;
339         }
340 
getPageTitle()341         public String getPageTitle() {
342             return mPageTitle;
343         }
344 
hadOnJsAlert()345         public boolean hadOnJsAlert() {
346             return mHadOnJsAlert;
347         }
348 
hadOnJsConfirm()349         public boolean hadOnJsConfirm() {
350             return mHadOnJsConfirm;
351         }
352 
hadOnJsPrompt()353         public boolean hadOnJsPrompt() {
354             return mHadOnJsPrompt;
355         }
356 
hadOnJsBeforeUnload()357         public boolean hadOnJsBeforeUnload() {
358             return mHadOnJsBeforeUnload;
359         }
360 
hadOnCreateWindow()361         public boolean hadOnCreateWindow() {
362             return mHadOnCreateWindow;
363         }
364 
hadOnCloseWindow()365         public boolean hadOnCloseWindow() {
366             return mHadOnCloseWindow;
367         }
368 
hadOnRequestFocus()369         public boolean hadOnRequestFocus() {
370             return mHadOnRequestFocus;
371         }
372 
hadOnReceivedIcon()373         public boolean hadOnReceivedIcon() {
374             return mHadOnReceivedIcon;
375         }
376 
getMessage()377         public String getMessage() {
378             return mMessage;
379         }
380 
381         @Override
onProgressChanged(WebView view, int newProgress)382         public void onProgressChanged(WebView view, int newProgress) {
383             super.onProgressChanged(view, newProgress);
384             mHadOnProgressChanged = true;
385         }
386 
387         @Override
onReceivedTitle(WebView view, String title)388         public void onReceivedTitle(WebView view, String title) {
389             super.onReceivedTitle(view, title);
390             mPageTitle = title;
391             mHadOnReceivedTitle = true;
392         }
393 
394         @Override
onJsAlert(WebView view, String url, String message, JsResult result)395         public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
396             super.onJsAlert(view, url, message, result);
397             mHadOnJsAlert = true;
398             mMessage = message;
399             result.confirm();
400             return true;
401         }
402 
403         @Override
onJsConfirm(WebView view, String url, String message, JsResult result)404         public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
405             super.onJsConfirm(view, url, message, result);
406             mHadOnJsConfirm = true;
407             mMessage = message;
408             result.confirm();
409             return true;
410         }
411 
412         @Override
onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result)413         public boolean onJsPrompt(WebView view, String url, String message,
414                 String defaultValue, JsPromptResult result) {
415             super.onJsPrompt(view, url, message, defaultValue, result);
416             mHadOnJsPrompt = true;
417             mMessage = message;
418             result.confirm(mPromptResult);
419             return true;
420         }
421 
422         @Override
onJsBeforeUnload(WebView view, String url, String message, JsResult result)423         public boolean onJsBeforeUnload(WebView view, String url, String message, JsResult result) {
424             super.onJsBeforeUnload(view, url, message, result);
425             mHadOnJsBeforeUnload = true;
426             mMessage = message;
427             result.confirm();
428             return true;
429         }
430 
431         @Override
onCloseWindow(WebView window)432         public void onCloseWindow(WebView window) {
433             super.onCloseWindow(window);
434             mHadOnCloseWindow = true;
435         }
436 
437         @Override
onCreateWindow(WebView view, boolean dialog, boolean userGesture, Message resultMsg)438         public boolean onCreateWindow(WebView view, boolean dialog, boolean userGesture,
439                 Message resultMsg) {
440             mHadOnCreateWindow = true;
441             if (mBlockWindowCreationSync) {
442                 return false;
443             }
444             WebView.WebViewTransport transport = (WebView.WebViewTransport) resultMsg.obj;
445             if (mBlockWindowCreationAsync) {
446                 transport.setWebView(null);
447             } else {
448                 WebView childView = new WebView(getActivity());
449                 final WebSettings settings = childView.getSettings();
450                 settings.setJavaScriptEnabled(true);
451                 childView.setWebChromeClient(this);
452                 transport.setWebView(childView);
453                 getActivity().addContentView(childView, new ViewGroup.LayoutParams(
454                         ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
455             }
456             resultMsg.sendToTarget();
457             return true;
458         }
459 
460         @Override
onRequestFocus(WebView view)461         public void onRequestFocus(WebView view) {
462             mHadOnRequestFocus = true;
463         }
464 
465         @Override
onReceivedIcon(WebView view, Bitmap icon)466         public void onReceivedIcon(WebView view, Bitmap icon) {
467             mHadOnReceivedIcon = true;
468         }
469     }
470 }
471