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