Home | History | Annotate | Download | only in cts
      1 /*
      2  * Copyright (C) 2011 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 com.android.compatibility.common.util.PollingCheck;
     20 import com.android.compatibility.common.util.TestThread;
     21 
     22 import android.graphics.Bitmap;
     23 import android.graphics.Picture;
     24 import android.graphics.Rect;
     25 import android.net.Uri;
     26 import android.os.Bundle;
     27 import android.os.Looper;
     28 import android.os.Message;
     29 import android.os.SystemClock;
     30 import android.print.PrintDocumentAdapter;
     31 import android.support.test.rule.ActivityTestRule;
     32 import android.test.InstrumentationTestCase;
     33 import android.util.DisplayMetrics;
     34 import android.view.View;
     35 import android.view.ViewGroup;
     36 import android.view.ViewParent;
     37 import android.webkit.DownloadListener;
     38 import android.webkit.CookieManager;
     39 import android.webkit.ValueCallback;
     40 import android.webkit.WebBackForwardList;
     41 import android.webkit.WebChromeClient;
     42 import android.webkit.WebMessage;
     43 import android.webkit.WebMessagePort;
     44 import android.webkit.WebSettings;
     45 import android.webkit.WebView.HitTestResult;
     46 import android.webkit.WebView.PictureListener;
     47 import android.webkit.WebView.VisualStateCallback;
     48 import android.webkit.WebView;
     49 import android.webkit.WebViewClient;
     50 
     51 import junit.framework.Assert;
     52 
     53 import java.io.File;
     54 import java.util.concurrent.Callable;
     55 import java.util.Map;
     56 
     57 /**
     58  * Many tests need to run WebView code in the UI thread. This class
     59  * wraps a WebView so that calls are ensured to arrive on the UI thread.
     60  *
     61  * All methods may be run on either the UI thread or test thread.
     62  */
     63 public class WebViewOnUiThread {
     64     /**
     65      * The maximum time, in milliseconds (10 seconds) to wait for a load
     66      * to be triggered.
     67      */
     68     private static final long LOAD_TIMEOUT = 10000;
     69 
     70     /**
     71      * Set to true after onPageFinished is called.
     72      */
     73     private boolean mLoaded;
     74 
     75     /**
     76      * Set to true after onNewPicture is called. Reset when onPageStarted
     77      * is called.
     78      */
     79     private boolean mNewPicture;
     80 
     81     /**
     82      * The progress, in percentage, of the page load. Valid values are between
     83      * 0 and 100.
     84      */
     85     private int mProgress;
     86 
     87     /**
     88      * The test that this class is being used in. Used for runTestOnUiThread.
     89      */
     90     private InstrumentationTestCase mTest;
     91 
     92     /**
     93      * The test rule that this class is being used in. Used for runTestOnUiThread.
     94      */
     95     private ActivityTestRule mActivityTestRule;
     96 
     97     /**
     98      * The WebView that calls will be made on.
     99      */
    100     private WebView mWebView;
    101 
    102     /**
    103      * Initializes the webView with a WebViewClient, WebChromeClient,
    104      * and PictureListener to prepare for loadUrlAndWaitForCompletion.
    105      *
    106      * A new WebViewOnUiThread should be called during setUp so as to
    107      * reinitialize between calls.
    108      *
    109      * @param test The test in which this is being run.
    110      * @param webView The webView that the methods should call.
    111      * @see #loadDataAndWaitForCompletion(String, String, String)
    112      * @deprecated Use {@link WebViewOnUiThread#WebViewOnUiThread(ActivityTestRule, WebView)}
    113      */
    114     @Deprecated
    115     public WebViewOnUiThread(InstrumentationTestCase test, WebView webView) {
    116         mTest = test;
    117         mWebView = webView;
    118         final WebViewClient webViewClient = new WaitForLoadedClient(this);
    119         final WebChromeClient webChromeClient = new WaitForProgressClient(this);
    120         runOnUiThread(new Runnable() {
    121             @Override
    122             public void run() {
    123                 mWebView.setWebViewClient(webViewClient);
    124                 mWebView.setWebChromeClient(webChromeClient);
    125                 mWebView.setPictureListener(new WaitForNewPicture());
    126             }
    127         });
    128     }
    129 
    130     /**
    131      * Initializes the webView with a WebViewClient, WebChromeClient,
    132      * and PictureListener to prepare for loadUrlAndWaitForCompletion.
    133      *
    134      * A new WebViewOnUiThread should be called during setUp so as to
    135      * reinitialize between calls.
    136      *
    137      * @param activityTestRule The test rule in which this is being run.
    138      * @param webView The webView that the methods should call.
    139      * @see #loadDataAndWaitForCompletion(String, String, String)
    140      */
    141     public WebViewOnUiThread(ActivityTestRule activityTestRule, WebView webView) {
    142         mActivityTestRule = activityTestRule;
    143         mWebView = webView;
    144         final WebViewClient webViewClient = new WaitForLoadedClient(this);
    145         final WebChromeClient webChromeClient = new WaitForProgressClient(this);
    146         runOnUiThread(() -> {
    147             mWebView.setWebViewClient(webViewClient);
    148             mWebView.setWebChromeClient(webChromeClient);
    149             mWebView.setPictureListener(new WaitForNewPicture());
    150         });
    151     }
    152 
    153     /**
    154      * Called after a test is complete and the WebView should be disengaged from
    155      * the tests.
    156      */
    157     public void cleanUp() {
    158         clearHistory();
    159         clearCache(true);
    160         setPictureListener(null);
    161         setWebChromeClient(null);
    162         setWebViewClient(null);
    163         runOnUiThread(new Runnable() {
    164             @Override
    165             public void run() {
    166                 mWebView.destroy();
    167             }
    168         });
    169     }
    170 
    171     /**
    172      * Called from WaitForNewPicture, this is used to indicate that
    173      * the page has been drawn.
    174      */
    175     synchronized public void onNewPicture() {
    176         mNewPicture = true;
    177         this.notifyAll();
    178     }
    179 
    180     /**
    181      * Called from WaitForLoadedClient, this is used to clear the picture
    182      * draw state so that draws before the URL begins loading don't count.
    183      */
    184     synchronized public void onPageStarted() {
    185         mNewPicture = false; // Earlier paints won't count.
    186     }
    187 
    188     /**
    189      * Called from WaitForLoadedClient, this is used to indicate that
    190      * the page is loaded, but not drawn yet.
    191      */
    192     synchronized public void onPageFinished() {
    193         mLoaded = true;
    194         this.notifyAll();
    195     }
    196 
    197     /**
    198      * Called from the WebChrome client, this sets the current progress
    199      * for a page.
    200      * @param progress The progress made so far between 0 and 100.
    201      */
    202     synchronized public void onProgressChanged(int progress) {
    203         mProgress = progress;
    204         this.notifyAll();
    205     }
    206 
    207     public void setWebViewClient(final WebViewClient webViewClient) {
    208         runOnUiThread(new Runnable() {
    209             @Override
    210             public void run() {
    211                 mWebView.setWebViewClient(webViewClient);
    212             }
    213         });
    214     }
    215 
    216     public void setWebChromeClient(final WebChromeClient webChromeClient) {
    217         runOnUiThread(new Runnable() {
    218             @Override
    219             public void run() {
    220                 mWebView.setWebChromeClient(webChromeClient);
    221             }
    222         });
    223     }
    224 
    225     public void setPictureListener(final PictureListener pictureListener) {
    226         runOnUiThread(new Runnable() {
    227             @Override
    228             public void run() {
    229                 mWebView.setPictureListener(pictureListener);
    230             }
    231         });
    232     }
    233 
    234     public void setNetworkAvailable(final boolean available) {
    235         runOnUiThread(new Runnable() {
    236             @Override
    237             public void run() {
    238                 mWebView.setNetworkAvailable(available);
    239             }
    240         });
    241     }
    242 
    243     public void setDownloadListener(final DownloadListener listener) {
    244         runOnUiThread(new Runnable() {
    245             @Override
    246             public void run() {
    247                 mWebView.setDownloadListener(listener);
    248             }
    249         });
    250     }
    251 
    252     public void setBackgroundColor(final int color) {
    253         runOnUiThread(new Runnable() {
    254             @Override
    255             public void run() {
    256                 mWebView.setBackgroundColor(color);
    257             }
    258         });
    259     }
    260 
    261     public void clearCache(final boolean includeDiskFiles) {
    262         runOnUiThread(new Runnable() {
    263             @Override
    264             public void run() {
    265                 mWebView.clearCache(includeDiskFiles);
    266             }
    267         });
    268     }
    269 
    270     public void clearHistory() {
    271         runOnUiThread(new Runnable() {
    272             @Override
    273             public void run() {
    274                 mWebView.clearHistory();
    275             }
    276         });
    277     }
    278 
    279     public void requestFocus() {
    280         runOnUiThread(new Runnable() {
    281             @Override
    282             public void run() {
    283                 mWebView.requestFocus();
    284             }
    285         });
    286     }
    287 
    288     public boolean canZoomIn() {
    289         return getValue(new ValueGetter<Boolean>() {
    290             @Override
    291             public Boolean capture() {
    292                 return mWebView.canZoomIn();
    293             }
    294         });
    295     }
    296 
    297     public boolean canZoomOut() {
    298         return getValue(new ValueGetter<Boolean>() {
    299             @Override
    300             public Boolean capture() {
    301                 return mWebView.canZoomOut();
    302             }
    303         });
    304     }
    305 
    306     public boolean zoomIn() {
    307         return getValue(new ValueGetter<Boolean>() {
    308             @Override
    309             public Boolean capture() {
    310                 return mWebView.zoomIn();
    311             }
    312         });
    313     }
    314 
    315     public boolean zoomOut() {
    316         return getValue(new ValueGetter<Boolean>() {
    317             @Override
    318             public Boolean capture() {
    319                 return mWebView.zoomOut();
    320             }
    321         });
    322     }
    323 
    324     public void zoomBy(final float zoomFactor) {
    325         runOnUiThread(new Runnable() {
    326             @Override
    327             public void run() {
    328                 mWebView.zoomBy(zoomFactor);
    329             }
    330         });
    331     }
    332 
    333     public void setFindListener(final WebView.FindListener listener) {
    334         runOnUiThread(new Runnable() {
    335             @Override
    336             public void run() {
    337                 mWebView.setFindListener(listener);
    338             }
    339         });
    340     }
    341 
    342     public void removeJavascriptInterface(final String interfaceName) {
    343         runOnUiThread(new Runnable() {
    344             @Override
    345             public void run() {
    346                 mWebView.removeJavascriptInterface(interfaceName);
    347             }
    348         });
    349     }
    350 
    351     public WebMessagePort[] createWebMessageChannel() {
    352         return getValue(new ValueGetter<WebMessagePort[]>() {
    353             @Override
    354             public WebMessagePort[] capture() {
    355                 return mWebView.createWebMessageChannel();
    356             }
    357         });
    358     }
    359 
    360     public void postWebMessage(final WebMessage message, final Uri targetOrigin) {
    361         runOnUiThread(new Runnable() {
    362             @Override
    363             public void run() {
    364                 mWebView.postWebMessage(message, targetOrigin);
    365             }
    366         });
    367     }
    368 
    369     public void addJavascriptInterface(final Object object, final String name) {
    370         runOnUiThread(new Runnable() {
    371             @Override
    372             public void run() {
    373                 mWebView.addJavascriptInterface(object, name);
    374             }
    375         });
    376     }
    377 
    378     public void flingScroll(final int vx, final int vy) {
    379         runOnUiThread(new Runnable() {
    380             @Override
    381             public void run() {
    382                 mWebView.flingScroll(vx, vy);
    383             }
    384         });
    385     }
    386 
    387     public void requestFocusNodeHref(final Message hrefMsg) {
    388         runOnUiThread(new Runnable() {
    389             @Override
    390             public void run() {
    391                 mWebView.requestFocusNodeHref(hrefMsg);
    392             }
    393         });
    394     }
    395 
    396     public void requestImageRef(final Message msg) {
    397         runOnUiThread(new Runnable() {
    398             @Override
    399             public void run() {
    400                 mWebView.requestImageRef(msg);
    401             }
    402         });
    403     }
    404 
    405     public void setInitialScale(final int scaleInPercent) {
    406         runOnUiThread(new Runnable() {
    407             @Override
    408             public void run() {
    409                 mWebView.setInitialScale(scaleInPercent);
    410             }
    411         });
    412     }
    413 
    414     public void clearSslPreferences() {
    415         runOnUiThread(new Runnable() {
    416             @Override
    417             public void run() {
    418                 mWebView.clearSslPreferences();
    419             }
    420         });
    421     }
    422 
    423     public void clearClientCertPreferences(final Runnable onCleared) {
    424         runOnUiThread(new Runnable() {
    425             @Override
    426             public void run() {
    427                 WebView.clearClientCertPreferences(onCleared);
    428             }
    429         });
    430     }
    431 
    432     public void resumeTimers() {
    433         runOnUiThread(new Runnable() {
    434             @Override
    435             public void run() {
    436                 mWebView.resumeTimers();
    437             }
    438         });
    439     }
    440 
    441     public void findNext(final boolean forward) {
    442         runOnUiThread(new Runnable() {
    443             @Override
    444             public void run() {
    445                 mWebView.findNext(forward);
    446             }
    447         });
    448     }
    449 
    450     public void clearMatches() {
    451         runOnUiThread(new Runnable() {
    452             @Override
    453             public void run() {
    454                 mWebView.clearMatches();
    455             }
    456         });
    457     }
    458 
    459     /**
    460      * Calls loadUrl on the WebView and then waits onPageFinished,
    461      * onNewPicture and onProgressChange to reach 100.
    462      * Test fails if the load timeout elapses.
    463      * @param url The URL to load.
    464      */
    465     public void loadUrlAndWaitForCompletion(final String url) {
    466         callAndWait(new Runnable() {
    467             @Override
    468             public void run() {
    469                 mWebView.loadUrl(url);
    470             }
    471         });
    472     }
    473 
    474     /**
    475      * Calls loadUrl on the WebView and then waits onPageFinished,
    476      * onNewPicture and onProgressChange to reach 100.
    477      * Test fails if the load timeout elapses.
    478      * @param url The URL to load.
    479      * @param extraHeaders The additional headers to be used in the HTTP request.
    480      */
    481     public void loadUrlAndWaitForCompletion(final String url,
    482             final Map<String, String> extraHeaders) {
    483         callAndWait(new Runnable() {
    484             @Override
    485             public void run() {
    486                 mWebView.loadUrl(url, extraHeaders);
    487             }
    488         });
    489     }
    490 
    491     public void loadUrl(final String url) {
    492         runOnUiThread(new Runnable() {
    493             @Override
    494             public void run() {
    495                 mWebView.loadUrl(url);
    496             }
    497         });
    498     }
    499 
    500     public void stopLoading() {
    501         runOnUiThread(new Runnable() {
    502             @Override
    503             public void run() {
    504                 mWebView.stopLoading();
    505             }
    506         });
    507     }
    508 
    509     public void postUrlAndWaitForCompletion(final String url, final byte[] postData) {
    510         callAndWait(new Runnable() {
    511             @Override
    512             public void run() {
    513                 mWebView.postUrl(url, postData);
    514             }
    515         });
    516     }
    517 
    518     public void loadDataAndWaitForCompletion(final String data,
    519             final String mimeType, final String encoding) {
    520         callAndWait(new Runnable() {
    521             @Override
    522             public void run() {
    523                 mWebView.loadData(data, mimeType, encoding);
    524             }
    525         });
    526     }
    527 
    528     public void loadDataWithBaseURLAndWaitForCompletion(final String baseUrl,
    529             final String data, final String mimeType, final String encoding,
    530             final String historyUrl) {
    531         callAndWait(new Runnable() {
    532             @Override
    533             public void run() {
    534                 mWebView.loadDataWithBaseURL(baseUrl, data, mimeType, encoding,
    535                         historyUrl);
    536             }
    537         });
    538     }
    539 
    540     /**
    541      * Reloads a page and waits for it to complete reloading. Use reload
    542      * if it is a form resubmission and the onFormResubmission responds
    543      * by telling WebView not to resubmit it.
    544      */
    545     public void reloadAndWaitForCompletion() {
    546         callAndWait(new Runnable() {
    547             @Override
    548             public void run() {
    549                 mWebView.reload();
    550             }
    551         });
    552     }
    553 
    554     /**
    555      * Reload the previous URL. Use reloadAndWaitForCompletion unless
    556      * it is a form resubmission and the onFormResubmission responds
    557      * by telling WebView not to resubmit it.
    558      */
    559     public void reload() {
    560         runOnUiThread(new Runnable() {
    561             @Override
    562             public void run() {
    563                 mWebView.reload();
    564             }
    565         });
    566     }
    567 
    568     /**
    569      * Use this only when JavaScript causes a page load to wait for the
    570      * page load to complete. Otherwise use loadUrlAndWaitForCompletion or
    571      * similar functions.
    572      */
    573     public void waitForLoadCompletion() {
    574         waitForCriteria(LOAD_TIMEOUT,
    575                 new Callable<Boolean>() {
    576                     @Override
    577                     public Boolean call() {
    578                         return isLoaded();
    579                     }
    580                 });
    581         clearLoad();
    582     }
    583 
    584     private void waitForCriteria(long timeout, Callable<Boolean> doneCriteria) {
    585         if (isUiThread()) {
    586             waitOnUiThread(timeout, doneCriteria);
    587         } else {
    588             waitOnTestThread(timeout, doneCriteria);
    589         }
    590     }
    591 
    592     public String getTitle() {
    593         return getValue(new ValueGetter<String>() {
    594             @Override
    595             public String capture() {
    596                 return mWebView.getTitle();
    597             }
    598         });
    599     }
    600 
    601     public WebSettings getSettings() {
    602         return getValue(new ValueGetter<WebSettings>() {
    603             @Override
    604             public WebSettings capture() {
    605                 return mWebView.getSettings();
    606             }
    607         });
    608     }
    609 
    610     public WebBackForwardList copyBackForwardList() {
    611         return getValue(new ValueGetter<WebBackForwardList>() {
    612             @Override
    613             public WebBackForwardList capture() {
    614                 return mWebView.copyBackForwardList();
    615             }
    616         });
    617     }
    618 
    619     public Bitmap getFavicon() {
    620         return getValue(new ValueGetter<Bitmap>() {
    621             @Override
    622             public Bitmap capture() {
    623                 return mWebView.getFavicon();
    624             }
    625         });
    626     }
    627 
    628     public String getUrl() {
    629         return getValue(new ValueGetter<String>() {
    630             @Override
    631             public String capture() {
    632                 return mWebView.getUrl();
    633             }
    634         });
    635     }
    636 
    637     public int getProgress() {
    638         return getValue(new ValueGetter<Integer>() {
    639             @Override
    640             public Integer capture() {
    641                 return mWebView.getProgress();
    642             }
    643         });
    644     }
    645 
    646     public int getHeight() {
    647         return getValue(new ValueGetter<Integer>() {
    648             @Override
    649             public Integer capture() {
    650                 return mWebView.getHeight();
    651             }
    652         });
    653     }
    654 
    655     public int getContentHeight() {
    656         return getValue(new ValueGetter<Integer>() {
    657             @Override
    658             public Integer capture() {
    659                 return mWebView.getContentHeight();
    660             }
    661         });
    662     }
    663 
    664     public boolean pageUp(final boolean top) {
    665         return getValue(new ValueGetter<Boolean>() {
    666             @Override
    667             public Boolean capture() {
    668                 return mWebView.pageUp(top);
    669             }
    670         });
    671     }
    672 
    673     public boolean pageDown(final boolean bottom) {
    674         return getValue(new ValueGetter<Boolean>() {
    675             @Override
    676             public Boolean capture() {
    677                 return mWebView.pageDown(bottom);
    678             }
    679         });
    680     }
    681 
    682     public void postVisualStateCallback(final long requestId, final VisualStateCallback callback) {
    683         runOnUiThread(new Runnable() {
    684             @Override
    685             public void run() {
    686                 mWebView.postVisualStateCallback(requestId, callback);
    687             }
    688         });
    689     }
    690 
    691     public int[] getLocationOnScreen() {
    692         final int[] location = new int[2];
    693         return getValue(new ValueGetter<int[]>() {
    694             @Override
    695             public int[] capture() {
    696                 mWebView.getLocationOnScreen(location);
    697                 return location;
    698             }
    699         });
    700     }
    701 
    702     public float getScale() {
    703         return getValue(new ValueGetter<Float>() {
    704             @Override
    705             public Float capture() {
    706                 return mWebView.getScale();
    707             }
    708         });
    709     }
    710 
    711     public boolean requestFocus(final int direction,
    712             final Rect previouslyFocusedRect) {
    713         return getValue(new ValueGetter<Boolean>() {
    714             @Override
    715             public Boolean capture() {
    716                 return mWebView.requestFocus(direction, previouslyFocusedRect);
    717             }
    718         });
    719     }
    720 
    721     public HitTestResult getHitTestResult() {
    722         return getValue(new ValueGetter<HitTestResult>() {
    723             @Override
    724             public HitTestResult capture() {
    725                 return mWebView.getHitTestResult();
    726             }
    727         });
    728     }
    729 
    730     public int getScrollX() {
    731         return getValue(new ValueGetter<Integer>() {
    732             @Override
    733             public Integer capture() {
    734                 return mWebView.getScrollX();
    735             }
    736         });
    737     }
    738 
    739     public int getScrollY() {
    740         return getValue(new ValueGetter<Integer>() {
    741             @Override
    742             public Integer capture() {
    743                 return mWebView.getScrollY();
    744             }
    745         });
    746     }
    747 
    748     public final DisplayMetrics getDisplayMetrics() {
    749         return getValue(new ValueGetter<DisplayMetrics>() {
    750             @Override
    751             public DisplayMetrics capture() {
    752                 return mWebView.getContext().getResources().getDisplayMetrics();
    753             }
    754         });
    755     }
    756 
    757     public boolean requestChildRectangleOnScreen(final View child,
    758             final Rect rect,
    759             final boolean immediate) {
    760         return getValue(new ValueGetter<Boolean>() {
    761             @Override
    762             public Boolean capture() {
    763                 return mWebView.requestChildRectangleOnScreen(child, rect,
    764                         immediate);
    765             }
    766         });
    767     }
    768 
    769     public int findAll(final String find) {
    770         return getValue(new ValueGetter<Integer>() {
    771             @Override
    772             public Integer capture() {
    773                 return mWebView.findAll(find);
    774             }
    775         });
    776     }
    777 
    778     public Picture capturePicture() {
    779         return getValue(new ValueGetter<Picture>() {
    780             @Override
    781             public Picture capture() {
    782                 return mWebView.capturePicture();
    783             }
    784         });
    785     }
    786 
    787     public void evaluateJavascript(final String script, final ValueCallback<String> result) {
    788         runOnUiThread(new Runnable() {
    789             @Override
    790             public void run() {
    791                 mWebView.evaluateJavascript(script, result);
    792             }
    793         });
    794     }
    795 
    796     public void saveWebArchive(final String basename, final boolean autoname,
    797                                final ValueCallback<String> callback) {
    798         runOnUiThread(new Runnable() {
    799             @Override
    800             public void run() {
    801                 mWebView.saveWebArchive(basename, autoname, callback);
    802             }
    803         });
    804     }
    805 
    806     public WebView createWebView() {
    807         return getValue(new ValueGetter<WebView>() {
    808             @Override
    809             public WebView capture() {
    810                 return new WebView(mWebView.getContext());
    811             }
    812         });
    813     }
    814 
    815     public PrintDocumentAdapter createPrintDocumentAdapter() {
    816         return getValue(new ValueGetter<PrintDocumentAdapter>() {
    817             @Override
    818             public PrintDocumentAdapter capture() {
    819                 return mWebView.createPrintDocumentAdapter();
    820             }
    821         });
    822     }
    823 
    824     public void setLayoutHeightToMatchParent() {
    825         runOnUiThread(new Runnable() {
    826             @Override
    827             public void run() {
    828                 ViewParent parent = mWebView.getParent();
    829                 if (parent instanceof ViewGroup) {
    830                     ((ViewGroup) parent).getLayoutParams().height =
    831                         ViewGroup.LayoutParams.MATCH_PARENT;
    832                 }
    833                 mWebView.getLayoutParams().height = ViewGroup.LayoutParams.MATCH_PARENT;
    834                 mWebView.requestLayout();
    835             }
    836         });
    837     }
    838 
    839     public void setLayoutToMatchParent() {
    840         runOnUiThread(new Runnable() {
    841             @Override
    842             public void run() {
    843                 setMatchParent((View) mWebView.getParent());
    844                 setMatchParent(mWebView);
    845                 mWebView.requestLayout();
    846             }
    847         });
    848     }
    849 
    850     public void setAcceptThirdPartyCookies(final boolean accept) {
    851         runOnUiThread(new Runnable() {
    852             @Override
    853             public void run() {
    854                 CookieManager.getInstance().setAcceptThirdPartyCookies(mWebView, accept);
    855             }
    856         });
    857     }
    858 
    859     public boolean acceptThirdPartyCookies() {
    860         return getValue(new ValueGetter<Boolean>() {
    861             @Override
    862             public Boolean capture() {
    863                 return CookieManager.getInstance().acceptThirdPartyCookies(mWebView);
    864             }
    865         });
    866     }
    867 
    868     /**
    869      * Helper for running code on the UI thread where an exception is
    870      * a test failure. If this is already the UI thread then it runs
    871      * the code immediately.
    872      *
    873      * @see InstrumentationTestCase#runTestOnUiThread(Runnable)
    874      * @see ActivityTestRule#runOnUiThread(Runnable)
    875      * @param r The code to run in the UI thread
    876      */
    877     public void runOnUiThread(Runnable r) {
    878         try {
    879             if (isUiThread()) {
    880                 r.run();
    881             } else {
    882                 if (mActivityTestRule != null) {
    883                     mActivityTestRule.runOnUiThread(r);
    884                 } else {
    885                     mTest.runTestOnUiThread(r);
    886                 }
    887             }
    888         } catch (Throwable t) {
    889             Assert.fail("Unexpected error while running on UI thread: "
    890                     + t.getMessage());
    891         }
    892     }
    893 
    894     /**
    895      * Accessor for underlying WebView.
    896      * @return The WebView being wrapped by this class.
    897      */
    898     public WebView getWebView() {
    899         return mWebView;
    900     }
    901 
    902     private<T> T getValue(ValueGetter<T> getter) {
    903         runOnUiThread(getter);
    904         return getter.getValue();
    905     }
    906 
    907     private abstract class ValueGetter<T> implements Runnable {
    908         private T mValue;
    909 
    910         @Override
    911         public void run() {
    912             mValue = capture();
    913         }
    914 
    915         protected abstract T capture();
    916 
    917         public T getValue() {
    918            return mValue;
    919         }
    920     }
    921 
    922     /**
    923      * Returns true if the current thread is the UI thread based on the
    924      * Looper.
    925      */
    926     private static boolean isUiThread() {
    927         return (Looper.myLooper() == Looper.getMainLooper());
    928     }
    929 
    930     /**
    931      * @return Whether or not the load has finished.
    932      */
    933     private synchronized boolean isLoaded() {
    934         return mLoaded && mNewPicture && mProgress == 100;
    935     }
    936 
    937     /**
    938      * Makes a WebView call, waits for completion and then resets the
    939      * load state in preparation for the next load call.
    940      * @param call The call to make on the UI thread prior to waiting.
    941      */
    942     private void callAndWait(Runnable call) {
    943         Assert.assertTrue("WebViewOnUiThread.load*AndWaitForCompletion calls "
    944                 + "may not be mixed with load* calls directly on WebView "
    945                 + "without calling waitForLoadCompletion after the load",
    946                 !isLoaded());
    947         clearLoad(); // clear any extraneous signals from a previous load.
    948         runOnUiThread(call);
    949         waitForLoadCompletion();
    950     }
    951 
    952     /**
    953      * Called whenever a load has been completed so that a subsequent call to
    954      * waitForLoadCompletion doesn't return immediately.
    955      */
    956     synchronized private void clearLoad() {
    957         mLoaded = false;
    958         mNewPicture = false;
    959         mProgress = 0;
    960     }
    961 
    962     /**
    963      * Uses a polling mechanism, while pumping messages to check when the
    964      * criteria is met.
    965      */
    966     private void waitOnUiThread(long timeout, final Callable<Boolean> doneCriteria) {
    967         new PollingCheck(timeout) {
    968             @Override
    969             protected boolean check() {
    970                 pumpMessages();
    971                 try {
    972                     return doneCriteria.call();
    973                 } catch (Exception e) {
    974                     Assert.fail("Unexpected error while checking the criteria: "
    975                             + e.getMessage());
    976                     return true;
    977                 }
    978             }
    979         }.run();
    980     }
    981 
    982     /**
    983      * Uses a wait/notify to check when the criteria is met.
    984      */
    985     private synchronized void waitOnTestThread(long timeout, Callable<Boolean> doneCriteria) {
    986         try {
    987             long waitEnd = SystemClock.uptimeMillis() + timeout;
    988             long timeRemaining = timeout;
    989             while (!doneCriteria.call() && timeRemaining > 0) {
    990                 this.wait(timeRemaining);
    991                 timeRemaining = waitEnd - SystemClock.uptimeMillis();
    992             }
    993             Assert.assertTrue("Action failed to complete before timeout", doneCriteria.call());
    994         } catch (InterruptedException e) {
    995             // We'll just drop out of the loop and fail
    996         } catch (Exception e) {
    997             Assert.fail("Unexpected error while checking the criteria: "
    998                     + e.getMessage());
    999         }
   1000     }
   1001 
   1002     /**
   1003      * Pumps all currently-queued messages in the UI thread and then exits.
   1004      * This is useful to force processing while running tests in the UI thread.
   1005      */
   1006     private void pumpMessages() {
   1007         class ExitLoopException extends RuntimeException {
   1008         }
   1009 
   1010         // Force loop to exit when processing this. Loop.quit() doesn't
   1011         // work because this is the main Loop.
   1012         mWebView.getHandler().post(new Runnable() {
   1013             @Override
   1014             public void run() {
   1015                 throw new ExitLoopException(); // exit loop!
   1016             }
   1017         });
   1018         try {
   1019             // Pump messages until our message gets through.
   1020             Looper.loop();
   1021         } catch (ExitLoopException e) {
   1022         }
   1023     }
   1024 
   1025     /**
   1026      * Set LayoutParams to MATCH_PARENT.
   1027      *
   1028      * @param view Target view
   1029      */
   1030     private void setMatchParent(View view) {
   1031         ViewGroup.LayoutParams params = view.getLayoutParams();
   1032         params.height = ViewGroup.LayoutParams.MATCH_PARENT;
   1033         params.width = ViewGroup.LayoutParams.MATCH_PARENT;
   1034         view.setLayoutParams(params);
   1035     }
   1036 
   1037     /**
   1038      * A WebChromeClient used to capture the onProgressChanged for use
   1039      * in waitFor functions. If a test must override the WebChromeClient,
   1040      * it can derive from this class or call onProgressChanged
   1041      * directly.
   1042      */
   1043     public static class WaitForProgressClient extends WebChromeClient {
   1044         private WebViewOnUiThread mOnUiThread;
   1045 
   1046         public WaitForProgressClient(WebViewOnUiThread onUiThread) {
   1047             mOnUiThread = onUiThread;
   1048         }
   1049 
   1050         @Override
   1051         public void onProgressChanged(WebView view, int newProgress) {
   1052             super.onProgressChanged(view, newProgress);
   1053             mOnUiThread.onProgressChanged(newProgress);
   1054         }
   1055     }
   1056 
   1057     /**
   1058      * A WebViewClient that captures the onPageFinished for use in
   1059      * waitFor functions. Using initializeWebView sets the WaitForLoadedClient
   1060      * into the WebView. If a test needs to set a specific WebViewClient and
   1061      * needs the waitForCompletion capability then it should derive from
   1062      * WaitForLoadedClient or call WebViewOnUiThread.onPageFinished.
   1063      */
   1064     public static class WaitForLoadedClient extends WebViewClient {
   1065         private WebViewOnUiThread mOnUiThread;
   1066 
   1067         public WaitForLoadedClient(WebViewOnUiThread onUiThread) {
   1068             mOnUiThread = onUiThread;
   1069         }
   1070 
   1071         @Override
   1072         public void onPageFinished(WebView view, String url) {
   1073             super.onPageFinished(view, url);
   1074             mOnUiThread.onPageFinished();
   1075         }
   1076 
   1077         @Override
   1078         public void onPageStarted(WebView view, String url, Bitmap favicon) {
   1079             super.onPageStarted(view, url, favicon);
   1080             mOnUiThread.onPageStarted();
   1081         }
   1082     }
   1083 
   1084     /**
   1085      * A PictureListener that captures the onNewPicture for use in
   1086      * waitForLoadCompletion. Using initializeWebView sets the PictureListener
   1087      * into the WebView. If a test needs to set a specific PictureListener and
   1088      * needs the waitForCompletion capability then it should call
   1089      * WebViewOnUiThread.onNewPicture.
   1090      */
   1091     private class WaitForNewPicture implements PictureListener {
   1092         @Override
   1093         public void onNewPicture(WebView view, Picture picture) {
   1094             WebViewOnUiThread.this.onNewPicture();
   1095         }
   1096     }
   1097 }
   1098