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 android.graphics.Bitmap;
     20 import android.graphics.Canvas;
     21 import android.graphics.Picture;
     22 import android.graphics.Rect;
     23 import android.net.Uri;
     24 import android.net.http.SslCertificate;
     25 import android.os.Message;
     26 import android.print.PrintDocumentAdapter;
     27 import android.util.DisplayMetrics;
     28 import android.view.View;
     29 import android.view.ViewGroup;
     30 import android.view.ViewParent;
     31 import android.webkit.CookieManager;
     32 import android.webkit.DownloadListener;
     33 import android.webkit.ValueCallback;
     34 import android.webkit.WebBackForwardList;
     35 import android.webkit.WebChromeClient;
     36 import android.webkit.WebMessage;
     37 import android.webkit.WebMessagePort;
     38 import android.webkit.WebSettings;
     39 import android.webkit.WebView;
     40 import android.webkit.WebView.HitTestResult;
     41 import android.webkit.WebView.PictureListener;
     42 import android.webkit.WebView.VisualStateCallback;
     43 import android.webkit.WebViewClient;
     44 import android.webkit.WebViewRenderProcessClient;
     45 
     46 import com.android.compatibility.common.util.PollingCheck;
     47 
     48 import com.google.common.util.concurrent.SettableFuture;
     49 
     50 import java.util.concurrent.Executor;
     51 
     52 /**
     53  * Many tests need to run WebView code in the UI thread. This class
     54  * wraps a WebView so that calls are ensured to arrive on the UI thread.
     55  *
     56  * All methods may be run on either the UI thread or test thread.
     57  *
     58  * This should remain functionally equivalent to androidx.webkit.WebViewOnUiThread.
     59  * Modifications to this class should be reflected in that class as necessary. See
     60  * http://go/modifying-webview-cts.
     61  */
     62 public class WebViewOnUiThread extends WebViewSyncLoader {
     63     /**
     64      * The WebView that calls will be made on.
     65      */
     66     private WebView mWebView;
     67 
     68     /**
     69      * Wraps a WebView to ensure that methods are run on the UI thread.
     70      *
     71      * A new WebViewOnUiThread should be called during setUp so as to
     72      * reinitialize between calls.
     73      *
     74      * @param webView The webView that the methods should call.
     75      */
     76     public WebViewOnUiThread(WebView webView) {
     77         super(webView);
     78         mWebView = webView;
     79     }
     80 
     81     public void cleanUp() {
     82         super.destroy();
     83     }
     84 
     85     public void setWebViewClient(final WebViewClient webViewClient) {
     86         WebkitUtils.onMainThreadSync(() -> {
     87             mWebView.setWebViewClient(webViewClient);
     88         });
     89     }
     90 
     91     public void setWebChromeClient(final WebChromeClient webChromeClient) {
     92         WebkitUtils.onMainThreadSync(() -> {
     93             mWebView.setWebChromeClient(webChromeClient);
     94         });
     95     }
     96 
     97     /**
     98      * Set the webview renderer client for {@code mWebView}, on the UI thread.
     99      */
    100     public void setWebViewRenderProcessClient(
    101             final WebViewRenderProcessClient webViewRenderProcessClient) {
    102         setWebViewRenderProcessClient(mWebView, webViewRenderProcessClient);
    103     }
    104 
    105     /**
    106      * Set the webview renderer client for {@code webView}, on the UI thread.
    107      */
    108     public static void setWebViewRenderProcessClient(
    109             final WebView webView,
    110             final WebViewRenderProcessClient webViewRenderProcessClient) {
    111         WebkitUtils.onMainThreadSync(() ->
    112                 webView.setWebViewRenderProcessClient(webViewRenderProcessClient)
    113         );
    114     }
    115 
    116     /**
    117      * Set the webview renderer client for {@code mWebView}, on the UI thread, with callbacks
    118      * executed by {@code executor}
    119      */
    120     public void setWebViewRenderProcessClient(
    121             final Executor executor, final WebViewRenderProcessClient webViewRenderProcessClient) {
    122         setWebViewRenderProcessClient(mWebView, executor, webViewRenderProcessClient);
    123     }
    124 
    125     /**
    126      * Set the webview renderer client for {@code webView}, on the UI thread, with callbacks
    127      * executed by {@code executor}
    128      */
    129     public static void setWebViewRenderProcessClient(
    130             final WebView webView,
    131             final Executor executor,
    132             final WebViewRenderProcessClient webViewRenderProcessClient) {
    133         WebkitUtils.onMainThreadSync(() ->
    134                 webView.setWebViewRenderProcessClient(executor, webViewRenderProcessClient)
    135         );
    136     }
    137 
    138     /**
    139      * Get the webview renderer client currently set on {@code mWebView}, on the UI thread.
    140      */
    141     public WebViewRenderProcessClient getWebViewRenderProcessClient() {
    142         return getWebViewRenderProcessClient(mWebView);
    143     }
    144 
    145     /**
    146      * Get the webview renderer client currently set on {@code webView}, on the UI thread.
    147      */
    148     public static WebViewRenderProcessClient getWebViewRenderProcessClient(
    149             final WebView webView) {
    150         return WebkitUtils.onMainThreadSync(() -> {
    151             return webView.getWebViewRenderProcessClient();
    152         });
    153     }
    154 
    155     public void setPictureListener(final PictureListener pictureListener) {
    156         WebkitUtils.onMainThreadSync(() -> {
    157             mWebView.setPictureListener(pictureListener);
    158         });
    159     }
    160 
    161     public void setNetworkAvailable(final boolean available) {
    162         WebkitUtils.onMainThreadSync(() -> {
    163             mWebView.setNetworkAvailable(available);
    164         });
    165     }
    166 
    167     public void setDownloadListener(final DownloadListener listener) {
    168         WebkitUtils.onMainThreadSync(() -> {
    169             mWebView.setDownloadListener(listener);
    170         });
    171     }
    172 
    173     public void setBackgroundColor(final int color) {
    174         WebkitUtils.onMainThreadSync(() -> {
    175             mWebView.setBackgroundColor(color);
    176         });
    177     }
    178 
    179     public void clearCache(final boolean includeDiskFiles) {
    180         WebkitUtils.onMainThreadSync(() -> {
    181             mWebView.clearCache(includeDiskFiles);
    182         });
    183     }
    184 
    185     public void clearHistory() {
    186         WebkitUtils.onMainThreadSync(() -> {
    187             mWebView.clearHistory();
    188         });
    189     }
    190 
    191     public void requestFocus() {
    192         new PollingCheck(WebkitUtils.TEST_TIMEOUT_MS) {
    193             @Override
    194             protected boolean check() {
    195                 requestFocusOnUiThread();
    196                 return hasFocus();
    197             }
    198         }.run();
    199     }
    200 
    201     private void requestFocusOnUiThread() {
    202         WebkitUtils.onMainThreadSync(() -> {
    203             mWebView.requestFocus();
    204         });
    205     }
    206 
    207     private boolean hasFocus() {
    208         return WebkitUtils.onMainThreadSync(() -> {
    209             return mWebView.hasFocus();
    210         });
    211     }
    212 
    213     public boolean canZoomIn() {
    214         return WebkitUtils.onMainThreadSync(() -> {
    215             return mWebView.canZoomIn();
    216         });
    217     }
    218 
    219     public boolean canZoomOut() {
    220         return WebkitUtils.onMainThreadSync(() -> {
    221             return mWebView.canZoomOut();
    222         });
    223     }
    224 
    225     public boolean zoomIn() {
    226         return WebkitUtils.onMainThreadSync(() -> {
    227             return mWebView.zoomIn();
    228         });
    229     }
    230 
    231     public boolean zoomOut() {
    232         return WebkitUtils.onMainThreadSync(() -> {
    233             return mWebView.zoomOut();
    234         });
    235     }
    236 
    237     public void zoomBy(final float zoomFactor) {
    238         WebkitUtils.onMainThreadSync(() -> {
    239             mWebView.zoomBy(zoomFactor);
    240         });
    241     }
    242 
    243     public void setFindListener(final WebView.FindListener listener) {
    244         WebkitUtils.onMainThreadSync(() -> {
    245             mWebView.setFindListener(listener);
    246         });
    247     }
    248 
    249     public void removeJavascriptInterface(final String interfaceName) {
    250         WebkitUtils.onMainThreadSync(() -> {
    251             mWebView.removeJavascriptInterface(interfaceName);
    252         });
    253     }
    254 
    255     public WebMessagePort[] createWebMessageChannel() {
    256         return WebkitUtils.onMainThreadSync(() -> {
    257             return mWebView.createWebMessageChannel();
    258         });
    259     }
    260 
    261     public void postWebMessage(final WebMessage message, final Uri targetOrigin) {
    262         WebkitUtils.onMainThreadSync(() -> {
    263             mWebView.postWebMessage(message, targetOrigin);
    264         });
    265     }
    266 
    267     public void addJavascriptInterface(final Object object, final String name) {
    268         WebkitUtils.onMainThreadSync(() -> {
    269             mWebView.addJavascriptInterface(object, name);
    270         });
    271     }
    272 
    273     public void flingScroll(final int vx, final int vy) {
    274         WebkitUtils.onMainThreadSync(() -> {
    275             mWebView.flingScroll(vx, vy);
    276         });
    277     }
    278 
    279     public void requestFocusNodeHref(final Message hrefMsg) {
    280         WebkitUtils.onMainThreadSync(() -> {
    281             mWebView.requestFocusNodeHref(hrefMsg);
    282         });
    283     }
    284 
    285     public void requestImageRef(final Message msg) {
    286         WebkitUtils.onMainThreadSync(() -> {
    287             mWebView.requestImageRef(msg);
    288         });
    289     }
    290 
    291     public void setInitialScale(final int scaleInPercent) {
    292         WebkitUtils.onMainThreadSync(() -> {
    293                 mWebView.setInitialScale(scaleInPercent);
    294         });
    295     }
    296 
    297     public void clearSslPreferences() {
    298         WebkitUtils.onMainThreadSync(() -> {
    299             mWebView.clearSslPreferences();
    300         });
    301     }
    302 
    303     public void clearClientCertPreferences(final Runnable onCleared) {
    304         WebkitUtils.onMainThreadSync(() -> {
    305             WebView.clearClientCertPreferences(onCleared);
    306         });
    307     }
    308 
    309     public void resumeTimers() {
    310         WebkitUtils.onMainThreadSync(() -> {
    311             mWebView.resumeTimers();
    312         });
    313     }
    314 
    315     public void findNext(final boolean forward) {
    316         WebkitUtils.onMainThreadSync(() -> {
    317             mWebView.findNext(forward);
    318         });
    319     }
    320 
    321     public void clearMatches() {
    322         WebkitUtils.onMainThreadSync(() -> {
    323             mWebView.clearMatches();
    324         });
    325     }
    326 
    327     public void loadUrl(final String url) {
    328         WebkitUtils.onMainThreadSync(() -> {
    329             mWebView.loadUrl(url);
    330         });
    331     }
    332 
    333     public void stopLoading() {
    334         WebkitUtils.onMainThreadSync(() -> {
    335             mWebView.stopLoading();
    336         });
    337     }
    338 
    339     /**
    340      * Reload the previous URL.
    341      */
    342     public void reload() {
    343         WebkitUtils.onMainThreadSync(() -> {
    344             mWebView.reload();
    345         });
    346     }
    347 
    348     public String getTitle() {
    349         return WebkitUtils.onMainThreadSync(() -> {
    350             return mWebView.getTitle();
    351         });
    352     }
    353 
    354     public WebSettings getSettings() {
    355         return WebkitUtils.onMainThreadSync(() -> {
    356             return mWebView.getSettings();
    357         });
    358     }
    359 
    360     public WebBackForwardList copyBackForwardList() {
    361         return WebkitUtils.onMainThreadSync(() -> {
    362             return mWebView.copyBackForwardList();
    363         });
    364     }
    365 
    366     public Bitmap getFavicon() {
    367         return WebkitUtils.onMainThreadSync(() -> {
    368             return mWebView.getFavicon();
    369         });
    370     }
    371 
    372     public String getUrl() {
    373         return WebkitUtils.onMainThreadSync(() -> {
    374             return mWebView.getUrl();
    375         });
    376     }
    377 
    378     public int getProgress() {
    379         return WebkitUtils.onMainThreadSync(() -> {
    380             return mWebView.getProgress();
    381         });
    382     }
    383 
    384     public int getHeight() {
    385         return WebkitUtils.onMainThreadSync(() -> {
    386             return mWebView.getHeight();
    387         });
    388     }
    389 
    390     public int getContentHeight() {
    391         return WebkitUtils.onMainThreadSync(() -> {
    392             return mWebView.getContentHeight();
    393         });
    394     }
    395 
    396     public boolean pageUp(final boolean top) {
    397         return WebkitUtils.onMainThreadSync(() -> {
    398             return mWebView.pageUp(top);
    399         });
    400     }
    401 
    402     public boolean pageDown(final boolean bottom) {
    403         return WebkitUtils.onMainThreadSync(() -> {
    404             return mWebView.pageDown(bottom);
    405         });
    406     }
    407 
    408     /**
    409      * Post a visual state listener callback for mWebView on the UI thread.
    410      */
    411     public void postVisualStateCallback(final long requestId, final VisualStateCallback callback) {
    412         WebkitUtils.onMainThreadSync(() -> {
    413             mWebView.postVisualStateCallback(requestId, callback);
    414         });
    415     }
    416 
    417     public int[] getLocationOnScreen() {
    418         final int[] location = new int[2];
    419         return WebkitUtils.onMainThreadSync(() -> {
    420             mWebView.getLocationOnScreen(location);
    421             return location;
    422         });
    423     }
    424 
    425     public float getScale() {
    426         return WebkitUtils.onMainThreadSync(() -> {
    427             return mWebView.getScale();
    428         });
    429     }
    430 
    431     public boolean requestFocus(final int direction,
    432             final Rect previouslyFocusedRect) {
    433         return WebkitUtils.onMainThreadSync(() -> {
    434             return mWebView.requestFocus(direction, previouslyFocusedRect);
    435         });
    436     }
    437 
    438     public HitTestResult getHitTestResult() {
    439         return WebkitUtils.onMainThreadSync(() -> {
    440             return mWebView.getHitTestResult();
    441         });
    442     }
    443 
    444     public int getScrollX() {
    445         return WebkitUtils.onMainThreadSync(() -> {
    446             return mWebView.getScrollX();
    447         });
    448     }
    449 
    450     public int getScrollY() {
    451         return WebkitUtils.onMainThreadSync(() -> {
    452             return mWebView.getScrollY();
    453         });
    454     }
    455 
    456     public final DisplayMetrics getDisplayMetrics() {
    457         return WebkitUtils.onMainThreadSync(() -> {
    458             return mWebView.getContext().getResources().getDisplayMetrics();
    459         });
    460     }
    461 
    462     public boolean requestChildRectangleOnScreen(final View child,
    463             final Rect rect,
    464             final boolean immediate) {
    465         return WebkitUtils.onMainThreadSync(() -> {
    466             return mWebView.requestChildRectangleOnScreen(child, rect,
    467                     immediate);
    468         });
    469     }
    470 
    471     public int findAll(final String find) {
    472         return WebkitUtils.onMainThreadSync(() -> {
    473             return mWebView.findAll(find);
    474         });
    475     }
    476 
    477     public Picture capturePicture() {
    478         return WebkitUtils.onMainThreadSync(() -> {
    479             return mWebView.capturePicture();
    480         });
    481     }
    482 
    483     /**
    484      * Execute javascript synchronously, returning the result.
    485      */
    486     public String evaluateJavascriptSync(final String script) {
    487         final SettableFuture<String> future = SettableFuture.create();
    488         evaluateJavascript(script, result -> future.set(result));
    489         return WebkitUtils.waitForFuture(future);
    490     }
    491 
    492     public void evaluateJavascript(final String script, final ValueCallback<String> result) {
    493         WebkitUtils.onMainThreadSync(() -> {
    494             mWebView.evaluateJavascript(script, result);
    495         });
    496     }
    497 
    498     public void saveWebArchive(final String basename, final boolean autoname,
    499                                final ValueCallback<String> callback) {
    500         WebkitUtils.onMainThreadSync(() -> {
    501             mWebView.saveWebArchive(basename, autoname, callback);
    502         });
    503     }
    504 
    505     public SslCertificate getCertificate() {
    506         return WebkitUtils.onMainThreadSync(() -> {
    507             return mWebView.getCertificate();
    508         });
    509     }
    510 
    511     public WebView createWebView() {
    512         return WebkitUtils.onMainThreadSync(() -> {
    513             return new WebView(mWebView.getContext());
    514         });
    515     }
    516 
    517     public PrintDocumentAdapter createPrintDocumentAdapter() {
    518         return WebkitUtils.onMainThreadSync(() -> {
    519             return mWebView.createPrintDocumentAdapter();
    520         });
    521     }
    522 
    523     public void setLayoutHeightToMatchParent() {
    524         WebkitUtils.onMainThreadSync(() -> {
    525             ViewParent parent = mWebView.getParent();
    526             if (parent instanceof ViewGroup) {
    527                 ((ViewGroup) parent).getLayoutParams().height =
    528                     ViewGroup.LayoutParams.MATCH_PARENT;
    529             }
    530             mWebView.getLayoutParams().height = ViewGroup.LayoutParams.MATCH_PARENT;
    531             mWebView.requestLayout();
    532         });
    533     }
    534 
    535     public void setLayoutToMatchParent() {
    536         WebkitUtils.onMainThreadSync(() -> {
    537             setMatchParent((View) mWebView.getParent());
    538             setMatchParent(mWebView);
    539             mWebView.requestLayout();
    540         });
    541     }
    542 
    543     public void setAcceptThirdPartyCookies(final boolean accept) {
    544         WebkitUtils.onMainThreadSync(() -> {
    545             CookieManager.getInstance().setAcceptThirdPartyCookies(mWebView, accept);
    546         });
    547     }
    548 
    549     public boolean acceptThirdPartyCookies() {
    550         return WebkitUtils.onMainThreadSync(() -> {
    551             return CookieManager.getInstance().acceptThirdPartyCookies(mWebView);
    552         });
    553     }
    554 
    555     /**
    556      * Accessor for underlying WebView.
    557      * @return The WebView being wrapped by this class.
    558      */
    559     public WebView getWebView() {
    560         return mWebView;
    561     }
    562 
    563     /**
    564      * Wait for the current state of the DOM to be ready to render on the next draw.
    565      */
    566     public void waitForDOMReadyToRender() {
    567         final SettableFuture<Void> future = SettableFuture.create();
    568         postVisualStateCallback(0, new VisualStateCallback() {
    569             @Override
    570             public void onComplete(long requestId) {
    571                 future.set(null);
    572             }
    573         });
    574         WebkitUtils.waitForFuture(future);
    575     }
    576 
    577     /**
    578      * Capture a bitmap representation of the current WebView state.
    579      *
    580      * This synchronises so that the bitmap contents reflects the current DOM state, rather than
    581      * potentially capturing a previously generated frame.
    582      */
    583     public Bitmap captureBitmap() {
    584         getSettings().setOffscreenPreRaster(true);
    585         waitForDOMReadyToRender();
    586         return WebkitUtils.onMainThreadSync(() -> {
    587             Bitmap bitmap = Bitmap.createBitmap(mWebView.getWidth(), mWebView.getHeight(),
    588                     Bitmap.Config.ARGB_8888);
    589             Canvas canvas = new Canvas(bitmap);
    590             mWebView.draw(canvas);
    591             return bitmap;
    592         });
    593     }
    594 
    595     /**
    596      * Set LayoutParams to MATCH_PARENT.
    597      *
    598      * @param view Target view
    599      */
    600     private void setMatchParent(View view) {
    601         ViewGroup.LayoutParams params = view.getLayoutParams();
    602         params.height = ViewGroup.LayoutParams.MATCH_PARENT;
    603         params.width = ViewGroup.LayoutParams.MATCH_PARENT;
    604         view.setLayoutParams(params);
    605     }
    606 }
    607