| /* |
| * Copyright (C) 2011 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package android.webkit.cts; |
| |
| import android.graphics.Bitmap; |
| import android.graphics.Canvas; |
| import android.graphics.Picture; |
| import android.graphics.Rect; |
| import android.net.Uri; |
| import android.net.http.SslCertificate; |
| import android.os.Message; |
| import android.print.PrintDocumentAdapter; |
| import android.util.DisplayMetrics; |
| import android.view.View; |
| import android.view.ViewGroup; |
| import android.view.ViewParent; |
| import android.webkit.CookieManager; |
| import android.webkit.DownloadListener; |
| import android.webkit.ValueCallback; |
| import android.webkit.WebBackForwardList; |
| import android.webkit.WebChromeClient; |
| import android.webkit.WebMessage; |
| import android.webkit.WebMessagePort; |
| import android.webkit.WebSettings; |
| import android.webkit.WebView; |
| import android.webkit.WebView.HitTestResult; |
| import android.webkit.WebView.PictureListener; |
| import android.webkit.WebView.VisualStateCallback; |
| import android.webkit.WebViewClient; |
| import android.webkit.WebViewRenderProcessClient; |
| |
| import com.android.compatibility.common.util.PollingCheck; |
| |
| import com.google.common.util.concurrent.SettableFuture; |
| |
| import java.util.concurrent.Executor; |
| |
| /** |
| * Many tests need to run WebView code in the UI thread. This class |
| * wraps a WebView so that calls are ensured to arrive on the UI thread. |
| * |
| * All methods may be run on either the UI thread or test thread. |
| * |
| * This should remain functionally equivalent to androidx.webkit.WebViewOnUiThread. |
| * Modifications to this class should be reflected in that class as necessary. See |
| * http://go/modifying-webview-cts. |
| */ |
| public class WebViewOnUiThread extends WebViewSyncLoader { |
| /** |
| * The WebView that calls will be made on. |
| */ |
| private WebView mWebView; |
| |
| /** |
| * Wraps a WebView to ensure that methods are run on the UI thread. |
| * |
| * A new WebViewOnUiThread should be called during setUp so as to |
| * reinitialize between calls. |
| * |
| * @param webView The webView that the methods should call. |
| */ |
| public WebViewOnUiThread(WebView webView) { |
| super(webView); |
| mWebView = webView; |
| } |
| |
| public void cleanUp() { |
| super.destroy(); |
| } |
| |
| public void setWebViewClient(final WebViewClient webViewClient) { |
| WebkitUtils.onMainThreadSync(() -> { |
| mWebView.setWebViewClient(webViewClient); |
| }); |
| } |
| |
| public void setWebChromeClient(final WebChromeClient webChromeClient) { |
| WebkitUtils.onMainThreadSync(() -> { |
| mWebView.setWebChromeClient(webChromeClient); |
| }); |
| } |
| |
| /** |
| * Set the webview renderer client for {@code mWebView}, on the UI thread. |
| */ |
| public void setWebViewRenderProcessClient( |
| final WebViewRenderProcessClient webViewRenderProcessClient) { |
| setWebViewRenderProcessClient(mWebView, webViewRenderProcessClient); |
| } |
| |
| /** |
| * Set the webview renderer client for {@code webView}, on the UI thread. |
| */ |
| public static void setWebViewRenderProcessClient( |
| final WebView webView, |
| final WebViewRenderProcessClient webViewRenderProcessClient) { |
| WebkitUtils.onMainThreadSync(() -> |
| webView.setWebViewRenderProcessClient(webViewRenderProcessClient) |
| ); |
| } |
| |
| /** |
| * Set the webview renderer client for {@code mWebView}, on the UI thread, with callbacks |
| * executed by {@code executor} |
| */ |
| public void setWebViewRenderProcessClient( |
| final Executor executor, final WebViewRenderProcessClient webViewRenderProcessClient) { |
| setWebViewRenderProcessClient(mWebView, executor, webViewRenderProcessClient); |
| } |
| |
| /** |
| * Set the webview renderer client for {@code webView}, on the UI thread, with callbacks |
| * executed by {@code executor} |
| */ |
| public static void setWebViewRenderProcessClient( |
| final WebView webView, |
| final Executor executor, |
| final WebViewRenderProcessClient webViewRenderProcessClient) { |
| WebkitUtils.onMainThreadSync(() -> |
| webView.setWebViewRenderProcessClient(executor, webViewRenderProcessClient) |
| ); |
| } |
| |
| /** |
| * Get the webview renderer client currently set on {@code mWebView}, on the UI thread. |
| */ |
| public WebViewRenderProcessClient getWebViewRenderProcessClient() { |
| return getWebViewRenderProcessClient(mWebView); |
| } |
| |
| /** |
| * Get the webview renderer client currently set on {@code webView}, on the UI thread. |
| */ |
| public static WebViewRenderProcessClient getWebViewRenderProcessClient( |
| final WebView webView) { |
| return WebkitUtils.onMainThreadSync(() -> { |
| return webView.getWebViewRenderProcessClient(); |
| }); |
| } |
| |
| public void setPictureListener(final PictureListener pictureListener) { |
| WebkitUtils.onMainThreadSync(() -> { |
| mWebView.setPictureListener(pictureListener); |
| }); |
| } |
| |
| public void setNetworkAvailable(final boolean available) { |
| WebkitUtils.onMainThreadSync(() -> { |
| mWebView.setNetworkAvailable(available); |
| }); |
| } |
| |
| public void setDownloadListener(final DownloadListener listener) { |
| WebkitUtils.onMainThreadSync(() -> { |
| mWebView.setDownloadListener(listener); |
| }); |
| } |
| |
| public void setBackgroundColor(final int color) { |
| WebkitUtils.onMainThreadSync(() -> { |
| mWebView.setBackgroundColor(color); |
| }); |
| } |
| |
| public void clearCache(final boolean includeDiskFiles) { |
| WebkitUtils.onMainThreadSync(() -> { |
| mWebView.clearCache(includeDiskFiles); |
| }); |
| } |
| |
| public void clearHistory() { |
| WebkitUtils.onMainThreadSync(() -> { |
| mWebView.clearHistory(); |
| }); |
| } |
| |
| public void requestFocus() { |
| new PollingCheck(WebkitUtils.TEST_TIMEOUT_MS) { |
| @Override |
| protected boolean check() { |
| requestFocusOnUiThread(); |
| return hasFocus(); |
| } |
| }.run(); |
| } |
| |
| private void requestFocusOnUiThread() { |
| WebkitUtils.onMainThreadSync(() -> { |
| mWebView.requestFocus(); |
| }); |
| } |
| |
| private boolean hasFocus() { |
| return WebkitUtils.onMainThreadSync(() -> { |
| return mWebView.hasFocus(); |
| }); |
| } |
| |
| public boolean canZoomIn() { |
| return WebkitUtils.onMainThreadSync(() -> { |
| return mWebView.canZoomIn(); |
| }); |
| } |
| |
| public boolean canZoomOut() { |
| return WebkitUtils.onMainThreadSync(() -> { |
| return mWebView.canZoomOut(); |
| }); |
| } |
| |
| public boolean zoomIn() { |
| return WebkitUtils.onMainThreadSync(() -> { |
| return mWebView.zoomIn(); |
| }); |
| } |
| |
| public boolean zoomOut() { |
| return WebkitUtils.onMainThreadSync(() -> { |
| return mWebView.zoomOut(); |
| }); |
| } |
| |
| public void zoomBy(final float zoomFactor) { |
| WebkitUtils.onMainThreadSync(() -> { |
| mWebView.zoomBy(zoomFactor); |
| }); |
| } |
| |
| public void setFindListener(final WebView.FindListener listener) { |
| WebkitUtils.onMainThreadSync(() -> { |
| mWebView.setFindListener(listener); |
| }); |
| } |
| |
| public void removeJavascriptInterface(final String interfaceName) { |
| WebkitUtils.onMainThreadSync(() -> { |
| mWebView.removeJavascriptInterface(interfaceName); |
| }); |
| } |
| |
| public WebMessagePort[] createWebMessageChannel() { |
| return WebkitUtils.onMainThreadSync(() -> { |
| return mWebView.createWebMessageChannel(); |
| }); |
| } |
| |
| public void postWebMessage(final WebMessage message, final Uri targetOrigin) { |
| WebkitUtils.onMainThreadSync(() -> { |
| mWebView.postWebMessage(message, targetOrigin); |
| }); |
| } |
| |
| public void addJavascriptInterface(final Object object, final String name) { |
| WebkitUtils.onMainThreadSync(() -> { |
| mWebView.addJavascriptInterface(object, name); |
| }); |
| } |
| |
| public void flingScroll(final int vx, final int vy) { |
| WebkitUtils.onMainThreadSync(() -> { |
| mWebView.flingScroll(vx, vy); |
| }); |
| } |
| |
| public void requestFocusNodeHref(final Message hrefMsg) { |
| WebkitUtils.onMainThreadSync(() -> { |
| mWebView.requestFocusNodeHref(hrefMsg); |
| }); |
| } |
| |
| public void requestImageRef(final Message msg) { |
| WebkitUtils.onMainThreadSync(() -> { |
| mWebView.requestImageRef(msg); |
| }); |
| } |
| |
| public void setInitialScale(final int scaleInPercent) { |
| WebkitUtils.onMainThreadSync(() -> { |
| mWebView.setInitialScale(scaleInPercent); |
| }); |
| } |
| |
| public void clearSslPreferences() { |
| WebkitUtils.onMainThreadSync(() -> { |
| mWebView.clearSslPreferences(); |
| }); |
| } |
| |
| public void clearClientCertPreferences(final Runnable onCleared) { |
| WebkitUtils.onMainThreadSync(() -> { |
| WebView.clearClientCertPreferences(onCleared); |
| }); |
| } |
| |
| public void resumeTimers() { |
| WebkitUtils.onMainThreadSync(() -> { |
| mWebView.resumeTimers(); |
| }); |
| } |
| |
| public void findNext(final boolean forward) { |
| WebkitUtils.onMainThreadSync(() -> { |
| mWebView.findNext(forward); |
| }); |
| } |
| |
| public void clearMatches() { |
| WebkitUtils.onMainThreadSync(() -> { |
| mWebView.clearMatches(); |
| }); |
| } |
| |
| public void loadUrl(final String url) { |
| WebkitUtils.onMainThreadSync(() -> { |
| mWebView.loadUrl(url); |
| }); |
| } |
| |
| public void stopLoading() { |
| WebkitUtils.onMainThreadSync(() -> { |
| mWebView.stopLoading(); |
| }); |
| } |
| |
| /** |
| * Reload the previous URL. |
| */ |
| public void reload() { |
| WebkitUtils.onMainThreadSync(() -> { |
| mWebView.reload(); |
| }); |
| } |
| |
| public String getTitle() { |
| return WebkitUtils.onMainThreadSync(() -> { |
| return mWebView.getTitle(); |
| }); |
| } |
| |
| public WebSettings getSettings() { |
| return WebkitUtils.onMainThreadSync(() -> { |
| return mWebView.getSettings(); |
| }); |
| } |
| |
| public WebBackForwardList copyBackForwardList() { |
| return WebkitUtils.onMainThreadSync(() -> { |
| return mWebView.copyBackForwardList(); |
| }); |
| } |
| |
| public Bitmap getFavicon() { |
| return WebkitUtils.onMainThreadSync(() -> { |
| return mWebView.getFavicon(); |
| }); |
| } |
| |
| public String getUrl() { |
| return WebkitUtils.onMainThreadSync(() -> { |
| return mWebView.getUrl(); |
| }); |
| } |
| |
| public int getProgress() { |
| return WebkitUtils.onMainThreadSync(() -> { |
| return mWebView.getProgress(); |
| }); |
| } |
| |
| public int getHeight() { |
| return WebkitUtils.onMainThreadSync(() -> { |
| return mWebView.getHeight(); |
| }); |
| } |
| |
| public int getContentHeight() { |
| return WebkitUtils.onMainThreadSync(() -> { |
| return mWebView.getContentHeight(); |
| }); |
| } |
| |
| public boolean pageUp(final boolean top) { |
| return WebkitUtils.onMainThreadSync(() -> { |
| return mWebView.pageUp(top); |
| }); |
| } |
| |
| public boolean pageDown(final boolean bottom) { |
| return WebkitUtils.onMainThreadSync(() -> { |
| return mWebView.pageDown(bottom); |
| }); |
| } |
| |
| /** |
| * Post a visual state listener callback for mWebView on the UI thread. |
| */ |
| public void postVisualStateCallback(final long requestId, final VisualStateCallback callback) { |
| WebkitUtils.onMainThreadSync(() -> { |
| mWebView.postVisualStateCallback(requestId, callback); |
| }); |
| } |
| |
| public int[] getLocationOnScreen() { |
| final int[] location = new int[2]; |
| return WebkitUtils.onMainThreadSync(() -> { |
| mWebView.getLocationOnScreen(location); |
| return location; |
| }); |
| } |
| |
| public float getScale() { |
| return WebkitUtils.onMainThreadSync(() -> { |
| return mWebView.getScale(); |
| }); |
| } |
| |
| public boolean requestFocus(final int direction, |
| final Rect previouslyFocusedRect) { |
| return WebkitUtils.onMainThreadSync(() -> { |
| return mWebView.requestFocus(direction, previouslyFocusedRect); |
| }); |
| } |
| |
| public HitTestResult getHitTestResult() { |
| return WebkitUtils.onMainThreadSync(() -> { |
| return mWebView.getHitTestResult(); |
| }); |
| } |
| |
| public int getScrollX() { |
| return WebkitUtils.onMainThreadSync(() -> { |
| return mWebView.getScrollX(); |
| }); |
| } |
| |
| public int getScrollY() { |
| return WebkitUtils.onMainThreadSync(() -> { |
| return mWebView.getScrollY(); |
| }); |
| } |
| |
| public final DisplayMetrics getDisplayMetrics() { |
| return WebkitUtils.onMainThreadSync(() -> { |
| return mWebView.getContext().getResources().getDisplayMetrics(); |
| }); |
| } |
| |
| public boolean requestChildRectangleOnScreen(final View child, |
| final Rect rect, |
| final boolean immediate) { |
| return WebkitUtils.onMainThreadSync(() -> { |
| return mWebView.requestChildRectangleOnScreen(child, rect, |
| immediate); |
| }); |
| } |
| |
| public int findAll(final String find) { |
| return WebkitUtils.onMainThreadSync(() -> { |
| return mWebView.findAll(find); |
| }); |
| } |
| |
| public Picture capturePicture() { |
| return WebkitUtils.onMainThreadSync(() -> { |
| return mWebView.capturePicture(); |
| }); |
| } |
| |
| /** |
| * Execute javascript synchronously, returning the result. |
| */ |
| public String evaluateJavascriptSync(final String script) { |
| final SettableFuture<String> future = SettableFuture.create(); |
| evaluateJavascript(script, result -> future.set(result)); |
| return WebkitUtils.waitForFuture(future); |
| } |
| |
| public void evaluateJavascript(final String script, final ValueCallback<String> result) { |
| WebkitUtils.onMainThreadSync(() -> { |
| mWebView.evaluateJavascript(script, result); |
| }); |
| } |
| |
| public void saveWebArchive(final String basename, final boolean autoname, |
| final ValueCallback<String> callback) { |
| WebkitUtils.onMainThreadSync(() -> { |
| mWebView.saveWebArchive(basename, autoname, callback); |
| }); |
| } |
| |
| public SslCertificate getCertificate() { |
| return WebkitUtils.onMainThreadSync(() -> { |
| return mWebView.getCertificate(); |
| }); |
| } |
| |
| public WebView createWebView() { |
| return WebkitUtils.onMainThreadSync(() -> { |
| return new WebView(mWebView.getContext()); |
| }); |
| } |
| |
| public PrintDocumentAdapter createPrintDocumentAdapter() { |
| return WebkitUtils.onMainThreadSync(() -> { |
| return mWebView.createPrintDocumentAdapter(); |
| }); |
| } |
| |
| public void setLayoutHeightToMatchParent() { |
| WebkitUtils.onMainThreadSync(() -> { |
| ViewParent parent = mWebView.getParent(); |
| if (parent instanceof ViewGroup) { |
| ((ViewGroup) parent).getLayoutParams().height = |
| ViewGroup.LayoutParams.MATCH_PARENT; |
| } |
| mWebView.getLayoutParams().height = ViewGroup.LayoutParams.MATCH_PARENT; |
| mWebView.requestLayout(); |
| }); |
| } |
| |
| public void setLayoutToMatchParent() { |
| WebkitUtils.onMainThreadSync(() -> { |
| setMatchParent((View) mWebView.getParent()); |
| setMatchParent(mWebView); |
| mWebView.requestLayout(); |
| }); |
| } |
| |
| public void setAcceptThirdPartyCookies(final boolean accept) { |
| WebkitUtils.onMainThreadSync(() -> { |
| CookieManager.getInstance().setAcceptThirdPartyCookies(mWebView, accept); |
| }); |
| } |
| |
| public boolean acceptThirdPartyCookies() { |
| return WebkitUtils.onMainThreadSync(() -> { |
| return CookieManager.getInstance().acceptThirdPartyCookies(mWebView); |
| }); |
| } |
| |
| /** |
| * Accessor for underlying WebView. |
| * @return The WebView being wrapped by this class. |
| */ |
| public WebView getWebView() { |
| return mWebView; |
| } |
| |
| /** |
| * Wait for the current state of the DOM to be ready to render on the next draw. |
| */ |
| public void waitForDOMReadyToRender() { |
| final SettableFuture<Void> future = SettableFuture.create(); |
| postVisualStateCallback(0, new VisualStateCallback() { |
| @Override |
| public void onComplete(long requestId) { |
| future.set(null); |
| } |
| }); |
| WebkitUtils.waitForFuture(future); |
| } |
| |
| /** |
| * Capture a bitmap representation of the current WebView state. |
| * |
| * This synchronises so that the bitmap contents reflects the current DOM state, rather than |
| * potentially capturing a previously generated frame. |
| */ |
| public Bitmap captureBitmap() { |
| getSettings().setOffscreenPreRaster(true); |
| waitForDOMReadyToRender(); |
| return WebkitUtils.onMainThreadSync(() -> { |
| Bitmap bitmap = Bitmap.createBitmap(mWebView.getWidth(), mWebView.getHeight(), |
| Bitmap.Config.ARGB_8888); |
| Canvas canvas = new Canvas(bitmap); |
| mWebView.draw(canvas); |
| return bitmap; |
| }); |
| } |
| |
| /** |
| * Set LayoutParams to MATCH_PARENT. |
| * |
| * @param view Target view |
| */ |
| private void setMatchParent(View view) { |
| ViewGroup.LayoutParams params = view.getLayoutParams(); |
| params.height = ViewGroup.LayoutParams.MATCH_PARENT; |
| params.width = ViewGroup.LayoutParams.MATCH_PARENT; |
| view.setLayoutParams(params); |
| } |
| } |