• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 dalvik.annotation.BrokenTest;
20 import dalvik.annotation.TestLevel;
21 import dalvik.annotation.TestTargetClass;
22 import dalvik.annotation.TestTargetNew;
23 import dalvik.annotation.TestTargets;
24 import dalvik.annotation.ToBeFixed;
25 
26 import android.content.Context;
27 import android.content.res.AssetManager;
28 import android.graphics.Bitmap;
29 import android.graphics.BitmapFactory;
30 import android.graphics.Canvas;
31 import android.graphics.Color;
32 import android.graphics.Picture;
33 import android.graphics.Rect;
34 import android.graphics.Bitmap.Config;
35 import android.net.http.SslCertificate;
36 import android.os.Bundle;
37 import android.os.Handler;
38 import android.os.Looper;
39 import android.os.Message;
40 import android.test.ActivityInstrumentationTestCase2;
41 import android.test.UiThreadTest;
42 import android.util.AttributeSet;
43 import android.util.DisplayMetrics;
44 import android.view.KeyEvent;
45 import android.view.MotionEvent;
46 import android.view.View;
47 import android.view.animation.cts.DelayedCheck;
48 import android.webkit.CacheManager;
49 import android.webkit.DownloadListener;
50 import android.webkit.WebBackForwardList;
51 import android.webkit.WebChromeClient;
52 import android.webkit.WebSettings;
53 import android.webkit.WebView;
54 import android.webkit.WebViewClient;
55 import android.webkit.WebViewDatabase;
56 import android.webkit.WebView.HitTestResult;
57 import android.webkit.WebView.PictureListener;
58 import android.widget.AutoCompleteTextView;
59 import android.widget.LinearLayout;
60 
61 import java.io.File;
62 import java.io.FileInputStream;
63 
64 @TestTargetClass(android.webkit.WebView.class)
65 public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewStubActivity> {
66     private static final int INITIAL_PROGRESS = 100;
67     private static long TEST_TIMEOUT = 20000L;
68     private static long TIME_FOR_LAYOUT = 1000L;
69 
70     private WebView mWebView;
71     private CtsTestServer mWebServer;
72 
WebViewTest()73     public WebViewTest() {
74         super("com.android.cts.stub", WebViewStubActivity.class);
75     }
76 
77     @Override
setUp()78     protected void setUp() throws Exception {
79         super.setUp();
80         mWebView = getActivity().getWebView();
81         File f = getActivity().getFileStreamPath("snapshot");
82         if (f.exists()) {
83             f.delete();
84         }
85     }
86 
87     @Override
tearDown()88     protected void tearDown() throws Exception {
89         mWebView.clearHistory();
90         mWebView.clearCache(true);
91         if (mWebServer != null) {
92             mWebServer.shutdown();
93         }
94         super.tearDown();
95     }
96 
startWebServer(boolean secure)97     private void startWebServer(boolean secure) throws Exception {
98         assertNull(mWebServer);
99         mWebServer = new CtsTestServer(getActivity(), secure);
100     }
101 
102     @TestTargets({
103         @TestTargetNew(
104             level = TestLevel.COMPLETE,
105             method = "WebView",
106             args = {Context.class}
107         ),
108         @TestTargetNew(
109             level = TestLevel.COMPLETE,
110             method = "WebView",
111             args = {Context.class, AttributeSet.class}
112         ),
113         @TestTargetNew(
114             level = TestLevel.COMPLETE,
115             method = "WebView",
116             args = {Context.class, AttributeSet.class, int.class}
117         )
118     })
testConstructor()119     public void testConstructor() {
120         new WebView(getActivity());
121         new WebView(getActivity(), null);
122         new WebView(getActivity(), null, 0);
123     }
124 
125     @TestTargetNew(
126         level = TestLevel.COMPLETE,
127         method = "findAddress",
128         args = {String.class}
129     )
testFindAddress()130     public void testFindAddress() {
131         /*
132          * Info about USPS
133          * http://en.wikipedia.org/wiki/Postal_address#United_States
134          * http://www.usps.com/
135          */
136         // full address
137         assertEquals("455 LARKSPUR DRIVE CALIFORNIA SPRINGS CALIFORNIA 92926",
138                 WebView.findAddress("455 LARKSPUR DRIVE CALIFORNIA SPRINGS CALIFORNIA 92926"));
139         // full address ( with abbreviated street type and state)
140         assertEquals("455 LARKSPUR DR CALIFORNIA SPRINGS CA 92926",
141                 WebView.findAddress("455 LARKSPUR DR CALIFORNIA SPRINGS CA 92926"));
142         // misspell the state ( CALIFORNIA -> CALIFONIA )
143         assertNull(WebView.findAddress("455 LARKSPUR DRIVE CALIFORNIA SPRINGS CALIFONIA 92926"));
144         // without optional zip code
145         assertEquals("455 LARKSPUR DR CALIFORNIA SPRINGS CA",
146                 WebView.findAddress("455 LARKSPUR DR CALIFORNIA SPRINGS CA"));
147         // house number, street name and street type are missing
148         assertNull(WebView.findAddress("CALIFORNIA SPRINGS CA"));
149         // city & state are missing
150         assertNull(WebView.findAddress("455 LARKSPUR DR"));
151     }
152 
153     @TestTargets({
154         @TestTargetNew(
155             level = TestLevel.SUFFICIENT,
156             method = "getZoomControls",
157             args = {}
158         ),
159         @TestTargetNew(
160             level = TestLevel.COMPLETE,
161             method = "getSettings",
162             args = {}
163         )
164     })
165     @SuppressWarnings("deprecation")
166     @UiThreadTest
testGetZoomControls()167     public void testGetZoomControls() {
168          WebSettings settings = mWebView.getSettings();
169          assertTrue(settings.supportZoom());
170          View zoomControls = mWebView.getZoomControls();
171          assertNotNull(zoomControls);
172 
173          // disable zoom support
174          settings.setSupportZoom(false);
175          assertFalse(settings.supportZoom());
176          assertNull(mWebView.getZoomControls());
177     }
178 
179     @TestTargetNew(
180         level = TestLevel.SUFFICIENT,
181         method = "invokeZoomPicker",
182         args = {},
183         notes = "Cannot test the effect of this method"
184     )
testInvokeZoomPicker()185     public void testInvokeZoomPicker() throws Exception {
186         WebSettings settings = mWebView.getSettings();
187         assertTrue(settings.supportZoom());
188         startWebServer(false);
189         String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
190         assertLoadUrlSuccessfully(mWebView, url);
191         mWebView.invokeZoomPicker();
192     }
193 
194     @TestTargets({
195         @TestTargetNew(
196             level = TestLevel.COMPLETE,
197             method = "zoomIn",
198             args = {}
199         ),
200         @TestTargetNew(
201             level = TestLevel.COMPLETE,
202             method = "zoomOut",
203             args = {}
204         ),
205         @TestTargetNew(
206             level = TestLevel.COMPLETE,
207             method = "getScale",
208             args = {}
209         ),
210         @TestTargetNew(
211             level = TestLevel.COMPLETE,
212             method = "getSettings",
213             args = {}
214         )
215     })
216     @UiThreadTest
testZoom()217     public void testZoom() {
218         WebSettings settings = mWebView.getSettings();
219         settings.setSupportZoom(false);
220         assertFalse(settings.supportZoom());
221         float currScale = mWebView.getScale();
222         float previousScale = currScale;
223 
224         // can zoom in or out although zoom support is disabled in web settings
225         assertTrue(mWebView.zoomIn());
226         currScale = mWebView.getScale();
227         assertTrue(currScale > previousScale);
228 
229         // zoom in
230         assertTrue(mWebView.zoomOut());
231         previousScale = currScale;
232         currScale = mWebView.getScale();
233         assertTrue(currScale < previousScale);
234 
235         // enable zoom support
236         settings.setSupportZoom(true);
237         assertTrue(settings.supportZoom());
238         currScale = mWebView.getScale();
239 
240         assertTrue(mWebView.zoomIn());
241         previousScale = currScale;
242         currScale = mWebView.getScale();
243         assertTrue(currScale > previousScale);
244 
245         // zoom in until it reaches maximum scale
246         while (currScale > previousScale) {
247             mWebView.zoomIn();
248             previousScale = currScale;
249             currScale = mWebView.getScale();
250         }
251 
252         // can not zoom in further
253         assertFalse(mWebView.zoomIn());
254         previousScale = currScale;
255         currScale = mWebView.getScale();
256         assertEquals(currScale, previousScale);
257 
258         // zoom out
259         assertTrue(mWebView.zoomOut());
260         previousScale = currScale;
261         currScale = mWebView.getScale();
262         assertTrue(currScale < previousScale);
263 
264         // zoom out until it reaches minimum scale
265         while (currScale < previousScale) {
266             mWebView.zoomOut();
267             previousScale = currScale;
268             currScale = mWebView.getScale();
269         }
270 
271         // can not zoom out further
272         assertFalse(mWebView.zoomOut());
273         previousScale = currScale;
274         currScale = mWebView.getScale();
275         assertEquals(currScale, previousScale);
276     }
277 
278     @TestTargets({
279         @TestTargetNew(
280             level = TestLevel.COMPLETE,
281             method = "setScrollBarStyle",
282             args = {int.class}
283         ),
284         @TestTargetNew(
285             level = TestLevel.COMPLETE,
286             method = "overlayHorizontalScrollbar",
287             args = {}
288         ),
289         @TestTargetNew(
290             level = TestLevel.COMPLETE,
291             method = "overlayVerticalScrollbar",
292             args = {}
293         )
294     })
295     @UiThreadTest
296     public void testSetScrollBarStyle() {
297         mWebView.setScrollBarStyle(View.SCROLLBARS_INSIDE_INSET);
298         assertFalse(mWebView.overlayHorizontalScrollbar());
299         assertFalse(mWebView.overlayVerticalScrollbar());
300 
301         mWebView.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
302         assertTrue(mWebView.overlayHorizontalScrollbar());
303         assertTrue(mWebView.overlayVerticalScrollbar());
304 
305         mWebView.setScrollBarStyle(View.SCROLLBARS_OUTSIDE_INSET);
306         assertFalse(mWebView.overlayHorizontalScrollbar());
307         assertFalse(mWebView.overlayVerticalScrollbar());
308 
309         mWebView.setScrollBarStyle(View.SCROLLBARS_OUTSIDE_OVERLAY);
310         assertTrue(mWebView.overlayHorizontalScrollbar());
311         assertTrue(mWebView.overlayVerticalScrollbar());
312     }
313 
314     @TestTargets({
315         @TestTargetNew(
316             level = TestLevel.COMPLETE,
317             method = "setHorizontalScrollbarOverlay",
318             args = {boolean.class}
319         ),
320         @TestTargetNew(
321             level = TestLevel.COMPLETE,
322             method = "setVerticalScrollbarOverlay",
323             args = {boolean.class}
324         ),
325         @TestTargetNew(
326             level = TestLevel.COMPLETE,
327             method = "overlayHorizontalScrollbar",
328             args = {}
329         ),
330         @TestTargetNew(
331             level = TestLevel.COMPLETE,
332             method = "overlayVerticalScrollbar",
333             args = {}
334         )
335     })
336     public void testScrollBarOverlay() throws Throwable {
337         DisplayMetrics metrics = mWebView.getContext().getResources().getDisplayMetrics();
338         int dimension = 2 * Math.max(metrics.widthPixels, metrics.heightPixels);
339 
340         String p = "<p style=\"height:" + dimension + "px;" +
341                 "width:" + dimension + "px;margin:0px auto;\">Test scroll bar overlay.</p>";
342         mWebView.loadData("<html><body>" + p + "</body></html>", "text/html", "UTF-8");
343         waitForLoadComplete(mWebView, TEST_TIMEOUT);
344         assertTrue(mWebView.overlayHorizontalScrollbar());
345         assertFalse(mWebView.overlayVerticalScrollbar());
346         int startX = mWebView.getScrollX();
347         int startY = mWebView.getScrollY();
348 
349         final int bigVelocity = 10000;
350         // fling to the max and wait for ending scroll
351         runTestOnUiThread(new Runnable() {
352             public void run() {
353                 mWebView.flingScroll(bigVelocity, bigVelocity);
354             }
355         });
356         getInstrumentation().waitForIdleSync();
357 
358         int overlayOffsetX = mWebView.getScrollX() - startX;
359         int insetOffsetY = mWebView.getScrollY() - startY;
360 
361         // scroll back
362         runTestOnUiThread(new Runnable() {
363             public void run() {
364                 mWebView.flingScroll(-bigVelocity, -bigVelocity);
365             }
366         });
367         getInstrumentation().waitForIdleSync();
368 
369         mWebView.setHorizontalScrollbarOverlay(false);
370         mWebView.setVerticalScrollbarOverlay(true);
371         assertFalse(mWebView.overlayHorizontalScrollbar());
372         assertTrue(mWebView.overlayVerticalScrollbar());
373 
374         // fling to the max and wait for ending scroll
375         runTestOnUiThread(new Runnable() {
376             public void run() {
377                 mWebView.flingScroll(bigVelocity, bigVelocity);
378             }
379         });
380         getInstrumentation().waitForIdleSync();
381 
382         int insetOffsetX = mWebView.getScrollX() - startX;
383         int overlayOffsetY = mWebView.getScrollY() - startY;
384 
385         assertTrue(overlayOffsetY > insetOffsetY);
386         assertTrue(overlayOffsetX > insetOffsetX);
387     }
388 
389     @TestTargets({
390         @TestTargetNew(
391             level = TestLevel.COMPLETE,
392             method = "loadUrl",
393             args = {String.class}
394         ),
395         @TestTargetNew(
396             level = TestLevel.COMPLETE,
397             method = "getUrl",
398             args = {}
399         ),
400         @TestTargetNew(
401             level = TestLevel.COMPLETE,
402             method = "getOriginalUrl",
403             args = {}
404         ),
405         @TestTargetNew(
406             level = TestLevel.COMPLETE,
407             method = "getProgress",
408             args = {}
409         )
410     })
testLoadUrl()411     public void testLoadUrl() throws Exception {
412         assertNull(mWebView.getUrl());
413         assertNull(mWebView.getOriginalUrl());
414         assertEquals(INITIAL_PROGRESS, mWebView.getProgress());
415 
416         startWebServer(false);
417         String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
418         mWebView.loadUrl(url);
419         waitForLoadComplete(mWebView, TEST_TIMEOUT);
420         assertEquals(100, mWebView.getProgress());
421         assertEquals(url, mWebView.getUrl());
422         assertEquals(url, mWebView.getOriginalUrl());
423         assertEquals(TestHtmlConstants.HELLO_WORLD_TITLE, mWebView.getTitle());
424     }
425 
426     @TestTargets({
427         @TestTargetNew(
428             level = TestLevel.COMPLETE,
429             method = "getUrl",
430             args = {}
431         ),
432         @TestTargetNew(
433             level = TestLevel.COMPLETE,
434             method = "getOriginalUrl",
435             args = {}
436         )
437     })
testGetOriginalUrl()438     public void testGetOriginalUrl() throws Exception {
439         assertNull(mWebView.getUrl());
440         assertNull(mWebView.getOriginalUrl());
441 
442         startWebServer(false);
443         String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
444         String redirect = mWebServer.getRedirectingAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
445         // set the web view client so that redirects are loaded in the WebView itself
446         mWebView.setWebViewClient(new WebViewClient());
447         mWebView.loadUrl(redirect);
448 
449         waitForLoadComplete(mWebView, TEST_TIMEOUT);
450         assertEquals(url, mWebView.getUrl());
451         assertEquals(redirect, mWebView.getOriginalUrl());
452     }
453 
454     @TestTargetNew(
455         level = TestLevel.COMPLETE,
456         method = "stopLoading",
457         args = {}
458     )
testStopLoading()459     public void testStopLoading() throws Exception {
460         assertNull(mWebView.getUrl());
461         assertEquals(INITIAL_PROGRESS, mWebView.getProgress());
462 
463         startWebServer(false);
464         String url = mWebServer.getDelayedAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
465         mWebView.loadUrl(url);
466         mWebView.stopLoading();
467         new DelayedCheck() {
468             @Override
469             protected boolean check() {
470                 return 100 == mWebView.getProgress();
471             }
472         }.run();
473         assertNull(mWebView.getUrl());
474     }
475 
476     @TestTargets({
477         @TestTargetNew(
478             level = TestLevel.COMPLETE,
479             method = "canGoBack",
480             args = {}
481         ),
482         @TestTargetNew(
483             level = TestLevel.COMPLETE,
484             method = "canGoForward",
485             args = {}
486         ),
487         @TestTargetNew(
488             level = TestLevel.COMPLETE,
489             method = "canGoBackOrForward",
490             args = {int.class}
491         ),
492         @TestTargetNew(
493             level = TestLevel.COMPLETE,
494             method = "goBack",
495             args = {}
496         ),
497         @TestTargetNew(
498             level = TestLevel.COMPLETE,
499             method = "goForward",
500             args = {}
501         ),
502         @TestTargetNew(
503             level = TestLevel.COMPLETE,
504             method = "goBackOrForward",
505             args = {int.class}
506         )
507     })
testGoBackAndForward()508     public void testGoBackAndForward() throws Exception {
509         assertGoBackOrForwardBySteps(false, -1);
510         assertGoBackOrForwardBySteps(false, 1);
511 
512         startWebServer(false);
513         String url1 = mWebServer.getAssetUrl(TestHtmlConstants.HTML_URL1);
514         String url2 = mWebServer.getAssetUrl(TestHtmlConstants.HTML_URL2);
515         String url3 = mWebServer.getAssetUrl(TestHtmlConstants.HTML_URL3);
516 
517         assertLoadUrlSuccessfully(mWebView, url1);
518         delayedCheckWebBackForwardList(url1, 0, 1);
519         assertGoBackOrForwardBySteps(false, -1);
520         assertGoBackOrForwardBySteps(false, 1);
521 
522         assertLoadUrlSuccessfully(mWebView, url2);
523         delayedCheckWebBackForwardList(url2, 1, 2);
524         assertGoBackOrForwardBySteps(true, -1);
525         assertGoBackOrForwardBySteps(false, 1);
526 
527         assertLoadUrlSuccessfully(mWebView, url3);
528         delayedCheckWebBackForwardList(url3, 2, 3);
529         assertGoBackOrForwardBySteps(true, -2);
530         assertGoBackOrForwardBySteps(false, 1);
531 
532         mWebView.goBack();
533         delayedCheckWebBackForwardList(url2, 1, 3);
534         assertGoBackOrForwardBySteps(true, -1);
535         assertGoBackOrForwardBySteps(true, 1);
536 
537         mWebView.goForward();
538         delayedCheckWebBackForwardList(url3, 2, 3);
539         assertGoBackOrForwardBySteps(true, -2);
540         assertGoBackOrForwardBySteps(false, 1);
541 
542         mWebView.goBackOrForward(-2);
543         delayedCheckWebBackForwardList(url1, 0, 3);
544         assertGoBackOrForwardBySteps(false, -1);
545         assertGoBackOrForwardBySteps(true, 2);
546 
547         mWebView.goBackOrForward(2);
548         delayedCheckWebBackForwardList(url3, 2, 3);
549         assertGoBackOrForwardBySteps(true, -2);
550         assertGoBackOrForwardBySteps(false, 1);
551     }
552 
553     @TestTargetNew(
554         level = TestLevel.COMPLETE,
555         method = "addJavascriptInterface",
556         args = {Object.class, String.class}
557     )
testAddJavascriptInterface()558     public void testAddJavascriptInterface() throws Exception {
559         WebSettings settings = mWebView.getSettings();
560         settings.setJavaScriptEnabled(true);
561         settings.setJavaScriptCanOpenWindowsAutomatically(true);
562 
563         final DummyJavaScriptInterface obj = new DummyJavaScriptInterface();
564         mWebView.addJavascriptInterface(obj, "dummy");
565         assertFalse(obj.hasChangedTitle());
566 
567         startWebServer(false);
568         String url = mWebServer.getAssetUrl(TestHtmlConstants.ADD_JAVA_SCRIPT_INTERFACE_URL);
569         assertLoadUrlSuccessfully(mWebView, url);
570         new DelayedCheck() {
571             @Override
572             protected boolean check() {
573                 return obj.hasChangedTitle();
574             }
575         }.run();
576     }
577 
578     @TestTargets({
579         @TestTargetNew(
580             level = TestLevel.COMPLETE,
581             method = "setBackgroundColor",
582             args = {int.class}
583         ),
584         @TestTargetNew(
585             level = TestLevel.COMPLETE,
586             method = "capturePicture",
587             args = {}
588         ),
589         @TestTargetNew(
590             level = TestLevel.COMPLETE,
591             method = "reload",
592             args = {}
593         )
594     })
testCapturePicture()595     public void testCapturePicture() throws Exception {
596         startWebServer(false);
597         String url = mWebServer.getAssetUrl(TestHtmlConstants.BLANK_PAGE_URL);
598         // showing the blank page will make the picture filled with background color
599         assertLoadUrlSuccessfully(mWebView, url);
600         Picture p = mWebView.capturePicture();
601         Bitmap b = Bitmap.createBitmap(p.getWidth(), p.getHeight(), Config.ARGB_8888);
602         p.draw(new Canvas(b));
603         // default color is white
604         assertBitmapFillWithColor(b, Color.WHITE);
605 
606         mWebView.setBackgroundColor(Color.CYAN);
607         mWebView.reload();
608         waitForLoadComplete(mWebView, TEST_TIMEOUT);
609         // the content of the picture will not be updated automatically
610         p.draw(new Canvas(b));
611         assertBitmapFillWithColor(b, Color.WHITE);
612         // update the content
613         p = mWebView.capturePicture();
614         p.draw(new Canvas(b));
615         assertBitmapFillWithColor(b, Color.CYAN);
616     }
617 
618     @TestTargetNew(
619         level = TestLevel.COMPLETE,
620         method = "setPictureListener",
621         args = {PictureListener.class}
622     )
testSetPictureListener()623     public void testSetPictureListener() throws Exception {
624         final MyPictureListener listener = new MyPictureListener();
625         mWebView.setPictureListener(listener);
626         startWebServer(false);
627         String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
628         assertLoadUrlSuccessfully(mWebView, url);
629         new DelayedCheck(TEST_TIMEOUT) {
630             protected boolean check() {
631                 return listener.callCount > 0;
632             }
633         }.run();
634         assertEquals(mWebView, listener.webView);
635         assertNotNull(listener.picture);
636 
637         final int oldCallCount = listener.callCount;
638         url = mWebServer.getAssetUrl(TestHtmlConstants.SMALL_IMG_URL);
639         assertLoadUrlSuccessfully(mWebView, url);
640         new DelayedCheck(TEST_TIMEOUT) {
641             protected boolean check() {
642                 return listener.callCount > oldCallCount;
643             }
644         }.run();
645     }
646 
647     @TestTargets({
648         @TestTargetNew(
649             level = TestLevel.COMPLETE,
650             method = "savePicture",
651             args = {Bundle.class, File.class}
652         ),
653         @TestTargetNew(
654             level = TestLevel.SUFFICIENT,
655             notes = "Cannot test whether picture has been restored correctly.",
656             method = "restorePicture",
657             args = {Bundle.class, File.class}
658         ),
659         @TestTargetNew(
660             level = TestLevel.COMPLETE,
661             method = "reload",
662             args = {}
663         )
664     })
testSaveAndRestorePicture()665     public void testSaveAndRestorePicture() throws Throwable {
666         mWebView.setBackgroundColor(Color.CYAN);
667         startWebServer(false);
668         String url = mWebServer.getAssetUrl(TestHtmlConstants.BLANK_PAGE_URL);
669         assertLoadUrlSuccessfully(mWebView, url);
670 
671         final Bundle bundle = new Bundle();
672         final File f = getActivity().getFileStreamPath("snapshot");
673 
674         try {
675             assertTrue(bundle.isEmpty());
676             assertEquals(0, f.length());
677             assertTrue(mWebView.savePicture(bundle, f));
678             assertTrue(f.length() > 0);
679             assertFalse(bundle.isEmpty());
680             Picture p = Picture.createFromStream(new FileInputStream(f));
681             Bitmap b = Bitmap.createBitmap(p.getWidth(), p.getHeight(), Config.ARGB_8888);
682             p.draw(new Canvas(b));
683             assertBitmapFillWithColor(b, Color.CYAN);
684 
685             mWebView.setBackgroundColor(Color.WHITE);
686             mWebView.reload();
687             waitForLoadComplete(mWebView, TEST_TIMEOUT);
688 
689             b = Bitmap.createBitmap(mWebView.getWidth(), mWebView.getHeight(), Config.ARGB_8888);
690             mWebView.draw(new Canvas(b));
691             assertBitmapFillWithColor(b, Color.WHITE);
692             runTestOnUiThread(new Runnable() {
693                 public void run() {
694                     assertTrue(mWebView.restorePicture(bundle, f));
695                 }
696             });
697             getInstrumentation().waitForIdleSync();
698             // Cannot test whether the picture has been restored successfully.
699             // Drawing the webview into a canvas will draw white, but on the display it is cyan
700         } finally {
701             if (f.exists()) {
702                 f.delete();
703             }
704         }
705     }
706 
707     @TestTargets({
708         @TestTargetNew(
709             level = TestLevel.COMPLETE,
710             method = "setHttpAuthUsernamePassword",
711             args = {String.class, String.class, String.class, String.class}
712         ),
713         @TestTargetNew(
714             level = TestLevel.COMPLETE,
715             method = "getHttpAuthUsernamePassword",
716             args = {String.class, String.class}
717         )
718     })
testAccessHttpAuthUsernamePassword()719     public void testAccessHttpAuthUsernamePassword() {
720         try {
721             WebViewDatabase.getInstance(getActivity()).clearHttpAuthUsernamePassword();
722 
723             String host = "http://localhost:8080";
724             String realm = "testrealm";
725             String userName = "user";
726             String password = "password";
727 
728             String[] result = mWebView.getHttpAuthUsernamePassword(host, realm);
729             assertNull(result);
730 
731             mWebView.setHttpAuthUsernamePassword(host, realm, userName, password);
732             result = mWebView.getHttpAuthUsernamePassword(host, realm);
733             assertNotNull(result);
734             assertEquals(userName, result[0]);
735             assertEquals(password, result[1]);
736 
737             String newPassword = "newpassword";
738             mWebView.setHttpAuthUsernamePassword(host, realm, userName, newPassword);
739             result = mWebView.getHttpAuthUsernamePassword(host, realm);
740             assertNotNull(result);
741             assertEquals(userName, result[0]);
742             assertEquals(newPassword, result[1]);
743 
744             String newUserName = "newuser";
745             mWebView.setHttpAuthUsernamePassword(host, realm, newUserName, newPassword);
746             result = mWebView.getHttpAuthUsernamePassword(host, realm);
747             assertNotNull(result);
748             assertEquals(newUserName, result[0]);
749             assertEquals(newPassword, result[1]);
750 
751             // the user is set to null, can not change any thing in the future
752             mWebView.setHttpAuthUsernamePassword(host, realm, null, password);
753             result = mWebView.getHttpAuthUsernamePassword(host, realm);
754             assertNotNull(result);
755             assertNull(result[0]);
756             assertEquals(password, result[1]);
757 
758             mWebView.setHttpAuthUsernamePassword(host, realm, userName, null);
759             result = mWebView.getHttpAuthUsernamePassword(host, realm);
760             assertNotNull(result);
761             assertEquals(userName, result[0]);
762             assertEquals(null, result[1]);
763 
764             mWebView.setHttpAuthUsernamePassword(host, realm, null, null);
765             result = mWebView.getHttpAuthUsernamePassword(host, realm);
766             assertNotNull(result);
767             assertNull(result[0]);
768             assertNull(result[1]);
769 
770             mWebView.setHttpAuthUsernamePassword(host, realm, newUserName, newPassword);
771             result = mWebView.getHttpAuthUsernamePassword(host, realm);
772             assertNotNull(result);
773             assertEquals(newUserName, result[0]);
774             assertEquals(newPassword, result[1]);
775         } finally {
776             WebViewDatabase.getInstance(getActivity()).clearHttpAuthUsernamePassword();
777         }
778     }
779 
780     @TestTargetNew(
781         level = TestLevel.COMPLETE,
782         method = "savePassword",
783         args = {String.class, String.class, String.class}
784     )
testSavePassword()785     public void testSavePassword() {
786         WebViewDatabase db = WebViewDatabase.getInstance(getActivity());
787         try {
788             db.clearUsernamePassword();
789 
790             String host = "http://localhost:8080";
791             String userName = "user";
792             String password = "password";
793             assertFalse(db.hasUsernamePassword());
794             mWebView.savePassword(host, userName, password);
795             assertTrue(db.hasUsernamePassword());
796         } finally {
797             db.clearUsernamePassword();
798         }
799     }
800 
801     @TestTargets({
802         @TestTargetNew(
803             level = TestLevel.COMPLETE,
804             method = "loadData",
805             args = {String.class, String.class, String.class}
806         ),
807         @TestTargetNew(
808             level = TestLevel.COMPLETE,
809             method = "getTitle",
810             args = {}
811         ),
812         @TestTargetNew(
813             level = TestLevel.COMPLETE,
814             method = "capturePicture",
815             args = {}
816         ),
817         @TestTargetNew(
818             level = TestLevel.COMPLETE,
819             method = "capturePicture",
820             args = {}
821         )
822     })
testLoadData()823     public void testLoadData() throws Exception {
824         assertNull(mWebView.getTitle());
825         mWebView.loadData("<html><head><title>Hello,World!</title></head><body></body></html>",
826                 "text/html", "UTF-8");
827         waitForLoadComplete(mWebView, TEST_TIMEOUT);
828         assertEquals("Hello,World!", mWebView.getTitle());
829 
830         startWebServer(false);
831         String imgUrl = mWebServer.getAssetUrl(TestHtmlConstants.SMALL_IMG_URL);
832         mWebView.loadData("<html><body><img src=\"" + imgUrl + "\"/></body></html>",
833                 "text/html", "UTF-8");
834         waitForLoadComplete(mWebView, TEST_TIMEOUT);
835 
836         AssetManager assets = getActivity().getAssets();
837         Bitmap b1 = BitmapFactory.decodeStream(assets.open(TestHtmlConstants.SMALL_IMG_URL));
838         b1 = b1.copy(Config.ARGB_8888, true);
839 
840         Picture p = mWebView.capturePicture();
841         Bitmap b2 = Bitmap.createBitmap(p.getWidth(), p.getHeight(), Config.ARGB_8888);
842         p.draw(new Canvas(b2));
843         assertTrue(checkBitmapInsideAnother(b1, b2));
844     }
845 
846     @TestTargets({
847         @TestTargetNew(
848             level = TestLevel.COMPLETE,
849             method = "loadDataWithBaseURL",
850             args = {String.class, String.class, String.class, String.class, String.class}
851         ),
852         @TestTargetNew(
853             level = TestLevel.COMPLETE,
854             method = "getTitle",
855             args = {}
856         ),
857         @TestTargetNew(
858             level = TestLevel.COMPLETE,
859             method = "getUrl",
860             args = {}
861         )
862     })
testLoadDataWithBaseUrl()863     public void testLoadDataWithBaseUrl() throws Exception {
864         assertNull(mWebView.getTitle());
865         assertNull(mWebView.getUrl());
866         String imgUrl = TestHtmlConstants.SMALL_IMG_URL; // relative
867 
868         startWebServer(false);
869         String baseUrl = mWebServer.getAssetUrl("foo.html");
870         String failUrl = "random";
871         mWebView.loadDataWithBaseURL(baseUrl,
872                 "<html><body><img src=\"" + imgUrl + "\"/></body></html>",
873                 "text/html", "UTF-8", failUrl);
874         waitForLoadComplete(mWebView, TEST_TIMEOUT);
875         // check that image was retrieved from the server
876         assertTrue(mWebServer.getLastRequestUrl().endsWith(imgUrl));
877         // the fail URL is used for the history entry, even if the load succeeds
878         assertEquals(failUrl, mWebView.getUrl());
879 
880         imgUrl = TestHtmlConstants.LARGE_IMG_URL;
881         mWebView.loadDataWithBaseURL(baseUrl,
882                 "<html><body><img src=\"" + imgUrl + "\"/></body></html>",
883                 "text/html", "UTF-8", null);
884         waitForLoadComplete(mWebView, TEST_TIMEOUT);
885         // check that image was retrieved from the server
886         assertTrue(mWebServer.getLastRequestUrl().endsWith(imgUrl));
887         // no history item saved, URL is still the last one
888         assertEquals(failUrl, mWebView.getUrl());
889     }
890 
891     @TestTargetNew(
892         level = TestLevel.SUFFICIENT,
893         method = "findAll",
894         args = {String.class},
895         notes = "Cannot check highlighting"
896     )
897     @UiThreadTest
testFindAll()898     public void testFindAll() throws InterruptedException {
899         String p = "<p>Find all instances of find on the page and highlight them.</p>";
900 
901         mWebView.loadData("<html><body>" + p + "</body></html>", "text/html", "UTF-8");
902         waitForLoadComplete(mWebView, TEST_TIMEOUT);
903 
904         assertEquals(2, mWebView.findAll("find"));
905     }
906 
907     @TestTargets({
908         @TestTargetNew(
909             level = TestLevel.COMPLETE,
910             method = "findNext",
911             args = {boolean.class}
912         ),
913         @TestTargetNew(
914             level = TestLevel.COMPLETE,
915             method = "findAll",
916             args = {String.class}
917         ),
918         @TestTargetNew(
919             level = TestLevel.COMPLETE,
920             method = "clearMatches",
921             args = {}
922         )
923     })
testFindNext()924     public void testFindNext() throws Throwable {
925         DisplayMetrics metrics = mWebView.getContext().getResources().getDisplayMetrics();
926         int dimension = Math.max(metrics.widthPixels, metrics.heightPixels);
927         // create a paragraph high enough to take up the entire screen
928         String p = "<p style=\"height:" + dimension + "px;\">" +
929                 "Find all instances of a word on the page and highlight them.</p>";
930 
931         mWebView.loadData("<html><body>" + p + p + "</body></html>", "text/html", "UTF-8");
932         waitForLoadComplete(mWebView, TEST_TIMEOUT);
933 
934         // highlight all the strings found
935         runTestOnUiThread(new Runnable() {
936             public void run() {
937                 mWebView.findAll("all");
938             }
939         });
940         getInstrumentation().waitForIdleSync();
941         int previousScrollY = mWebView.getScrollY();
942 
943         // Can not use @UiThreadTest here as we need wait in other thread until the scroll in UI
944         // thread finishes
945         findNextOnUiThread(true);
946         delayedCheckStopScrolling();
947         // assert that the view scrolls and focuses "all" in the second page
948         assertTrue(mWebView.getScrollY() > previousScrollY);
949         previousScrollY = mWebView.getScrollY();
950 
951         findNextOnUiThread(true);
952         delayedCheckStopScrolling();
953         // assert that the view scrolls and focuses "all" in the first page
954         assertTrue(mWebView.getScrollY() < previousScrollY);
955         previousScrollY = mWebView.getScrollY();
956 
957         findNextOnUiThread(false);
958         delayedCheckStopScrolling();
959         // assert that the view scrolls and focuses "all" in the second page
960         assertTrue(mWebView.getScrollY() > previousScrollY);
961         previousScrollY = mWebView.getScrollY();
962 
963         findNextOnUiThread(false);
964         delayedCheckStopScrolling();
965         // assert that the view scrolls and focuses "all" in the first page
966         assertTrue(mWebView.getScrollY() < previousScrollY);
967         previousScrollY = mWebView.getScrollY();
968 
969         // clear the result
970         runTestOnUiThread(new Runnable() {
971             public void run() {
972                 mWebView.clearMatches();
973             }
974         });
975         getInstrumentation().waitForIdleSync();
976 
977         // can not scroll any more
978         findNextOnUiThread(false);
979         delayedCheckStopScrolling();
980         assertTrue(mWebView.getScrollY() == previousScrollY);
981 
982         findNextOnUiThread(true);
983         delayedCheckStopScrolling();
984 
985         assertTrue(mWebView.getScrollY() == previousScrollY);
986     }
987 
988     @TestTargetNew(
989         level = TestLevel.COMPLETE,
990         method = "documentHasImages",
991         args = {android.os.Message.class}
992     )
993     public void testDocumentHasImages() throws Exception {
994         startWebServer(false);
995         String imgUrl = mWebServer.getAssetUrl(TestHtmlConstants.SMALL_IMG_URL);
996         mWebView.loadData("<html><body><img src=\"" + imgUrl + "\"/></body></html>",
997                 "text/html", "UTF-8");
998         waitForLoadComplete(mWebView, TEST_TIMEOUT);
999 
1000         // create the handler in other thread
1001         final DocumentHasImageCheckHandler handler =
1002             new DocumentHasImageCheckHandler(mWebView.getHandler().getLooper());
1003         Message response = new Message();
1004         response.setTarget(handler);
1005         assertFalse(handler.hasCalledHandleMessage());
1006         mWebView.documentHasImages(response);
1007         new DelayedCheck() {
1008             @Override
1009             protected boolean check() {
1010                 return handler.hasCalledHandleMessage();
1011             }
1012         }.run();
1013         assertEquals(1, handler.getMsgArg1());
1014     }
1015 
1016     @TestTargets({
1017         @TestTargetNew(
1018             level = TestLevel.COMPLETE,
1019             method = "pageDown",
1020             args = {boolean.class}
1021         ),
1022         @TestTargetNew(
1023             level = TestLevel.COMPLETE,
1024             method = "pageUp",
1025             args = {boolean.class}
1026         )
1027     })
1028     public void testPageScroll() throws Throwable {
1029         DisplayMetrics metrics = mWebView.getContext().getResources().getDisplayMetrics();
1030         int dimension = 2 * Math.max(metrics.widthPixels, metrics.heightPixels);
1031         String p = "<p style=\"height:" + dimension + "px;\">" +
1032                 "Scroll by half the size of the page.</p>";
1033         mWebView.loadData("<html><body>" + p + p + "</body></html>", "text/html", "UTF-8");
1034         waitForLoadComplete(mWebView, TEST_TIMEOUT);
1035 
1036         assertTrue(pageDownOnUiThread(false));
1037 
1038         // scroll to the bottom
1039         while (pageDownOnUiThread(false)) {
1040             // do nothing
1041         }
1042         assertFalse(pageDownOnUiThread(false));
1043         int bottomScrollY = mWebView.getScrollY();
1044 
1045         assertTrue(pageUpOnUiThread(false));
1046 
1047         // scroll to the top
1048         while (pageUpOnUiThread(false)) {
1049             // do nothing
1050         }
1051         assertFalse(pageUpOnUiThread(false));
1052         int topScrollY = mWebView.getScrollY();
1053 
1054         // jump to the bottom
1055         assertTrue(pageDownOnUiThread(true));
1056         assertEquals(bottomScrollY, mWebView.getScrollY());
1057 
1058         // jump to the top
1059         assertTrue(pageUpOnUiThread(true));
1060         assertEquals(topScrollY, mWebView.getScrollY());
1061     }
1062 
1063     @TestTargetNew(
1064         level = TestLevel.COMPLETE,
1065         method = "getContentHeight",
1066         args = {}
1067     )
1068     public void testGetContentHeight() throws InterruptedException {
1069         mWebView.loadData("<html><body></body></html>", "text/html", "UTF-8");
1070         waitForLoadComplete(mWebView, TEST_TIMEOUT);
1071         assertEquals(mWebView.getHeight(), mWebView.getContentHeight() * mWebView.getScale(), 2f);
1072 
1073         final int pageHeight = 600;
1074         // set the margin to 0
1075         String p = "<p style=\"height:" + pageHeight + "px;margin:0px auto;\">Get the height of "
1076                 + "HTML content.</p>";
1077         mWebView.loadData("<html><body>" + p + "</body></html>", "text/html", "UTF-8");
1078         waitForLoadComplete(mWebView, TEST_TIMEOUT);
1079         assertTrue(mWebView.getContentHeight() > pageHeight);
1080         int extraSpace = mWebView.getContentHeight() - pageHeight;
1081 
1082         mWebView.loadData("<html><body>" + p + p + "</body></html>", "text/html", "UTF-8");
1083         waitForLoadComplete(mWebView, TEST_TIMEOUT);
1084         assertEquals(pageHeight + pageHeight + extraSpace, mWebView.getContentHeight());
1085     }
1086 
1087     @TestTargetNew(
1088         level = TestLevel.SUFFICIENT,
1089         notes = "Cannot test whether the view is cleared.",
1090         method = "clearView",
1091         args = {}
1092     )
testClearView()1093     public void testClearView() throws Throwable {
1094         startWebServer(false);
1095         String imgUrl = mWebServer.getAssetUrl(TestHtmlConstants.SMALL_IMG_URL);
1096         mWebView.loadData("<html><body><img src=\"" + imgUrl + "\"/></body></html>",
1097                 "text/html", "UTF-8");
1098         waitForLoadComplete(mWebView, TEST_TIMEOUT);
1099 
1100         AssetManager assets = getActivity().getAssets();
1101         Bitmap b1 = BitmapFactory.decodeStream(assets.open(TestHtmlConstants.SMALL_IMG_URL));
1102         b1 = b1.copy(Config.ARGB_8888, true);
1103 
1104         Picture p = mWebView.capturePicture();
1105         Bitmap b2 = Bitmap.createBitmap(p.getWidth(), p.getHeight(), Config.ARGB_8888);
1106         p.draw(new Canvas(b2));
1107         // the image is painted
1108         assertTrue(checkBitmapInsideAnother(b1, b2));
1109 
1110         mWebView.clearView();
1111         runTestOnUiThread(new Runnable() {
1112             public void run() {
1113                 mWebView.invalidate();
1114             }
1115         });
1116         getInstrumentation().waitForIdleSync();
1117         // Can not check whether method clearView() take effect by automatic testing:
1118         // 1. Can not use getMeasuredHeight() and getMeasuredWidth() to
1119         //    check that the onMeasure() returns 0
1120         // 2. Can not use capturePicture() to check that the content has been cleared.
1121         //    The result of capturePicture() is not updated after clearView() is called.
1122     }
1123 
1124     @TestTargetNew(
1125         level = TestLevel.SUFFICIENT,
1126         method = "clearCache",
1127         args = {boolean.class}
1128     )
testClearCache()1129     public void testClearCache() throws Exception {
1130         final File cacheFileBaseDir = CacheManager.getCacheFileBaseDir();
1131         mWebView.clearCache(true);
1132         assertEquals(0, cacheFileBaseDir.list().length);
1133 
1134         startWebServer(false);
1135         mWebView.loadUrl(mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL));
1136         waitForLoadComplete(mWebView, TEST_TIMEOUT);
1137         int cacheFileCount = cacheFileBaseDir.list().length;
1138         assertTrue(cacheFileCount > 0);
1139 
1140         mWebView.clearCache(false);
1141         // the cache files are still there
1142         // can not check other effects of the method
1143         assertEquals(cacheFileCount, cacheFileBaseDir.list().length);
1144 
1145         mWebView.clearCache(true);
1146         // check the files are deleted
1147         new DelayedCheck(TEST_TIMEOUT) {
1148             @Override
1149             protected boolean check() {
1150                 return cacheFileBaseDir.list().length == 0;
1151             }
1152         }.run();
1153     }
1154 
1155     @TestTargets({
1156         @TestTargetNew(
1157             level = TestLevel.SUFFICIENT,
1158             method = "enablePlatformNotifications",
1159             args = {},
1160             notes = "Cannot simulate data state or proxy changes"
1161         ),
1162         @TestTargetNew(
1163             level = TestLevel.SUFFICIENT,
1164             method = "disablePlatformNotifications",
1165             args = {},
1166             notes = "Cannot simulate data state or proxy changes"
1167         )
1168     })
testPlatformNotifications()1169     public void testPlatformNotifications() {
1170         WebView.enablePlatformNotifications();
1171         WebView.disablePlatformNotifications();
1172     }
1173 
1174     @TestTargets({
1175         @TestTargetNew(
1176             level = TestLevel.SUFFICIENT,
1177             method = "getPluginList",
1178             args = {}
1179         ),
1180         @TestTargetNew(
1181             level = TestLevel.SUFFICIENT,
1182             method = "refreshPlugins",
1183             args = {boolean.class}
1184         )
1185     })
testAccessPluginList()1186     public void testAccessPluginList() {
1187         assertNotNull(WebView.getPluginList());
1188 
1189         // can not find a way to install plugins
1190         mWebView.refreshPlugins(false);
1191     }
1192 
1193     @TestTargetNew(
1194         level = TestLevel.SUFFICIENT,
1195         method = "destroy",
1196         args = {}
1197     )
testDestroy()1198     public void testDestroy() {
1199         // Create a new WebView, since we cannot call destroy() on a view in the hierarchy
1200         WebView localWebView = new WebView(getActivity());
1201         localWebView.destroy();
1202     }
1203 
1204     @TestTargetNew(
1205         level = TestLevel.COMPLETE,
1206         method = "flingScroll",
1207         args = {int.class, int.class}
1208     )
testFlingScroll()1209     public void testFlingScroll() throws Throwable {
1210         DisplayMetrics metrics = mWebView.getContext().getResources().getDisplayMetrics();
1211         int dimension = 2 * Math.max(metrics.widthPixels, metrics.heightPixels);
1212         String p = "<p style=\"height:" + dimension + "px;" +
1213                 "width:" + dimension + "px\">Test fling scroll.</p>";
1214         mWebView.loadData("<html><body>" + p + "</body></html>", "text/html", "UTF-8");
1215         waitForLoadComplete(mWebView, TEST_TIMEOUT);
1216 
1217         int previousScrollX = mWebView.getScrollX();
1218         int previousScrollY = mWebView.getScrollY();
1219         runTestOnUiThread(new Runnable() {
1220             public void run() {
1221                 mWebView.flingScroll(100, 100);
1222             }
1223         });
1224 
1225         int timeSlice = 500;
1226         Thread.sleep(timeSlice);
1227         assertTrue(mWebView.getScrollX() > previousScrollX);
1228         assertTrue(mWebView.getScrollY() > previousScrollY);
1229 
1230         previousScrollY = mWebView.getScrollY();
1231         previousScrollX = mWebView.getScrollX();
1232         Thread.sleep(timeSlice);
1233         assertTrue(mWebView.getScrollX() >= previousScrollX);
1234         assertTrue(mWebView.getScrollY() >= previousScrollY);
1235 
1236         previousScrollY = mWebView.getScrollY();
1237         previousScrollX = mWebView.getScrollX();
1238         Thread.sleep(timeSlice);
1239         assertTrue(mWebView.getScrollX() >= previousScrollX);
1240         assertTrue(mWebView.getScrollY() >= previousScrollY);
1241     }
1242 
1243     @TestTargetNew(
1244         level = TestLevel.COMPLETE,
1245         method = "requestFocusNodeHref",
1246         args = {android.os.Message.class}
1247     )
testRequestFocusNodeHref()1248     public void testRequestFocusNodeHref() throws InterruptedException {
1249         String links = "<DL><p><DT><A HREF=\"" + TestHtmlConstants.HTML_URL1
1250                 + "\">HTML_URL1</A><DT><A HREF=\"" + TestHtmlConstants.HTML_URL2
1251                 + "\">HTML_URL2</A></DL><p>";
1252         mWebView.loadData("<html><body>" + links + "</body></html>", "text/html", "UTF-8");
1253         waitForLoadComplete(mWebView, TEST_TIMEOUT);
1254 
1255         final HrefCheckHandler handler = new HrefCheckHandler(mWebView.getHandler().getLooper());
1256         Message hrefMsg = new Message();
1257         hrefMsg.setTarget(handler);
1258 
1259         // focus on first link
1260         handler.reset();
1261         getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_DOWN);
1262         mWebView.requestFocusNodeHref(hrefMsg);
1263         new DelayedCheck() {
1264             @Override
1265             protected boolean check() {
1266                 return handler.hasCalledHandleMessage();
1267             }
1268         }.run();
1269         assertEquals(TestHtmlConstants.HTML_URL1, handler.getResultUrl());
1270 
1271         // focus on second link
1272         handler.reset();
1273         hrefMsg = new Message();
1274         hrefMsg.setTarget(handler);
1275         getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_DOWN);
1276         mWebView.requestFocusNodeHref(hrefMsg);
1277         new DelayedCheck() {
1278             @Override
1279             protected boolean check() {
1280                 return handler.hasCalledHandleMessage();
1281             }
1282         }.run();
1283         assertEquals(TestHtmlConstants.HTML_URL2, handler.getResultUrl());
1284 
1285         mWebView.requestFocusNodeHref(null);
1286     }
1287 
1288     @TestTargetNew(
1289         level = TestLevel.COMPLETE,
1290         method = "requestImageRef",
1291         args = {android.os.Message.class}
1292     )
testRequestImageRef()1293     public void testRequestImageRef() throws Exception {
1294         AssetManager assets = getActivity().getAssets();
1295         Bitmap bitmap = BitmapFactory.decodeStream(assets.open(TestHtmlConstants.LARGE_IMG_URL));
1296         int imgWidth = bitmap.getWidth();
1297         int imgHeight = bitmap.getHeight();
1298 
1299         startWebServer(false);
1300         String imgUrl = mWebServer.getAssetUrl(TestHtmlConstants.LARGE_IMG_URL);
1301         mWebView.loadData("<html><title>Title</title><body><img src=\"" + imgUrl
1302                 + "\"/></body></html>", "text/html", "UTF-8");
1303         waitForLoadComplete(mWebView, TEST_TIMEOUT);
1304 
1305         final HrefCheckHandler handler = new HrefCheckHandler(mWebView.getHandler().getLooper());
1306         Message msg = new Message();
1307         msg.setTarget(handler);
1308 
1309         // touch the image
1310         handler.reset();
1311         int[] location = new int[2];
1312         mWebView.getLocationOnScreen(location);
1313         getInstrumentation().sendPointerSync(
1314                 MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN,
1315                         location[0] + imgWidth / 2,
1316                         location[1] + imgHeight / 2, 0));
1317         mWebView.requestImageRef(msg);
1318         new DelayedCheck() {
1319             @Override
1320             protected boolean check() {
1321                 return handler.hasCalledHandleMessage();
1322             }
1323         }.run();
1324         assertEquals(imgUrl, handler.mResultUrl);
1325     }
1326 
1327     @TestTargetNew(
1328         level = TestLevel.SUFFICIENT,
1329         method = "debugDump",
1330         args = {}
1331     )
testDebugDump()1332     public void testDebugDump() {
1333         mWebView.debugDump();
1334     }
1335 
1336     @TestTargetNew(
1337         level = TestLevel.COMPLETE,
1338         method = "clearFormData",
1339         args = {}
1340     )
1341     @BrokenTest(value = "Causes the process to crash some time after test completion.")
testClearFormData()1342     public void testClearFormData() throws Throwable {
1343         String form = "<form><input type=\"text\" name=\"testClearFormData\"></form>";
1344         mWebView.loadData("<html><body>" + form + "</body></html>", "text/html", "UTF-8");
1345         waitForLoadComplete(mWebView, TEST_TIMEOUT);
1346         moveFocusDown();
1347         getInstrumentation().sendStringSync("test");
1348         sendKeys(KeyEvent.KEYCODE_ENTER);
1349 
1350         mWebView.reload();
1351         waitForLoadComplete(mWebView, TEST_TIMEOUT);
1352         moveFocusDown();
1353         View input = mWebView.findFocus();
1354         assertTrue(input instanceof AutoCompleteTextView);
1355         getInstrumentation().sendStringSync("te");
1356         assertTrue(((AutoCompleteTextView) input).isPopupShowing());
1357 
1358         mWebView.reload();
1359         waitForLoadComplete(mWebView, TEST_TIMEOUT);
1360         moveFocusDown();
1361         mWebView.clearFormData();
1362         // no auto completion choice after clearing
1363         input = mWebView.findFocus();
1364         assertTrue(input instanceof AutoCompleteTextView);
1365         getInstrumentation().sendStringSync("te");
1366         assertFalse(((AutoCompleteTextView) input).isPopupShowing());
1367     }
1368 
1369     @TestTargetNew(
1370         level = TestLevel.COMPLETE,
1371         method = "getHitTestResult",
1372         args = {}
1373     )
testGetHitTestResult()1374     public void testGetHitTestResult() throws Throwable {
1375         String anchor = "<p><a href=\"" + TestHtmlConstants.EXT_WEB_URL1
1376                 + "\">normal anchor</a></p>";
1377         String blankAnchor = "<p><a href=\"\">blank anchor</a></p>";
1378         String form = "<p><form><input type=\"text\" name=\"Test\"><br>"
1379                 + "<input type=\"submit\" value=\"Submit\"></form></p>";
1380         String phoneNo = "3106984000";
1381         String tel = "<p><a href=\"tel:" + phoneNo + "\">Phone</a></p>";
1382         String email = "test@gmail.com";
1383         String mailto = "<p><a href=\"mailto:" + email + "\">Email</a></p>";
1384         String location = "shanghai";
1385         String geo = "<p><a href=\"geo:0,0?q=" + location + "\">Location</a></p>";
1386         mWebView.loadDataWithBaseURL("fake://home", "<html><body>" + anchor + blankAnchor + form
1387                 + tel + mailto + geo + "</body></html>", "text/html", "UTF-8", null);
1388         waitForLoadComplete(mWebView, TEST_TIMEOUT);
1389 
1390         // anchor
1391         moveFocusDown();
1392         HitTestResult result = mWebView.getHitTestResult();
1393         assertEquals(HitTestResult.SRC_ANCHOR_TYPE, result.getType());
1394         assertEquals(TestHtmlConstants.EXT_WEB_URL1, result.getExtra());
1395 
1396         // blank anchor
1397         moveFocusDown();
1398         result = mWebView.getHitTestResult();
1399         assertEquals(HitTestResult.SRC_ANCHOR_TYPE, result.getType());
1400         assertEquals("fake://home", result.getExtra());
1401 
1402         // text field
1403         moveFocusDown();
1404         result = mWebView.getHitTestResult();
1405         assertEquals(HitTestResult.EDIT_TEXT_TYPE, result.getType());
1406         assertNull(result.getExtra());
1407 
1408         // submit button
1409         moveFocusDown();
1410         result = mWebView.getHitTestResult();
1411         assertEquals(HitTestResult.UNKNOWN_TYPE, result.getType());
1412         assertNull(result.getExtra());
1413 
1414         // phone number
1415         moveFocusDown();
1416         result = mWebView.getHitTestResult();
1417         assertEquals(HitTestResult.PHONE_TYPE, result.getType());
1418         assertEquals(phoneNo, result.getExtra());
1419 
1420         // email
1421         moveFocusDown();
1422         result = mWebView.getHitTestResult();
1423         assertEquals(HitTestResult.EMAIL_TYPE, result.getType());
1424         assertEquals(email, result.getExtra());
1425 
1426         // geo address
1427         moveFocusDown();
1428         result = mWebView.getHitTestResult();
1429         assertEquals(HitTestResult.GEO_TYPE, result.getType());
1430         assertEquals(location, result.getExtra());
1431     }
1432 
1433     @TestTargetNew(
1434         level = TestLevel.COMPLETE,
1435         method = "setInitialScale",
1436         args = {int.class}
1437     )
testSetInitialScale()1438     public void testSetInitialScale() throws InterruptedException {
1439         String p = "<p style=\"height:1000px;width:1000px\">Test setInitialScale.</p>";
1440         mWebView.loadData("<html><body>" + p + "</body></html>", "text/html", "UTF-8");
1441         waitForLoadComplete(mWebView, TEST_TIMEOUT);
1442         final float defaultScale = getInstrumentation().getTargetContext().getResources().
1443             getDisplayMetrics().density;
1444         assertEquals(defaultScale, mWebView.getScale(), 0f);
1445 
1446         mWebView.setInitialScale(0);
1447         // modify content to fool WebKit into re-loading
1448         mWebView.loadData("<html><body>" + p + "2" + "</body></html>", "text/html", "UTF-8");
1449         waitForLoadComplete(mWebView, TEST_TIMEOUT);
1450         assertEquals(defaultScale, mWebView.getScale(), 0f);
1451 
1452         mWebView.setInitialScale(50);
1453         mWebView.loadData("<html><body>" + p + "3" + "</body></html>", "text/html", "UTF-8");
1454         waitForLoadComplete(mWebView, TEST_TIMEOUT);
1455         assertEquals(0.5f, mWebView.getScale(), .02f);
1456 
1457         mWebView.setInitialScale(0);
1458         mWebView.loadData("<html><body>" + p + "4" + "</body></html>", "text/html", "UTF-8");
1459         waitForLoadComplete(mWebView, TEST_TIMEOUT);
1460         assertEquals(defaultScale, mWebView.getScale(), 0f);
1461     }
1462 
1463     @TestTargetNew(
1464         level = TestLevel.SUFFICIENT,
1465         notes = "No API to trigger receiving an icon. Favicon not loaded automatically.",
1466         method = "getFavicon",
1467         args = {}
1468     )
1469     @ToBeFixed(explanation = "Favicon is not loaded automatically.")
testGetFavicon()1470     public void testGetFavicon() throws Exception {
1471         startWebServer(false);
1472         String url = mWebServer.getAssetUrl(TestHtmlConstants.TEST_FAVICON_URL);
1473         assertLoadUrlSuccessfully(mWebView, url);
1474         mWebView.getFavicon();
1475         // ToBeFixed: Favicon is not loaded automatically.
1476         // assertNotNull(mWebView.getFavicon());
1477     }
1478 
1479     @TestTargetNew(
1480         level = TestLevel.COMPLETE,
1481         method = "clearHistory",
1482         args = {}
1483     )
testClearHistory()1484     public void testClearHistory() throws Exception {
1485         startWebServer(false);
1486         String url1 = mWebServer.getAssetUrl(TestHtmlConstants.HTML_URL1);
1487         String url2 = mWebServer.getAssetUrl(TestHtmlConstants.HTML_URL2);
1488         String url3 = mWebServer.getAssetUrl(TestHtmlConstants.HTML_URL3);
1489 
1490         assertLoadUrlSuccessfully(mWebView, url1);
1491         delayedCheckWebBackForwardList(url1, 0, 1);
1492 
1493         assertLoadUrlSuccessfully(mWebView, url2);
1494         delayedCheckWebBackForwardList(url2, 1, 2);
1495 
1496         assertLoadUrlSuccessfully(mWebView, url3);
1497         delayedCheckWebBackForwardList(url3, 2, 3);
1498 
1499         mWebView.clearHistory();
1500 
1501         // only current URL is left after clearing
1502         delayedCheckWebBackForwardList(url3, 0, 1);
1503     }
1504 
1505     @TestTargets({
1506         @TestTargetNew(
1507             level = TestLevel.COMPLETE,
1508             method = "saveState",
1509             args = {Bundle.class}
1510         ),
1511         @TestTargetNew(
1512             level = TestLevel.COMPLETE,
1513             method = "restoreState",
1514             args = {Bundle.class}
1515         ),
1516         @TestTargetNew(
1517             level = TestLevel.COMPLETE,
1518             method = "copyBackForwardList",
1519             args = {}
1520         )
1521     })
1522     @ToBeFixed(explanation="Web history items do not get inflated after restore.")
testSaveAndRestoreState()1523     public void testSaveAndRestoreState() throws Throwable {
1524         // nothing to save
1525         assertNull(mWebView.saveState(new Bundle()));
1526 
1527         startWebServer(false);
1528         String url1 = mWebServer.getAssetUrl(TestHtmlConstants.HTML_URL1);
1529         String url2 = mWebServer.getAssetUrl(TestHtmlConstants.HTML_URL2);
1530         String url3 = mWebServer.getAssetUrl(TestHtmlConstants.HTML_URL3);
1531 
1532         // make a history list
1533         assertLoadUrlSuccessfully(mWebView, url1);
1534         delayedCheckWebBackForwardList(url1, 0, 1);
1535         assertLoadUrlSuccessfully(mWebView, url2);
1536         delayedCheckWebBackForwardList(url2, 1, 2);
1537         assertLoadUrlSuccessfully(mWebView, url3);
1538         delayedCheckWebBackForwardList(url3, 2, 3);
1539 
1540         // save the list
1541         Bundle bundle = new Bundle();
1542         WebBackForwardList saveList = mWebView.saveState(bundle);
1543         assertNotNull(saveList);
1544         assertEquals(3, saveList.getSize());
1545         assertEquals(2, saveList.getCurrentIndex());
1546         assertEquals(url1, saveList.getItemAtIndex(0).getUrl());
1547         assertEquals(url2, saveList.getItemAtIndex(1).getUrl());
1548         assertEquals(url3, saveList.getItemAtIndex(2).getUrl());
1549 
1550         // change the content to a new "blank" web view without history
1551         final WebView newWebView = new WebView(getActivity());
1552 
1553         WebBackForwardList copyListBeforeRestore = newWebView.copyBackForwardList();
1554         assertNotNull(copyListBeforeRestore);
1555         assertEquals(0, copyListBeforeRestore.getSize());
1556 
1557         // restore the list
1558         final WebBackForwardList restoreList = newWebView.restoreState(bundle);
1559         assertNotNull(restoreList);
1560         assertEquals(3, restoreList.getSize());
1561         assertEquals(2, saveList.getCurrentIndex());
1562         /* ToBeFixed: The WebHistoryItems do not get inflated. Uncomment remaining tests when fixed.
1563         // wait for the list items to get inflated
1564         new DelayedCheck(TEST_TIMEOUT) {
1565             @Override
1566             protected boolean check() {
1567                 return restoreList.getItemAtIndex(0).getUrl() != null &&
1568                        restoreList.getItemAtIndex(1).getUrl() != null &&
1569                        restoreList.getItemAtIndex(2).getUrl() != null;
1570             }
1571         }.run();
1572         assertEquals(url1, restoreList.getItemAtIndex(0).getUrl());
1573         assertEquals(url2, restoreList.getItemAtIndex(1).getUrl());
1574         assertEquals(url3, restoreList.getItemAtIndex(2).getUrl());
1575 
1576         WebBackForwardList copyListAfterRestore = newWebView.copyBackForwardList();
1577         assertNotNull(copyListAfterRestore);
1578         assertEquals(3, copyListAfterRestore.getSize());
1579         assertEquals(2, copyListAfterRestore.getCurrentIndex());
1580         assertEquals(url1, copyListAfterRestore.getItemAtIndex(0).getUrl());
1581         assertEquals(url2, copyListAfterRestore.getItemAtIndex(1).getUrl());
1582         assertEquals(url3, copyListAfterRestore.getItemAtIndex(2).getUrl());
1583         */
1584     }
1585 
1586     @TestTargetNew(
1587         level = TestLevel.COMPLETE,
1588         method = "setWebViewClient",
1589         args = {WebViewClient.class}
1590     )
testSetWebViewClient()1591     public void testSetWebViewClient() throws Throwable {
1592         final MockWebViewClient webViewClient = new MockWebViewClient();
1593         mWebView.setWebViewClient(webViewClient);
1594 
1595         assertFalse(webViewClient.onScaleChangedCalled());
1596         runTestOnUiThread(new Runnable() {
1597             public void run() {
1598                 mWebView.zoomIn();
1599             }
1600         });
1601         getInstrumentation().waitForIdleSync();
1602         assertTrue(webViewClient.onScaleChangedCalled());
1603     }
1604 
1605     @TestTargets({
1606         @TestTargetNew(
1607             level = TestLevel.COMPLETE,
1608             method = "setCertificate",
1609             args = {SslCertificate.class}
1610         ),
1611         @TestTargetNew(
1612             level = TestLevel.COMPLETE,
1613             method = "getCertificate",
1614             args = {}
1615         )
1616     })
testAccessCertificate()1617     public void testAccessCertificate() throws Throwable {
1618         runTestOnUiThread(new Runnable() {
1619             public void run() {
1620                 mWebView = new MockWebView(getActivity());
1621                 getActivity().setContentView(mWebView);
1622             }
1623         });
1624         getInstrumentation().waitForIdleSync();
1625 
1626         final MockWebView mockWebView = (MockWebView) mWebView;
1627         // need the client to handle error
1628         mockWebView.setWebViewClient(new WebViewClient());
1629 
1630         mockWebView.reset();
1631         startWebServer(true);
1632         String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
1633         // attempt to load the url. This will fail during certificate verification, but the
1634         // certificate will still be set. WebViewClient.onReceivedSslError() is a hidden API,
1635         // so we cannot ignore the error.
1636         mockWebView.loadUrl(url);
1637         new DelayedCheck(TEST_TIMEOUT) {
1638             @Override
1639             protected boolean check() {
1640                 return mockWebView.hasCalledSetCertificate();
1641             }
1642         }.run();
1643         SslCertificate cert = mockWebView.getCertificate();
1644         assertNotNull(cert);
1645         assertEquals("Android", cert.getIssuedTo().getUName());
1646     }
1647 
1648     @TestTargetNew(
1649         level = TestLevel.NOT_FEASIBLE,
1650         notes = "WebViewClient.onReceivedSslError() is hidden, cannot store SSL preferences.",
1651         method = "clearSslPreferences",
1652         args = {}
1653     )
testClearSslPreferences()1654     public void testClearSslPreferences() {
1655         mWebView.clearSslPreferences();
1656     }
1657 
1658     @TestTargets({
1659         @TestTargetNew(
1660             level = TestLevel.COMPLETE,
1661             method = "pauseTimers",
1662             args = {}
1663         ),
1664         @TestTargetNew(
1665             level = TestLevel.COMPLETE,
1666             method = "resumeTimers",
1667             args = {}
1668         )
1669     })
1670     @ToBeFixed(explanation = "WebView.pauseTimers() does not pause javascript timers")
1671     @BrokenTest(value = "Frequently crashes the process some time after test completion.")
testPauseTimers()1672     public void testPauseTimers() throws Exception {
1673         WebSettings settings = mWebView.getSettings();
1674         settings.setJavaScriptEnabled(true);
1675         startWebServer(false);
1676         // load a page which increments the number in its title every second
1677         String url = mWebServer.getAssetUrl(TestHtmlConstants.TEST_TIMER_URL);
1678         assertLoadUrlSuccessfully(mWebView, url);
1679         int counter = Integer.parseInt(mWebView.getTitle());
1680         Thread.sleep(2000);
1681         assertTrue(Integer.parseInt(mWebView.getTitle()) > counter);
1682         mWebView.pauseTimers();
1683         Thread.sleep(2000); // give the implementation time to stop the timer
1684         counter = Integer.parseInt(mWebView.getTitle());
1685         Thread.sleep(2000);
1686         // ToBeFixed: Uncomment the following line once pauseTimers() is fixed
1687         // assertEquals(counter, Integer.parseInt(mWebView.getTitle()));
1688         mWebView.resumeTimers();
1689         Thread.sleep(2000);
1690         assertTrue(Integer.parseInt(mWebView.getTitle()) > counter);
1691     }
1692 
1693 
1694     @TestTargetNew(
1695         level = TestLevel.COMPLETE,
1696         method = "requestChildRectangleOnScreen",
1697         args = {View.class, Rect.class, boolean.class}
1698     )
testRequestChildRectangleOnScreen()1699     public void testRequestChildRectangleOnScreen() throws Throwable {
1700         DisplayMetrics metrics = mWebView.getContext().getResources().getDisplayMetrics();
1701         final int dimension = 2 * Math.max(metrics.widthPixels, metrics.heightPixels);
1702         String p = "<p style=\"height:" + dimension + "px;width:" + dimension + "px\">&nbsp;</p>";
1703         mWebView.loadData("<html><body>" + p + "</body></html>", "text/html", "UTF-8");
1704         waitForLoadComplete(mWebView, TEST_TIMEOUT);
1705         getInstrumentation().waitForIdleSync();
1706 
1707         runTestOnUiThread(new Runnable() {
1708             public void run() {
1709                 int origX = mWebView.getScrollX();
1710                 int origY = mWebView.getScrollY();
1711 
1712                 int half = dimension / 2;
1713                 Rect rect = new Rect(half, half, half + 1, half + 1);
1714                 assertTrue(mWebView.requestChildRectangleOnScreen(mWebView, rect, true));
1715                 assertTrue(mWebView.getScrollX() > origX);
1716                 assertTrue(mWebView.getScrollY() > origY);
1717             }
1718         });
1719     }
1720 
1721     @TestTargetNew(
1722         level = TestLevel.SUFFICIENT,
1723         method = "performLongClick",
1724         args = {}
1725     )
testPerformLongClick()1726     public void testPerformLongClick() throws InterruptedException {
1727         String form = "<p><form><input type=\"text\" name=\"Test\"><br>"
1728                 + "<input type=\"submit\" value=\"Submit\"></form></p>";
1729         mWebView.loadDataWithBaseURL("fake://home", "<html><body>" + form
1730                 + "</body></html>", "text/html", "UTF-8", null);
1731         waitForLoadComplete(mWebView, TEST_TIMEOUT);
1732 
1733         mWebView.performLongClick();
1734         // no simple way to check the effect of a long click
1735     }
1736 
1737     @TestTargets({
1738         @TestTargetNew(
1739             level = TestLevel.COMPLETE,
1740             method = "setDownloadListener",
1741             args = {DownloadListener.class}
1742         ),
1743         @TestTargetNew(
1744             level = TestLevel.SUFFICIENT,
1745             method = "requestFocus",
1746             args = {int.class, Rect.class}
1747         )
1748     })
1749     @ToBeFixed(explanation="Mime type and content length passed to listener are incorrect.")
testSetDownloadListener()1750     public void testSetDownloadListener() throws Throwable {
1751         final String mimeType = "application/octet-stream";
1752         final int length = 100;
1753         final MyDownloadListener listener = new MyDownloadListener();
1754 
1755         startWebServer(false);
1756         String url = mWebServer.getBinaryUrl(mimeType, length);
1757         mWebView.setWebViewClient(new WebViewClient());
1758         mWebView.setDownloadListener(listener);
1759         mWebView.loadData("<html><body><a href=\"" + url + "\">link</a></body></html>",
1760                 "text/html", "UTF-8");
1761         waitForLoadComplete(mWebView, TEST_TIMEOUT);
1762         // focus on the link
1763         runTestOnUiThread(new Runnable() {
1764             public void run() {
1765                 assertTrue(mWebView.requestFocus(View.FOCUS_DOWN, null));
1766             }
1767         });
1768         getInstrumentation().waitForIdleSync();
1769         getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_CENTER);
1770         new DelayedCheck(TEST_TIMEOUT) {
1771             @Override
1772             protected boolean check() {
1773                 return listener.called;
1774             }
1775         }.run();
1776         assertEquals(url, listener.url);
1777         assertTrue(listener.contentDisposition.contains("test.bin"));
1778         // ToBeFixed: uncomment the following tests after fixing the framework
1779         // assertEquals(mimeType, listener.mimeType);
1780         // assertEquals(length, listener.contentLength);
1781     }
1782 
1783     @TestTargetNew(
1784         level = TestLevel.PARTIAL,
1785         method = "setLayoutParams",
1786         args = {android.view.ViewGroup.LayoutParams.class}
1787     )
1788     @ToBeFixed(bug = "1695243", explanation = "the javadoc for setLayoutParams() is incomplete.")
1789     @UiThreadTest
testSetLayoutParams()1790     public void testSetLayoutParams() {
1791         LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(600, 800);
1792         mWebView.setLayoutParams(params);
1793         assertSame(params, mWebView.getLayoutParams());
1794     }
1795 
1796     @TestTargetNew(
1797         level = TestLevel.NOT_FEASIBLE,
1798         notes = "No documentation",
1799         method = "setMapTrackballToArrowKeys",
1800         args = {boolean.class}
1801     )
testSetMapTrackballToArrowKeys()1802     public void testSetMapTrackballToArrowKeys() {
1803         mWebView.setMapTrackballToArrowKeys(true);
1804     }
1805 
1806     @TestTargetNew(
1807         level = TestLevel.COMPLETE,
1808         method = "setNetworkAvailable",
1809         args = {boolean.class}
1810     )
testSetNetworkAvailable()1811     public void testSetNetworkAvailable() throws Exception {
1812         WebSettings settings = mWebView.getSettings();
1813         settings.setJavaScriptEnabled(true);
1814         startWebServer(false);
1815         String url = mWebServer.getAssetUrl(TestHtmlConstants.NETWORK_STATE_URL);
1816         assertLoadUrlSuccessfully(mWebView, url);
1817         assertEquals("ONLINE", mWebView.getTitle());
1818 
1819         mWebView.setNetworkAvailable(false);
1820         mWebView.reload();
1821         waitForLoadComplete(mWebView, TEST_TIMEOUT);
1822         assertEquals("OFFLINE", mWebView.getTitle());
1823 
1824         mWebView.setNetworkAvailable(true);
1825         mWebView.reload();
1826         waitForLoadComplete(mWebView, TEST_TIMEOUT);
1827         assertEquals("ONLINE", mWebView.getTitle());
1828     }
1829 
1830     @TestTargetNew(
1831         level = TestLevel.COMPLETE,
1832         method = "setWebChromeClient",
1833         args = {WebChromeClient.class}
1834     )
testSetWebChromeClient()1835     public void testSetWebChromeClient() throws Throwable {
1836         final MockWebChromeClient webChromeClient = new MockWebChromeClient();
1837         mWebView.setWebChromeClient(webChromeClient);
1838 
1839         assertFalse(webChromeClient.onProgressChangedCalled());
1840         startWebServer(false);
1841         String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
1842         mWebView.loadUrl(url);
1843 
1844         new DelayedCheck(TEST_TIMEOUT) {
1845             @Override
1846             protected boolean check() {
1847                 return webChromeClient.onProgressChangedCalled();
1848             }
1849         }.run();
1850     }
1851 
1852     @TestTargets({
1853         @TestTargetNew(
1854             level = TestLevel.NOT_NECESSARY,
1855             method = "dispatchKeyEvent",
1856             args = {KeyEvent.class}
1857         ),
1858         @TestTargetNew(
1859             level = TestLevel.NOT_NECESSARY,
1860             method = "onAttachedToWindow",
1861             args = {}
1862         ),
1863         @TestTargetNew(
1864             level = TestLevel.NOT_NECESSARY,
1865             method = "onDetachedFromWindow",
1866             args = {}
1867         ),
1868         @TestTargetNew(
1869             level = TestLevel.NOT_NECESSARY,
1870             method = "onChildViewAdded",
1871             args = {View.class, View.class}
1872         ),
1873         @TestTargetNew(
1874             level = TestLevel.NOT_NECESSARY,
1875             method = "onChildViewRemoved",
1876             args = {View.class, View.class}
1877         ),
1878         @TestTargetNew(
1879             level = TestLevel.NOT_NECESSARY,
1880             method = "onDraw",
1881             args = {Canvas.class}
1882         ),
1883         @TestTargetNew(
1884             level = TestLevel.NOT_NECESSARY,
1885             method = "onFocusChanged",
1886             args = {boolean.class, int.class, Rect.class}
1887         ),
1888         @TestTargetNew(
1889             level = TestLevel.NOT_NECESSARY,
1890             method = "onGlobalFocusChanged",
1891             args = {View.class, View.class}
1892         ),
1893         @TestTargetNew(
1894             level = TestLevel.NOT_NECESSARY,
1895             method = "onKeyDown",
1896             args = {int.class, KeyEvent.class}
1897         ),
1898         @TestTargetNew(
1899             level = TestLevel.NOT_NECESSARY,
1900             method = "onKeyUp",
1901             args = {int.class, KeyEvent.class}
1902         ),
1903         @TestTargetNew(
1904             level = TestLevel.NOT_NECESSARY,
1905             method = "onMeasure",
1906             args = {int.class, int.class}
1907         ),
1908         @TestTargetNew(
1909             level = TestLevel.NOT_NECESSARY,
1910             method = "onScrollChanged",
1911             args = {int.class, int.class, int.class, int.class}
1912         ),
1913         @TestTargetNew(
1914             level = TestLevel.NOT_NECESSARY,
1915             method = "onSizeChanged",
1916             args = {int.class, int.class, int.class, int.class}
1917         ),
1918         @TestTargetNew(
1919             level = TestLevel.NOT_NECESSARY,
1920             method = "onTouchEvent",
1921             args = {MotionEvent.class}
1922         ),
1923         @TestTargetNew(
1924             level = TestLevel.NOT_NECESSARY,
1925             method = "onTrackballEvent",
1926             args = {MotionEvent.class}
1927         ),
1928         @TestTargetNew(
1929             level = TestLevel.NOT_NECESSARY,
1930             method = "onWindowFocusChanged",
1931             args = {boolean.class}
1932         ),
1933         @TestTargetNew(
1934             level = TestLevel.NOT_FEASIBLE,
1935             method = "computeScroll",
1936             args = {}
1937         ),
1938         @TestTargetNew(
1939             level = TestLevel.NOT_FEASIBLE,
1940             method = "computeHorizontalScrollRange",
1941             args = {}
1942         ),
1943         @TestTargetNew(
1944             level = TestLevel.NOT_FEASIBLE,
1945             method = "computeVerticalScrollRange",
1946             args = {}
1947         )
1948     })
testInternals()1949     public void testInternals() {
1950         // Do not test these APIs. They are implementation details.
1951     }
1952 
1953     private static class MockWebView extends WebView {
1954         private boolean mHasCalledSetCertificate;
1955 
MockWebView(Context context)1956         public MockWebView(Context context) {
1957             super(context);
1958         }
1959 
1960         @Override
setCertificate(SslCertificate certificate)1961         public void setCertificate(SslCertificate certificate) {
1962             super.setCertificate(certificate);
1963             mHasCalledSetCertificate = true;
1964         }
1965 
reset()1966         public void reset() {
1967             mHasCalledSetCertificate = false;
1968         }
1969 
hasCalledSetCertificate()1970         public boolean hasCalledSetCertificate() {
1971             return mHasCalledSetCertificate;
1972         }
1973     }
1974 
1975     private static class MockWebViewClient extends WebViewClient {
1976         private boolean mOnScaleChangedCalled = false;
1977 
onScaleChangedCalled()1978         public boolean onScaleChangedCalled() {
1979             return mOnScaleChangedCalled;
1980         }
1981 
1982         @Override
onScaleChanged(WebView view, float oldScale, float newScale)1983         public void onScaleChanged(WebView view, float oldScale, float newScale) {
1984             super.onScaleChanged(view, oldScale, newScale);
1985             mOnScaleChangedCalled = true;
1986         }
1987     }
1988 
1989     private static class MockWebChromeClient extends WebChromeClient {
1990         private boolean mOnProgressChanged = false;
1991 
onProgressChangedCalled()1992         public boolean onProgressChangedCalled() {
1993             return mOnProgressChanged;
1994         }
1995 
1996         @Override
onProgressChanged(WebView view, int newProgress)1997         public void onProgressChanged(WebView view, int newProgress) {
1998             super.onProgressChanged(view, newProgress);
1999             mOnProgressChanged = true;
2000         }
2001     }
2002 
2003     private static class HrefCheckHandler extends Handler {
2004         private boolean mHadRecieved;
2005 
2006         private String mResultUrl;
2007 
HrefCheckHandler(Looper looper)2008         public HrefCheckHandler(Looper looper) {
2009             super(looper);
2010         }
2011 
hasCalledHandleMessage()2012         public boolean hasCalledHandleMessage() {
2013             return mHadRecieved;
2014         }
2015 
getResultUrl()2016         public String getResultUrl() {
2017             return mResultUrl;
2018         }
2019 
reset()2020         public void reset(){
2021             mResultUrl = null;
2022             mHadRecieved = false;
2023         }
2024 
2025         @Override
handleMessage(Message msg)2026         public void handleMessage(Message msg) {
2027             mHadRecieved = true;
2028             mResultUrl = msg.getData().getString("url");
2029         }
2030     }
2031 
2032     private static class DocumentHasImageCheckHandler extends Handler {
2033         private boolean mReceived;
2034 
2035         private int mMsgArg1;
2036 
DocumentHasImageCheckHandler(Looper looper)2037         public DocumentHasImageCheckHandler(Looper looper) {
2038             super(looper);
2039         }
2040 
hasCalledHandleMessage()2041         public boolean hasCalledHandleMessage() {
2042             return mReceived;
2043         }
2044 
getMsgArg1()2045         public int getMsgArg1() {
2046             return mMsgArg1;
2047         }
2048 
reset()2049         public void reset(){
2050             mMsgArg1 = -1;
2051             mReceived = false;
2052         }
2053 
2054         @Override
handleMessage(Message msg)2055         public void handleMessage(Message msg) {
2056             mReceived = true;
2057             mMsgArg1 = msg.arg1;
2058         }
2059     };
2060 
findNextOnUiThread(final boolean forward)2061     private void findNextOnUiThread(final boolean forward) throws Throwable {
2062         runTestOnUiThread(new Runnable() {
2063             public void run() {
2064                 mWebView.findNext(forward);
2065             }
2066         });
2067         getInstrumentation().waitForIdleSync();
2068     }
2069 
moveFocusDown()2070     private void moveFocusDown() throws Throwable {
2071         // send down key and wait for idle
2072         sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
2073         // waiting for idle isn't always sufficient for the key to be fully processed
2074         Thread.sleep(500);
2075     }
2076 
pageDownOnUiThread(final boolean bottom)2077     private boolean pageDownOnUiThread(final boolean bottom) throws Throwable {
2078         PageDownRunner runner = new PageDownRunner(bottom);
2079         runTestOnUiThread(runner);
2080         getInstrumentation().waitForIdleSync();
2081         return runner.mResult;
2082     }
2083 
2084     private class PageDownRunner implements Runnable {
2085         private boolean mResult, mBottom;
2086 
PageDownRunner(boolean bottom)2087         public PageDownRunner(boolean bottom) {
2088             mBottom = bottom;
2089         }
2090 
run()2091         public void run() {
2092             mResult = mWebView.pageDown(mBottom);
2093         }
2094     }
2095 
pageUpOnUiThread(final boolean top)2096     private boolean pageUpOnUiThread(final boolean top) throws Throwable {
2097         PageUpRunner runner = new PageUpRunner(top);
2098         runTestOnUiThread(runner);
2099         getInstrumentation().waitForIdleSync();
2100         return runner.mResult;
2101     }
2102 
2103     private class PageUpRunner implements Runnable {
2104         private boolean mResult, mTop;
2105 
PageUpRunner(boolean top)2106         public PageUpRunner(boolean top) {
2107             this.mTop = top;
2108         }
2109 
run()2110         public void run() {
2111             mResult = mWebView.pageUp(mTop);
2112         }
2113     }
2114 
delayedCheckStopScrolling()2115     private void delayedCheckStopScrolling() {
2116         new DelayedCheck() {
2117             private int scrollY = mWebView.getScrollY();
2118 
2119             @Override
2120             protected boolean check() {
2121                 if (scrollY == mWebView.getScrollY()){
2122                     return true;
2123                 } else {
2124                     scrollY = mWebView.getScrollY();
2125                     return false;
2126                 }
2127             }
2128         }.run();
2129     }
2130 
delayedCheckWebBackForwardList(final String currUrl, final int currIndex, final int size)2131     private void delayedCheckWebBackForwardList(final String currUrl, final int currIndex,
2132             final int size) {
2133         new DelayedCheck() {
2134             @Override
2135             protected boolean check() {
2136                 WebBackForwardList list = mWebView.copyBackForwardList();
2137                 return checkWebBackForwardList(list, currUrl, currIndex, size);
2138             }
2139         }.run();
2140     }
2141 
checkWebBackForwardList(WebBackForwardList list, String currUrl, int currIndex, int size)2142     private boolean checkWebBackForwardList(WebBackForwardList list, String currUrl,
2143             int currIndex, int size) {
2144         return (list != null)
2145                 && (list.getSize() == size)
2146                 && (list.getCurrentIndex() == currIndex)
2147                 && list.getItemAtIndex(currIndex).getUrl().equals(currUrl);
2148     }
2149 
assertGoBackOrForwardBySteps(boolean expected, int steps)2150     private void assertGoBackOrForwardBySteps(boolean expected, int steps) {
2151         // skip if steps equals to 0
2152         if (steps == 0)
2153             return;
2154 
2155         int start = steps > 0 ? 1 : steps;
2156         int end = steps > 0 ? steps : -1;
2157 
2158         // check all the steps in the history
2159         for (int i = start; i <= end; i++) {
2160             assertEquals(expected, mWebView.canGoBackOrForward(i));
2161 
2162             // shortcut methods for one step
2163             if (i == 1) {
2164                 assertEquals(expected, mWebView.canGoForward());
2165             } else if (i == -1) {
2166                 assertEquals(expected, mWebView.canGoBack());
2167             }
2168         }
2169     }
2170 
assertBitmapFillWithColor(Bitmap bitmap, int color)2171     private void assertBitmapFillWithColor(Bitmap bitmap, int color) {
2172         for (int i = 0; i < bitmap.getWidth(); i ++)
2173             for (int j = 0; j < bitmap.getHeight(); j ++) {
2174                 assertEquals(color, bitmap.getPixel(i, j));
2175             }
2176     }
2177 
checkBitmapInsideAnother(Bitmap b1, Bitmap b2)2178     private boolean checkBitmapInsideAnother(Bitmap b1, Bitmap b2) {
2179         for (int i = 0; i < b2.getWidth(); i++) {
2180             for (int j = 0; j < b2.getHeight(); j++) {
2181                 if (checkBitmapInsideAnother(b1, b2, i, j))
2182                     return true;
2183             }
2184         }
2185         return false;
2186     }
2187 
checkBitmapInsideAnother(Bitmap b1, Bitmap b2, int x, int y)2188     private boolean checkBitmapInsideAnother(Bitmap b1, Bitmap b2, int x, int y) {
2189         int w = b1.getWidth();
2190         int h = b1.getHeight();
2191 
2192         if ((x + w > b2.getWidth()) || (x + h > b2.getHeight())) {
2193             return false;
2194         }
2195         for (int i = 0; i < w; i++)
2196             for (int j = 0; j < h; j++) {
2197                 if (b1.getPixel(i, j) != b2.getPixel(x + i, y + j)) {
2198                     return false;
2199                 }
2200             }
2201         return true;
2202     }
2203 
assertLoadUrlSuccessfully(WebView webView, String url)2204     private void assertLoadUrlSuccessfully(WebView webView, String url)
2205             throws InterruptedException {
2206         webView.loadUrl(url);
2207         waitForLoadComplete(webView, TEST_TIMEOUT);
2208     }
2209 
waitForLoadComplete(final WebView webView, long timeout)2210     private void waitForLoadComplete(final WebView webView, long timeout)
2211             throws InterruptedException {
2212         new DelayedCheck(timeout) {
2213             @Override
2214             protected boolean check() {
2215                 return webView.getProgress() == 100;
2216             }
2217         }.run();
2218         Thread.sleep(TIME_FOR_LAYOUT);
2219     }
2220 
2221     private final class DummyJavaScriptInterface {
2222         private boolean mTitleChanged;
2223 
hasChangedTitle()2224         private boolean hasChangedTitle() {
2225             return mTitleChanged;
2226         }
2227 
onLoad(String oldTitle)2228         public void onLoad(String oldTitle) {
2229             mWebView.getHandler().post(new Runnable() {
2230                 public void run() {
2231                     mWebView.loadUrl("javascript:changeTitle(\"new title\")");
2232                     mTitleChanged = true;
2233                 }
2234             });
2235         }
2236     }
2237 
2238     private final class MyDownloadListener implements DownloadListener {
2239         public String url;
2240         public String mimeType;
2241         public long contentLength;
2242         public String contentDisposition;
2243         public boolean called;
2244 
onDownloadStart(String url, String userAgent, String contentDisposition, String mimetype, long contentLength)2245         public void onDownloadStart(String url, String userAgent, String contentDisposition,
2246                 String mimetype, long contentLength) {
2247             this.called = true;
2248             this.url = url;
2249             this.mimeType = mimetype;
2250             this.contentLength = contentLength;
2251             this.contentDisposition = contentDisposition;
2252         }
2253     }
2254 
2255     private static class MyPictureListener implements PictureListener {
2256         public int callCount;
2257         public WebView webView;
2258         public Picture picture;
2259 
onNewPicture(WebView view, Picture picture)2260         public void onNewPicture(WebView view, Picture picture) {
2261             this.callCount += 1;
2262             this.webView = view;
2263             this.picture = picture;
2264         }
2265     }
2266 }
2267