FileDocCategorySizeDatePackage
WebViewChromium.javaAPI DocAndroid 5.1 API74551Thu Mar 12 22:22:56 GMT 2015com.android.webview.chromium

WebViewChromium

public class WebViewChromium extends Object implements android.webkit.WebViewProvider, org.chromium.content.browser.SmartClipProvider, WebViewProvider.ScrollDelegate, WebViewProvider.ViewDelegate
This class is the delegate to which WebViewProxy forwards all API calls. Most of the actual functionality is implemented by AwContents (or ContentViewCore within it). This class also contains WebView-specific APIs that require the creation of other adapters (otherwise org.chromium.content would depend on the webview.chromium package) and a small set of no-op deprecated APIs.

Fields Summary
private WebViewChromiumRunQueue
mRunQueue
private static final String
TAG
android.webkit.WebView
mWebView
WebView.PrivateAccess
mWebViewPrivate
private WebViewContentsClientAdapter
mContentsClientAdapter
private ContentSettingsAdapter
mWebSettings
private org.chromium.android_webview.AwContents
mAwContents
private DrawGLFunctor
mGLfunctor
private final WebView.HitTestResult
mHitTestResult
private final int
mAppTargetSdkVersion
private WebViewChromiumFactoryProvider
mFactory
private static boolean
sRecordWholeDocumentEnabledByApi
Constructors Summary
public WebViewChromium(WebViewChromiumFactoryProvider factory, android.webkit.WebView webView, WebView.PrivateAccess webViewPrivate)

        mWebView = webView;
        mWebViewPrivate = webViewPrivate;
        mHitTestResult = new WebView.HitTestResult();
        mAppTargetSdkVersion = mWebView.getContext().getApplicationInfo().targetSdkVersion;
        mFactory = factory;
        mRunQueue = new WebViewChromiumRunQueue();
        factory.getWebViewDelegate().addWebViewAssetPath(mWebView.getContext());
    
Methods Summary
public voidaddJavascriptInterface(java.lang.Object obj, java.lang.String interfaceName)

        if (checkNeedsPost()) {
            mRunQueue.addTask(new Runnable() {
                @Override
                public void run() {
                    addJavascriptInterface(obj, interfaceName);
                }
            });
            return;
        }
        Class<? extends Annotation> requiredAnnotation = null;
        if (mAppTargetSdkVersion >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
           requiredAnnotation = JavascriptInterface.class;
        }
        mAwContents.addPossiblyUnsafeJavascriptInterface(obj, interfaceName, requiredAnnotation);
    
public booleancanGoBack()

        mFactory.startYourEngines(true);
        if (checkNeedsPost()) {
            Boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() {
                @Override
                public Boolean call() {
                    return canGoBack();
                }
            });
            return ret;
        }
        return mAwContents.canGoBack();
    
public booleancanGoBackOrForward(int steps)

        mFactory.startYourEngines(true);
        if (checkNeedsPost()) {
            Boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() {
                @Override
                public Boolean call() {
                    return canGoBackOrForward(steps);
                }
            });
            return ret;
        }
        return mAwContents.canGoBackOrForward(steps);
    
public booleancanGoForward()

        mFactory.startYourEngines(true);
        if (checkNeedsPost()) {
            Boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() {
                @Override
                public Boolean call() {
                    return canGoForward();
                }
            });
            return ret;
        }
        return mAwContents.canGoForward();
    
public booleancanZoomIn()

        if (checkNeedsPost()) {
            return false;
        }
        return mAwContents.canZoomIn();
    
public booleancanZoomOut()

        if (checkNeedsPost()) {
            return false;
        }
        return mAwContents.canZoomOut();
    
public android.graphics.PicturecapturePicture()

        mFactory.startYourEngines(true);
        if (checkNeedsPost()) {
            Picture ret = runOnUiThreadBlocking(new Callable<Picture>() {
                @Override
                public Picture call() {
                    return capturePicture();
                }
            });
            return ret;
        }
        return mAwContents.capturePicture();
    
private booleancheckNeedsPost()

        boolean needsPost = !mFactory.hasStarted() || !ThreadUtils.runningOnUiThread();
        if (!needsPost && mAwContents == null) {
            throw new IllegalStateException(
                    "AwContents must be created if we are not posting!");
        }
        return needsPost;
    
private voidcheckThread()

        if (!ThreadUtils.runningOnUiThread()) {
            final RuntimeException threadViolation = createThreadException();
            ThreadUtils.postOnUiThread(new Runnable() {
                @Override
                public void run() {
                    throw threadViolation;
                }
            });
            throw createThreadException();
        }
    
public voidclearCache(boolean includeDiskFiles)

        if (checkNeedsPost()) {
            mRunQueue.addTask(new Runnable() {
                @Override
                public void run() {
                    clearCache(includeDiskFiles);
                }
            });
            return;
        }
        mAwContents.clearCache(includeDiskFiles);
    
public voidclearFormData()
This is a poorly named method, but we keep it for historical reasons.

        if (checkNeedsPost()) {
            mRunQueue.addTask(new Runnable() {
                @Override
                public void run() {
                    clearFormData();
                }
            });
            return;
        }
        mAwContents.hideAutofillPopup();
    
public voidclearHistory()

        if (checkNeedsPost()) {
            mRunQueue.addTask(new Runnable() {
                @Override
                public void run() {
                    clearHistory();
                }
            });
            return;
        }
        mAwContents.clearHistory();
    
public voidclearMatches()

        if (checkNeedsPost()) {
            mRunQueue.addTask(new Runnable() {
                @Override
                public void run() {
                    clearMatches();
                }
            });
            return;
        }
        mAwContents.clearMatches();
    
public voidclearSslPreferences()

        if (checkNeedsPost()) {
            mRunQueue.addTask(new Runnable() {
                @Override
                public void run() {
                    clearSslPreferences();
                }
            });
            return;
        }
        mAwContents.clearSslPreferences();
    
public voidclearView()

        if (checkNeedsPost()) {
            mRunQueue.addTask(new Runnable() {
                @Override
                public void run() {
                    clearView();
                }
            });
            return;
        }
        mAwContents.clearView();
    
static voidcompleteWindowCreation(android.webkit.WebView parent, android.webkit.WebView child)

        AwContents parentContents = ((WebViewChromium) parent.getWebViewProvider()).mAwContents;
        AwContents childContents =
                child == null ? null : ((WebViewChromium) child.getWebViewProvider()).mAwContents;
        parentContents.supplyContentsForPopup(childContents);
    
public intcomputeHorizontalScrollOffset()

        mFactory.startYourEngines(false);
        if (checkNeedsPost()) {
            int ret = runOnUiThreadBlocking(new Callable<Integer>() {
                @Override
                public Integer call() {
                    return computeHorizontalScrollOffset();
                }
            });
            return ret;
        }
        return mAwContents.computeHorizontalScrollOffset();
    
public intcomputeHorizontalScrollRange()

        mFactory.startYourEngines(false);
        if (checkNeedsPost()) {
            int ret = runOnUiThreadBlocking(new Callable<Integer>() {
                @Override
                public Integer call() {
                    return computeHorizontalScrollRange();
                }
            });
            return ret;
        }
        return mAwContents.computeHorizontalScrollRange();
    
public voidcomputeScroll()

        mFactory.startYourEngines(false);
        if (checkNeedsPost()) {
            runVoidTaskOnUiThreadBlocking(new Runnable() {
                @Override
                public void run() {
                    computeScroll();
                }
            });
            return;
        }
        mAwContents.computeScroll();
    
public intcomputeVerticalScrollExtent()

        mFactory.startYourEngines(false);
        if (checkNeedsPost()) {
            int ret = runOnUiThreadBlocking(new Callable<Integer>() {
                @Override
                public Integer call() {
                    return computeVerticalScrollExtent();
                }
            });
            return ret;
        }
        return mAwContents.computeVerticalScrollExtent();
    
public intcomputeVerticalScrollOffset()

        mFactory.startYourEngines(false);
        if (checkNeedsPost()) {
            int ret = runOnUiThreadBlocking(new Callable<Integer>() {
                @Override
                public Integer call() {
                    return computeVerticalScrollOffset();
                }
            });
            return ret;
        }
        return mAwContents.computeVerticalScrollOffset();
    
public intcomputeVerticalScrollRange()

        mFactory.startYourEngines(false);
        if (checkNeedsPost()) {
            int ret = runOnUiThreadBlocking(new Callable<Integer>() {
                @Override
                public Integer call() {
                    return computeVerticalScrollRange();
                }
            });
            return ret;
        }
        return mAwContents.computeVerticalScrollRange();
    
public android.webkit.WebBackForwardListcopyBackForwardList()

        mFactory.startYourEngines(true);
        if (checkNeedsPost()) {
            WebBackForwardList ret = runOnUiThreadBlocking(new Callable<WebBackForwardList>() {
                @Override
                public WebBackForwardList call() {
                    return copyBackForwardList();
                }
            });
            return ret;
        }
        return new WebBackForwardListChromium(
                mAwContents.getNavigationHistory());
    
public android.print.PrintDocumentAdaptercreatePrintDocumentAdapter()

         return createPrintDocumentAdapter("default");
    
public android.print.PrintDocumentAdaptercreatePrintDocumentAdapter(java.lang.String documentName)

        checkThread();
        return new AwPrintDocumentAdapter(mAwContents.getPdfExporter(), documentName);
    
private java.lang.RuntimeExceptioncreateThreadException()

        return new IllegalStateException(
                "Calling View methods on another thread than the UI thread.");
    
public voiddestroy()

        if (checkNeedsPost()) {
            mRunQueue.addTask(new Runnable() {
                @Override
                public void run() {
                    destroy();
                }
            });
            return;
        }

        mAwContents.destroy();
        if (mGLfunctor != null) {
            mGLfunctor.destroy();
            mGLfunctor = null;
        }
    
public booleandispatchKeyEvent(android.view.KeyEvent event)

        mFactory.startYourEngines(false);
        if (checkNeedsPost()) {
            boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() {
                @Override
                public Boolean call() {
                    return dispatchKeyEvent(event);
                }
            });
            return ret;
        }
        return mAwContents.dispatchKeyEvent(event);
    
public voiddocumentHasImages(android.os.Message response)

        if (checkNeedsPost()) {
            mRunQueue.addTask(new Runnable() {
                @Override
                public void run() {
                    documentHasImages(response);
                }
            });
            return;
        }
        mAwContents.documentHasImages(response);
    
private booleandoesSupportFullscreen(android.webkit.WebChromeClient client)
Returns true if the supplied {@link WebChromeClient} supports fullscreen.

For fullscreen support, implementations of {@link WebChromeClient#onShowCustomView} and {@link WebChromeClient#onHideCustomView()} are required.

        if (client == null) {
            return false;
        }
        Class<?> clientClass = client.getClass();
        boolean foundShowMethod = false;
        boolean foundHideMethod = false;
        while (clientClass != WebChromeClient.class && (!foundShowMethod || !foundHideMethod)) {
            if (!foundShowMethod) {
                try {
                    clientClass.getDeclaredMethod("onShowCustomView", View.class,
                            CustomViewCallback.class);
                    foundShowMethod = true;
                } catch (NoSuchMethodException e) { }
            }

            if (!foundHideMethod) {
                try {
                    clientClass.getDeclaredMethod("onHideCustomView");
                    foundHideMethod = true;
                } catch (NoSuchMethodException e) { }
            }
            clientClass = clientClass.getSuperclass();
        }
        return foundShowMethod && foundHideMethod;
    
public voiddumpViewHierarchyWithProperties(java.io.BufferedWriter out, int level)

        // Intentional no-op
    
static voidenableSlowWholeDocumentDraw()

       
        sRecordWholeDocumentEnabledByApi = true;
    
public voidevaluateJavaScript(java.lang.String script, android.webkit.ValueCallback resultCallback)

        checkThread();
        mAwContents.evaluateJavaScript(script, resultCallback);
    
public voidextractSmartClipData(int x, int y, int width, int height)

        checkThread();
        mAwContents.extractSmartClipData(x, y, width, height);
    
public intfindAll(java.lang.String searchString)

        findAllAsync(searchString);
        return 0;
    
public voidfindAllAsync(java.lang.String searchString)

        if (checkNeedsPost()) {
            mRunQueue.addTask(new Runnable() {
                @Override
                public void run() {
                    findAllAsync(searchString);
                }
            });
            return;
        }
        mAwContents.findAllAsync(searchString);
    
public android.view.ViewfindHierarchyView(java.lang.String className, int hashCode)

        // Intentional no-op
        return null;
    
public voidfindNext(boolean forwards)

        if (checkNeedsPost()) {
            mRunQueue.addTask(new Runnable() {
                @Override
                public void run() {
                    findNext(forwards);
                }
            });
            return;
        }
        mAwContents.findNext(forwards);
    
private static java.lang.StringfixupBase(java.lang.String url)

        return TextUtils.isEmpty(url) ? "about:blank" : url;
    
private static java.lang.StringfixupData(java.lang.String data)

        return TextUtils.isEmpty(data) ? "" : data;
    
private static java.lang.StringfixupHistory(java.lang.String url)

        return TextUtils.isEmpty(url) ? "about:blank" : url;
    
private static java.lang.StringfixupMimeType(java.lang.String mimeType)

        return TextUtils.isEmpty(mimeType) ? "text/html" : mimeType;
    
public voidflingScroll(int vx, int vy)

        if (checkNeedsPost()) {
            mRunQueue.addTask(new Runnable() {
                @Override
                public void run() {
                    flingScroll(vx, vy);
                }
            });
            return;
        }
        mAwContents.flingScroll(vx, vy);
    
public voidfreeMemory()

        // Intentional no-op. Memory is managed automatically by Chromium.
    
public android.view.accessibility.AccessibilityNodeProvidergetAccessibilityNodeProvider()

        mFactory.startYourEngines(false);
        if (checkNeedsPost()) {
            AccessibilityNodeProvider ret = runOnUiThreadBlocking(
                    new Callable<AccessibilityNodeProvider>() {
                @Override
                public AccessibilityNodeProvider call() {
                    return getAccessibilityNodeProvider();
                }
            });
            return ret;
        }
        return mAwContents.getAccessibilityNodeProvider();
    
public android.net.http.SslCertificategetCertificate()

        mFactory.startYourEngines(true);
        if (checkNeedsPost()) {
            SslCertificate ret = runOnUiThreadBlocking(new Callable<SslCertificate>() {
                @Override
                public SslCertificate call() {
                    return getCertificate();
                }
            });
            return ret;
        }
        return mAwContents.getCertificate();
    
public intgetContentHeight()

        if (mAwContents == null) return 0;
        // No checkThread() as it is mostly thread safe (workaround for b/10594869).
        return mAwContents.getContentHeightCss();
    
public intgetContentWidth()

        if (mAwContents == null) return 0;
        // No checkThread() as it is mostly thread safe (workaround for b/10594869).
        return mAwContents.getContentWidthCss();
    
public android.graphics.BitmapgetFavicon()

        mFactory.startYourEngines(true);
        if (checkNeedsPost()) {
            Bitmap ret = runOnUiThreadBlocking(new Callable<Bitmap>() {
                @Override
                public Bitmap call() {
                    return getFavicon();
                }
            });
            return ret;
        }
        return mAwContents.getFavicon();
    
public WebView.HitTestResultgetHitTestResult()

        mFactory.startYourEngines(true);
        if (checkNeedsPost()) {
            WebView.HitTestResult ret = runOnUiThreadBlocking(
                    new Callable<WebView.HitTestResult>() {
                @Override
                public WebView.HitTestResult call() {
                    return getHitTestResult();
                }
            });
            return ret;
        }
        AwContents.HitTestData data = mAwContents.getLastHitTestResult();
        mHitTestResult.setType(data.hitTestResultType);
        mHitTestResult.setExtra(data.hitTestResultExtraData);
        return mHitTestResult;
    
public java.lang.String[]getHttpAuthUsernamePassword(java.lang.String host, java.lang.String realm)

        mFactory.startYourEngines(true);
        if (checkNeedsPost()) {
            String[] ret = runOnUiThreadBlocking(new Callable<String[]>() {
                @Override
                public String[] call() {
                    return getHttpAuthUsernamePassword(host, realm);
                }
            });
            return ret;
        }
        return mAwContents.getHttpAuthUsernamePassword(host, realm);
    
public java.lang.StringgetOriginalUrl()

        mFactory.startYourEngines(true);
        if (checkNeedsPost()) {
            String ret = runOnUiThreadBlocking(new Callable<String>() {
                @Override
                public String call() {
                    return getOriginalUrl();
                }
            });
            return ret;
        }
        String url =  mAwContents.getOriginalUrl();
        if (url == null || url.trim().isEmpty()) return null;
        return url;
    
public intgetProgress()

        if (mAwContents == null) return 100;
        // No checkThread() because the value is cached java side (workaround for b/10533304).
        return mAwContents.getMostRecentProgress();
    
public floatgetScale()

        // No checkThread() as it is mostly thread safe (workaround for b/10652991).
        mFactory.startYourEngines(true);
        return mAwContents.getScale();
    
public WebViewProvider.ScrollDelegategetScrollDelegate()

        return this;
    
public android.webkit.WebSettingsgetSettings()

        return mWebSettings;
    
public java.lang.StringgetTitle()

        mFactory.startYourEngines(true);
        if (checkNeedsPost()) {
            String ret = runOnUiThreadBlocking(new Callable<String>() {
                @Override
                public String call() {
                    return getTitle();
                }
            });
            return ret;
        }
        return mAwContents.getTitle();
    
public java.lang.StringgetTouchIconUrl()

        // Intentional no-op: hidden method on WebView.
        return null;
    
public java.lang.StringgetUrl()

        mFactory.startYourEngines(true);
        if (checkNeedsPost()) {
            String ret = runOnUiThreadBlocking(new Callable<String>() {
                @Override
                public String call() {
                    return getUrl();
                }
            });
            return ret;
        }
        String url =  mAwContents.getUrl();
        if (url == null || url.trim().isEmpty()) return null;
        return url;
    
public WebViewProvider.ViewDelegategetViewDelegate()

        return this;
    
public intgetVisibleTitleHeight()

        // This is deprecated in WebView and should always return 0.
        return 0;
    
public android.view.ViewgetZoomControls()

        mFactory.startYourEngines(false);
        if (checkNeedsPost()) {
            return null;
        }

        // This was deprecated in 2009 and hidden in JB MR1, so just provide the minimum needed
        // to stop very out-dated applications from crashing.
        Log.w(TAG, "WebView doesn't support getZoomControls");
        return mAwContents.getSettings().supportZoom() ? new View(mWebView.getContext()) : null;
    
public voidgoBack()

        if (checkNeedsPost()) {
            mRunQueue.addTask(new Runnable() {
                @Override
                public void run() {
                    goBack();
                }
            });
            return;
        }
        mAwContents.goBack();
    
public voidgoBackOrForward(int steps)

        if (checkNeedsPost()) {
            mRunQueue.addTask(new Runnable() {
                @Override
                public void run() {
                    goBackOrForward(steps);
                }
            });
            return;
        }
        mAwContents.goBackOrForward(steps);
    
public voidgoForward()

        if (checkNeedsPost()) {
            mRunQueue.addTask(new Runnable() {
                @Override
                public void run() {
                    goForward();
                }
            });
            return;
        }
        mAwContents.goForward();
    
public voidinit(java.util.Map javaScriptInterfaces, boolean privateBrowsing)

        if (privateBrowsing) {
            mFactory.startYourEngines(true);
            final String msg = "Private browsing is not supported in WebView.";
            if (mAppTargetSdkVersion >= Build.VERSION_CODES.KITKAT) {
                throw new IllegalArgumentException(msg);
            } else {
                Log.w(TAG, msg);
                TextView warningLabel = new TextView(mWebView.getContext());
                warningLabel.setText(mWebView.getContext().getString(
                        R.string.webviewchromium_private_browsing_warning));
                mWebView.addView(warningLabel);
            }
        }

        // We will defer real initialization until we know which thread to do it on, unless:
        // - we are on the main thread already (common case),
        // - the app is targeting >= JB MR2, in which case checkThread enforces that all usage
        //   comes from a single thread. (Note in JB MR2 this exception was in WebView.java).
        if (mAppTargetSdkVersion >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
            mFactory.startYourEngines(false);
            checkThread();
        } else if (!mFactory.hasStarted()) {
            if (Looper.myLooper() == Looper.getMainLooper()) {
                mFactory.startYourEngines(true);
            }
        }

        final boolean isAccessFromFileURLsGrantedByDefault =
                mAppTargetSdkVersion < Build.VERSION_CODES.JELLY_BEAN;
        final boolean areLegacyQuirksEnabled =
                mAppTargetSdkVersion < Build.VERSION_CODES.KITKAT;

        mContentsClientAdapter = new WebViewContentsClientAdapter(
                mWebView, mFactory.getWebViewDelegate());
        mWebSettings = new ContentSettingsAdapter(new AwSettings(
                mWebView.getContext(), isAccessFromFileURLsGrantedByDefault,
                areLegacyQuirksEnabled));

        if (mAppTargetSdkVersion < Build.VERSION_CODES.LOLLIPOP) {
            // Prior to Lollipop we always allowed third party cookies and mixed content.
            mWebSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
            mWebSettings.setAcceptThirdPartyCookies(true);
            mWebSettings.getAwSettings().setZeroLayoutHeightDisablesViewportQuirk(true);
        }

        mRunQueue.addTask(new Runnable() {
                @Override
                public void run() {
                    initForReal();
                    if (privateBrowsing) {
                        // Intentionally irreversibly disable the webview instance, so that private
                        // user data cannot leak through misuse of a non-privateBrowing WebView
                        // instance. Can't just null out mAwContents as we never null-check it
                        // before use.
                        destroy();
                    }
                }
        });
    
private voidinitForReal()

        Context ctx = resourcesContextWrapper(mWebView.getContext());
        mAwContents = new AwContents(mFactory.getBrowserContext(), mWebView, ctx,
                new InternalAccessAdapter(), new WebViewNativeGLDelegate(),
                mContentsClientAdapter, mWebSettings.getAwSettings());

        if (mAppTargetSdkVersion >= Build.VERSION_CODES.KITKAT) {
            // On KK and above, favicons are automatically downloaded as the method
            // old apps use to enable that behavior is deprecated.
            AwContents.setShouldDownloadFavicons();
        }

        AwContentsStatics.setRecordFullDocument(sRecordWholeDocumentEnabledByApi ||
                mAppTargetSdkVersion < Build.VERSION_CODES.LOLLIPOP);

        if (mAppTargetSdkVersion < Build.VERSION_CODES.LOLLIPOP) {
            // Prior to Lollipop, JavaScript objects injected via addJavascriptInterface
            // were not inspectable.
            mAwContents.disableJavascriptInterfacesInspection();
        }

        // TODO: This assumes AwContents ignores second Paint param.
        mAwContents.setLayerType(mWebView.getLayerType(), null);
    
public voidinvokeZoomPicker()

        if (checkNeedsPost()) {
            mRunQueue.addTask(new Runnable() {
                @Override
                public void run() {
                    invokeZoomPicker();
                }
            });
            return;
        }
        mAwContents.invokeZoomPicker();
    
private static booleanisBase64Encoded(java.lang.String encoding)

        return "base64".equals(encoding);
    
public booleanisPaused()

        mFactory.startYourEngines(true);
        if (checkNeedsPost()) {
            Boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() {
                @Override
                public Boolean call() {
                    return isPaused();
                }
            });
            return ret;
        }
        return mAwContents.isPaused();
    
public booleanisPrivateBrowsingEnabled()

        // Not supported in this WebView implementation.
        return false;
    
public voidloadData(java.lang.String data, java.lang.String mimeType, java.lang.String encoding)

        loadUrlOnUiThread(LoadUrlParams.createLoadDataParams(
                fixupData(data), fixupMimeType(mimeType), isBase64Encoded(encoding)));
    
public voidloadDataWithBaseURL(java.lang.String baseUrl, java.lang.String data, java.lang.String mimeType, java.lang.String encoding, java.lang.String historyUrl)

        data = fixupData(data);
        mimeType = fixupMimeType(mimeType);
        LoadUrlParams loadUrlParams;
        baseUrl = fixupBase(baseUrl);
        historyUrl = fixupHistory(historyUrl);

        if (baseUrl.startsWith("data:")) {
            // For backwards compatibility with WebViewClassic, we use the value of |encoding|
            // as the charset, as long as it's not "base64".
            boolean isBase64 = isBase64Encoded(encoding);
            loadUrlParams = LoadUrlParams.createLoadDataParamsWithBaseUrl(
                    data, mimeType, isBase64, baseUrl, historyUrl, isBase64 ? null : encoding);
        } else {
            // When loading data with a non-data: base URL, the classic WebView would effectively
            // "dump" that string of data into the WebView without going through regular URL
            // loading steps such as decoding URL-encoded entities. We achieve this same behavior by
            // base64 encoding the data that is passed here and then loading that as a data: URL.
            try {
                loadUrlParams = LoadUrlParams.createLoadDataParamsWithBaseUrl(
                        Base64.encodeToString(data.getBytes("utf-8"), Base64.DEFAULT), mimeType,
                        true, baseUrl, historyUrl, "utf-8");
            } catch (java.io.UnsupportedEncodingException e) {
                Log.wtf(TAG, "Unable to load data string " + data, e);
                return;
            }
        }
        loadUrlOnUiThread(loadUrlParams);
    
public voidloadUrl(java.lang.String url, java.util.Map additionalHttpHeaders)

        // TODO: We may actually want to do some sanity checks here (like filter about://chrome).

        // For backwards compatibility, apps targeting less than K will have JS URLs evaluated
        // directly and any result of the evaluation will not replace the current page content.
        // Matching Chrome behavior more closely; apps targetting >= K that load a JS URL will
        // have the result of that URL replace the content of the current page.
        final String JAVASCRIPT_SCHEME = "javascript:";
        if (mAppTargetSdkVersion < Build.VERSION_CODES.KITKAT &&
                url != null && url.startsWith(JAVASCRIPT_SCHEME)) {
            mFactory.startYourEngines(true);
            if (checkNeedsPost()) {
                mRunQueue.addTask(new Runnable() {
                    @Override
                    public void run() {
                        mAwContents.evaluateJavaScriptEvenIfNotYetNavigated(
                                url.substring(JAVASCRIPT_SCHEME.length()));
                    }
                });
            } else {
                mAwContents.evaluateJavaScriptEvenIfNotYetNavigated(
                        url.substring(JAVASCRIPT_SCHEME.length()));
            }
            return;
        }

        LoadUrlParams params = new LoadUrlParams(url);
        if (additionalHttpHeaders != null) params.setExtraHeaders(additionalHttpHeaders);
        loadUrlOnUiThread(params);
    
public voidloadUrl(java.lang.String url)

        // Early out to match old WebView implementation
        if (url == null) {
            return;
        }
        loadUrl(url, null);
    
private voidloadUrlOnUiThread(org.chromium.content_public.browser.LoadUrlParams loadUrlParams)

        // This is the last point that we can delay starting the Chromium backend up
        // and if the app has not caused us to bind the Chromium UI thread to a background thread
        // we now bind Chromium's notion of the UI thread to the app main thread.
        mFactory.startYourEngines(true);
        if (checkNeedsPost()) {
            // Disallowed in WebView API for apps targetting a new SDK
            assert mAppTargetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2;
            mRunQueue.addTask(new Runnable() {
                @Override
                public void run() {
                    mAwContents.loadUrl(loadUrlParams);
                }
            });
            return;
        }
        mAwContents.loadUrl(loadUrlParams);
    
public voidnotifyFindDialogDismissed()

        if (checkNeedsPost()) {
            mRunQueue.addTask(new Runnable() {
                @Override
                public void run() {
                    notifyFindDialogDismissed();
                }
            });
            return;
        }
        clearMatches();
    
public voidonAttachedToWindow()

        // This API is our strongest signal from the View system that this
        // WebView is going to be bound to a View hierarchy and so at this
        // point we must bind Chromium's UI thread to the current thread.
        mFactory.startYourEngines(false);
        checkThread();
        mAwContents.onAttachedToWindow();
    
public voidonConfigurationChanged(android.content.res.Configuration newConfig)

        if (checkNeedsPost()) {
            mRunQueue.addTask(new Runnable() {
                @Override
                public void run() {
                    onConfigurationChanged(newConfig);
                }
            });
            return;
        }
        mAwContents.onConfigurationChanged(newConfig);
    
public android.view.inputmethod.InputConnectiononCreateInputConnection(android.view.inputmethod.EditorInfo outAttrs)

        mFactory.startYourEngines(false);
        if (checkNeedsPost()) {
           return null;
        }
        return mAwContents.onCreateInputConnection(outAttrs);
    
public voidonDetachedFromWindow()

        if (checkNeedsPost()) {
            mRunQueue.addTask(new Runnable() {
                @Override
                public void run() {
                    onDetachedFromWindow();
                }
            });
            return;
        }

        mAwContents.onDetachedFromWindow();
    
public voidonDraw(android.graphics.Canvas canvas)

        mFactory.startYourEngines(true);
        if (checkNeedsPost()) {
            runVoidTaskOnUiThreadBlocking(new Runnable() {
                @Override
                public void run() {
                    onDraw(canvas);
                }
            });
            return;
        }
        mAwContents.onDraw(canvas);
    
public voidonDrawVerticalScrollBar(android.graphics.Canvas canvas, android.graphics.drawable.Drawable scrollBar, int l, int t, int r, int b)

        // WebViewClassic was overriding this method to handle rubberband over-scroll. Since
        // WebViewChromium doesn't support that the vanilla implementation of this method can be
        // used.
        mWebViewPrivate.super_onDrawVerticalScrollBar(canvas, scrollBar, l, t, r, b);
    
public voidonFinishTemporaryDetach()

        mAwContents.onFinishTemporaryDetach();
    
public voidonFocusChanged(boolean focused, int direction, android.graphics.Rect previouslyFocusedRect)

        if (checkNeedsPost()) {
            mRunQueue.addTask(new Runnable() {
                @Override
                public void run() {
                    onFocusChanged(focused, direction, previouslyFocusedRect);
                }
            });
            return;
        }
        mAwContents.onFocusChanged(focused, direction, previouslyFocusedRect);
    
public booleanonGenericMotionEvent(android.view.MotionEvent event)

        mFactory.startYourEngines(false);
        if (checkNeedsPost()) {
            boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() {
                @Override
                public Boolean call() {
                    return onGenericMotionEvent(event);
                }
            });
            return ret;
        }
        return mAwContents.onGenericMotionEvent(event);
    
public booleanonHoverEvent(android.view.MotionEvent event)

        mFactory.startYourEngines(false);
        if (checkNeedsPost()) {
            boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() {
                @Override
                public Boolean call() {
                    return onHoverEvent(event);
                }
            });
            return ret;
        }
        return mAwContents.onHoverEvent(event);
    
public voidonInitializeAccessibilityEvent(android.view.accessibility.AccessibilityEvent event)

        mFactory.startYourEngines(false);
        if (checkNeedsPost()) {
            runVoidTaskOnUiThreadBlocking(new Runnable() {
                @Override
                public void run() {
                    onInitializeAccessibilityEvent(event);
                }
            });
            return;
        }
        mAwContents.onInitializeAccessibilityEvent(event);
    
public voidonInitializeAccessibilityNodeInfo(android.view.accessibility.AccessibilityNodeInfo info)

        mFactory.startYourEngines(false);
        if (checkNeedsPost()) {
            runVoidTaskOnUiThreadBlocking(new Runnable() {
                @Override
                public void run() {
                    onInitializeAccessibilityNodeInfo(info);
                }
            });
            return;
        }
        mAwContents.onInitializeAccessibilityNodeInfo(info);
    
public booleanonKeyDown(int keyCode, android.view.KeyEvent event)

        mFactory.startYourEngines(false);
        if (checkNeedsPost()) {
            boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() {
                @Override
                public Boolean call() {
                    return onKeyDown(keyCode, event);
                }
            });
            return ret;
        }
        UnimplementedWebViewApi.invoke();
        return false;
    
public booleanonKeyMultiple(int keyCode, int repeatCount, android.view.KeyEvent event)

        mFactory.startYourEngines(false);
        if (checkNeedsPost()) {
            boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() {
                @Override
                public Boolean call() {
                    return onKeyMultiple(keyCode, repeatCount, event);
                }
            });
            return ret;
        }
        UnimplementedWebViewApi.invoke();
        return false;
    
public booleanonKeyUp(int keyCode, android.view.KeyEvent event)

        mFactory.startYourEngines(false);
        if (checkNeedsPost()) {
            boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() {
                @Override
                public Boolean call() {
                    return onKeyUp(keyCode, event);
                }
            });
            return ret;
        }
        return mAwContents.onKeyUp(keyCode, event);
    
public voidonMeasure(int widthMeasureSpec, int heightMeasureSpec)

        mFactory.startYourEngines(false);
        if (checkNeedsPost()) {
            runVoidTaskOnUiThreadBlocking(new Runnable() {
                @Override
                public void run() {
                    onMeasure(widthMeasureSpec, heightMeasureSpec);
                }
            });
            return;
        }
        mAwContents.onMeasure(widthMeasureSpec, heightMeasureSpec);
    
public voidonOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY)

        if (checkNeedsPost()) {
            mRunQueue.addTask(new Runnable() {
                @Override
                public void run() {
                    onOverScrolled(scrollX, scrollY, clampedX, clampedY);
                }
            });
            return;
        }
        mAwContents.onContainerViewOverScrolled(scrollX, scrollY, clampedX, clampedY);
    
public voidonPause()

        if (checkNeedsPost()) {
            mRunQueue.addTask(new Runnable() {
                @Override
                public void run() {
                    onPause();
                }
            });
            return;
        }
        mAwContents.onPause();
    
public voidonResume()

        if (checkNeedsPost()) {
            mRunQueue.addTask(new Runnable() {
                @Override
                public void run() {
                    onResume();
                }
            });
            return;
        }
        mAwContents.onResume();
    
public voidonScrollChanged(int l, int t, int oldl, int oldt)

    
public voidonSizeChanged(int w, int h, int ow, int oh)

        if (checkNeedsPost()) {
            mRunQueue.addTask(new Runnable() {
                @Override
                public void run() {
                    onSizeChanged(w, h, ow, oh);
                }
            });
            return;
        }
        mAwContents.onSizeChanged(w, h, ow, oh);
    
public voidonStartTemporaryDetach()

        mAwContents.onStartTemporaryDetach();
    
public booleanonTouchEvent(android.view.MotionEvent ev)

        mFactory.startYourEngines(false);
        if (checkNeedsPost()) {
            boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() {
                @Override
                public Boolean call() {
                    return onTouchEvent(ev);
                }
            });
            return ret;
        }
        return mAwContents.onTouchEvent(ev);
    
public booleanonTrackballEvent(android.view.MotionEvent ev)

        // Trackball event not handled, which eventually gets converted to DPAD keyevents
        return false;
    
public voidonVisibilityChanged(android.view.View changedView, int visibility)

        // The AwContents will find out the container view visibility before the first draw so we
        // can safely ignore onVisibilityChanged callbacks that happen before init().
        if (mAwContents == null) return;

        if (checkNeedsPost()) {
            mRunQueue.addTask(new Runnable() {
                @Override
                public void run() {
                    onVisibilityChanged(changedView, visibility);
                }
            });
            return;
        }
        mAwContents.onVisibilityChanged(changedView, visibility);
    
public voidonWindowFocusChanged(boolean hasWindowFocus)

        if (checkNeedsPost()) {
            mRunQueue.addTask(new Runnable() {
                @Override
                public void run() {
                    onWindowFocusChanged(hasWindowFocus);
                }
            });
            return;
        }
        mAwContents.onWindowFocusChanged(hasWindowFocus);
    
public voidonWindowVisibilityChanged(int visibility)

        if (checkNeedsPost()) {
            mRunQueue.addTask(new Runnable() {
                @Override
                public void run() {
                    onWindowVisibilityChanged(visibility);
                }
            });
            return;
        }
        mAwContents.onWindowVisibilityChanged(visibility);
    
public booleanoverlayHorizontalScrollbar()

        mFactory.startYourEngines(false);
        if (checkNeedsPost()) {
            boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() {
                @Override
                public Boolean call() {
                    return overlayHorizontalScrollbar();
                }
            });
            return ret;
        }
        return mAwContents.overlayHorizontalScrollbar();
    
public booleanoverlayVerticalScrollbar()

        mFactory.startYourEngines(false);
        if (checkNeedsPost()) {
            boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() {
                @Override
                public Boolean call() {
                    return overlayVerticalScrollbar();
                }
            });
            return ret;
        }
        return mAwContents.overlayVerticalScrollbar();
    
public booleanpageDown(boolean bottom)

        mFactory.startYourEngines(true);
        if (checkNeedsPost()) {
            Boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() {
                @Override
                public Boolean call() {
                    return pageDown(bottom);
                }
            });
            return ret;
        }
        return mAwContents.pageDown(bottom);
    
public booleanpageUp(boolean top)

        mFactory.startYourEngines(true);
        if (checkNeedsPost()) {
            Boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() {
                @Override
                public Boolean call() {
                    return pageUp(top);
                }
            });
            return ret;
        }
        return mAwContents.pageUp(top);
    
public voidpauseTimers()

        if (checkNeedsPost()) {
            mRunQueue.addTask(new Runnable() {
                @Override
                public void run() {
                    pauseTimers();
                }
            });
            return;
        }
        mAwContents.pauseTimers();
    
public booleanperformAccessibilityAction(int action, android.os.Bundle arguments)

        mFactory.startYourEngines(false);
        if (checkNeedsPost()) {
            boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() {
                @Override
                public Boolean call() {
                    return performAccessibilityAction(action, arguments);
                }
            });
            return ret;
        }
        if (mAwContents.supportsAccessibilityAction(action)) {
            return mAwContents.performAccessibilityAction(action, arguments);
        }
        return mWebViewPrivate.super_performAccessibilityAction(action, arguments);
    
public booleanperformLongClick()

        // Return false unless the WebView is attached to a View with a parent
        return mWebView.getParent() != null ? mWebViewPrivate.super_performLongClick() : false;
    
public voidpostUrl(java.lang.String url, byte[] postData)

        LoadUrlParams params = LoadUrlParams.createLoadHttpPostParams(url, postData);
        Map<String,String> headers = new HashMap<String,String>();
        headers.put("Content-Type", "application/x-www-form-urlencoded");
        params.setExtraHeaders(headers);
        loadUrlOnUiThread(params);
    
public voidpreDispatchDraw(android.graphics.Canvas canvas)

        // TODO(leandrogracia): remove this method from WebViewProvider if we think
        // we won't need it again.
    
public voidreload()

        if (checkNeedsPost()) {
            mRunQueue.addTask(new Runnable() {
                @Override
                public void run() {
                    reload();
                }
            });
            return;
        }
        mAwContents.reload();
    
public voidremoveJavascriptInterface(java.lang.String interfaceName)

        if (checkNeedsPost()) {
            mRunQueue.addTask(new Runnable() {
                @Override
                public void run() {
                    removeJavascriptInterface(interfaceName);
                }
            });
            return;
        }
        mAwContents.removeJavascriptInterface(interfaceName);
    
public booleanrequestChildRectangleOnScreen(android.view.View child, android.graphics.Rect rect, boolean immediate)

        mFactory.startYourEngines(false);
        if (checkNeedsPost()) {
            boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() {
                @Override
                public Boolean call() {
                    return requestChildRectangleOnScreen(child, rect, immediate);
                }
            });
            return ret;
        }
        return mAwContents.requestChildRectangleOnScreen(child, rect, immediate);
    
public booleanrequestFocus(int direction, android.graphics.Rect previouslyFocusedRect)

        mFactory.startYourEngines(false);
        if (checkNeedsPost()) {
            boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() {
                @Override
                public Boolean call() {
                    return requestFocus(direction, previouslyFocusedRect);
                }
            });
            return ret;
        }
        mAwContents.requestFocus();
        return mWebViewPrivate.super_requestFocus(direction, previouslyFocusedRect);
    
public voidrequestFocusNodeHref(android.os.Message hrefMsg)

        if (checkNeedsPost()) {
            mRunQueue.addTask(new Runnable() {
                @Override
                public void run() {
                    requestFocusNodeHref(hrefMsg);
                }
            });
            return;
        }
        mAwContents.requestFocusNodeHref(hrefMsg);
    
public voidrequestImageRef(android.os.Message msg)

        if (checkNeedsPost()) {
            mRunQueue.addTask(new Runnable() {
                @Override
                public void run() {
                    requestImageRef(msg);
                }
            });
            return;
        }
        mAwContents.requestImageRef(msg);
    
private static android.content.ContextresourcesContextWrapper(android.content.Context ctx)

        return new ContextWrapper(ctx) {
            @Override
            public ClassLoader getClassLoader() {
                final ClassLoader appCl = getBaseContext().getClassLoader();
                final ClassLoader webViewCl = this.getClass().getClassLoader();
                return new ClassLoader() {
                    @Override
                    protected Class<?> findClass(String name) throws ClassNotFoundException {
                        // First look in the WebViewProvider class loader.
                        try {
                            return webViewCl.loadClass(name);
                        } catch (ClassNotFoundException e) {
                            // Look in the app class loader; allowing it to throw ClassNotFoundException.
                            return appCl.loadClass(name);
                        }
                    }
                };
            }

            @Override
            public Object getSystemService(String name) {
                if (name.equals(Context.LAYOUT_INFLATER_SERVICE)) {
                    LayoutInflater i = (LayoutInflater) getBaseContext().getSystemService(name);
                    return i.cloneInContext(this);
                } else {
                    return getBaseContext().getSystemService(name);
                }
            }

        };
    
public booleanrestorePicture(android.os.Bundle b, java.io.File src)

        // Intentional no-op: hidden method on WebView.
        return false;
    
public android.webkit.WebBackForwardListrestoreState(android.os.Bundle inState)

        mFactory.startYourEngines(true);
        if (checkNeedsPost()) {
            WebBackForwardList ret = runOnUiThreadBlocking(new Callable<WebBackForwardList>() {
                @Override
                public WebBackForwardList call() {
                    return restoreState(inState);
                }
            });
            return ret;
        }
        if (inState == null) return null;
        if (!mAwContents.restoreState(inState)) return null;
        return copyBackForwardList();
    
public voidresumeTimers()

        if (checkNeedsPost()) {
            mRunQueue.addTask(new Runnable() {
                @Override
                public void run() {
                    resumeTimers();
                }
            });
            return;
        }
        mAwContents.resumeTimers();
    
private TrunBlockingFuture(java.util.concurrent.FutureTask task)

        if (!mFactory.hasStarted()) throw new RuntimeException("Must be started before we block!");
        if (ThreadUtils.runningOnUiThread()) {
            throw new IllegalStateException("This method should only be called off the UI thread");
        }
        mRunQueue.addTask(task);
        try {
            return task.get(4, TimeUnit.SECONDS);
        } catch (java.util.concurrent.TimeoutException e) {
            throw new RuntimeException("Probable deadlock detected due to WebView API being called "
                    + "on incorrect thread while the UI thread is blocked.", e);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    
private TrunOnUiThreadBlocking(java.util.concurrent.Callable c)

        return runBlockingFuture(new FutureTask<T>(c));
    
private voidrunVoidTaskOnUiThreadBlocking(java.lang.Runnable r)

        FutureTask<Void> task = new FutureTask<Void>(r, null);
        runBlockingFuture(task);
    
public voidsavePassword(java.lang.String host, java.lang.String username, java.lang.String password)

        // This is a deprecated API: intentional no-op.
    
public booleansavePicture(android.os.Bundle b, java.io.File dest)

        // Intentional no-op: hidden method on WebView.
        return false;
    
public android.webkit.WebBackForwardListsaveState(android.os.Bundle outState)

        mFactory.startYourEngines(true);
        if (checkNeedsPost()) {
            WebBackForwardList ret = runOnUiThreadBlocking(new Callable<WebBackForwardList>() {
                @Override
                public WebBackForwardList call() {
                    return saveState(outState);
                }
            });
            return ret;
        }
        if (outState == null) return null;
        if (!mAwContents.saveState(outState)) return null;
        return copyBackForwardList();
    
public voidsaveWebArchive(java.lang.String filename)

        saveWebArchive(filename, false, null);
    
public voidsaveWebArchive(java.lang.String basename, boolean autoname, android.webkit.ValueCallback callback)

        if (checkNeedsPost()) {
            mRunQueue.addTask(new Runnable() {
                @Override
                public void run() {
                    saveWebArchive(basename, autoname, callback);
                }
            });
            return;
        }
        mAwContents.saveWebArchive(basename, autoname, callback);
    
public voidsetBackgroundColor(int color)

        mFactory.startYourEngines(false);
        if (checkNeedsPost()) {
            ThreadUtils.postOnUiThread(new Runnable() {
                @Override
                public void run() {
                    setBackgroundColor(color);
                }
            });
            return;
        }
        mAwContents.setBackgroundColor(color);
    
public voidsetCertificate(android.net.http.SslCertificate certificate)

        // intentional no-op
    
public voidsetDownloadListener(android.webkit.DownloadListener listener)

        mContentsClientAdapter.setDownloadListener(listener);
    
public voidsetFindListener(WebView.FindListener listener)

        mContentsClientAdapter.setFindListener(listener);
    
public booleansetFrame(int left, int top, int right, int bottom)

        return mWebViewPrivate.super_setFrame(left, top, right, bottom);
    
public voidsetHorizontalScrollbarOverlay(boolean overlay)

        if (checkNeedsPost()) {
            mRunQueue.addTask(new Runnable() {
                @Override
                public void run() {
                    setHorizontalScrollbarOverlay(overlay);
                }
            });
            return;
        }
        mAwContents.setHorizontalScrollbarOverlay(overlay);
    
public voidsetHttpAuthUsernamePassword(java.lang.String host, java.lang.String realm, java.lang.String username, java.lang.String password)

        if (checkNeedsPost()) {
            mRunQueue.addTask(new Runnable() {
                @Override
                public void run() {
                    setHttpAuthUsernamePassword(host, realm, username, password);
                }
            });
            return;
        }
        mAwContents.setHttpAuthUsernamePassword(host, realm, username, password);
    
public voidsetInitialScale(int scaleInPercent)

        // No checkThread() as it is thread safe
        mWebSettings.getAwSettings().setInitialPageScale(scaleInPercent);
    
public voidsetLayerType(int layerType, android.graphics.Paint paint)

        // This can be called from WebView constructor in which case mAwContents
        // is still null. We set the layer type in initForReal in that case.
        if (mAwContents == null) return;
        if (checkNeedsPost()) {
            ThreadUtils.postOnUiThread(new Runnable() {
                @Override
                public void run() {
                    setLayerType(layerType, paint);
                }
            });
            return;
        }
        mAwContents.setLayerType(layerType, paint);
    
public voidsetLayoutParams(ViewGroup.LayoutParams layoutParams)

        // This API is our strongest signal from the View system that this
        // WebView is going to be bound to a View hierarchy and so at this
        // point we must bind Chromium's UI thread to the current thread.
        mFactory.startYourEngines(false);
        checkThread();
        mWebViewPrivate.super_setLayoutParams(layoutParams);
    
public voidsetMapTrackballToArrowKeys(boolean setMap)

        // This is a deprecated API: intentional no-op.
    
public voidsetNetworkAvailable(boolean networkUp)

        // Note that this purely toggles the JS navigator.online property.
        // It does not in affect chromium or network stack state in any way.
        if (checkNeedsPost()) {
            mRunQueue.addTask(new Runnable() {
                @Override
                public void run() {
                    setNetworkAvailable(networkUp);
                }
            });
            return;
        }
        mAwContents.setNetworkAvailable(networkUp);
    
public voidsetOverScrollMode(int mode)

        // This gets called from the android.view.View c'tor that WebView inherits from. This
        // causes the method to be called when mAwContents == null.
        // It's safe to ignore these calls however since AwContents will read the current value of
        // this setting when it's created.
        if (mAwContents == null) return;

        if (checkNeedsPost()) {
            mRunQueue.addTask(new Runnable() {
                @Override
                public void run() {
                    setOverScrollMode(mode);
                }
            });
            return;
        }
        mAwContents.setOverScrollMode(mode);
    
public voidsetPictureListener(WebView.PictureListener listener)

        if (checkNeedsPost()) {
            mRunQueue.addTask(new Runnable() {
                @Override
                public void run() {
                    setPictureListener(listener);
                }
            });
            return;
        }
        mContentsClientAdapter.setPictureListener(listener);
        mAwContents.enableOnNewPicture(listener != null,
                mAppTargetSdkVersion >= Build.VERSION_CODES.JELLY_BEAN_MR2);
    
public voidsetScrollBarStyle(int style)

        if (checkNeedsPost()) {
            mRunQueue.addTask(new Runnable() {
                @Override
                public void run() {
                    setScrollBarStyle(style);
                }
            });
            return;
        }
        mAwContents.setScrollBarStyle(style);
    
public voidsetSmartClipResultHandler(android.os.Handler resultHandler)

        checkThread();
        mAwContents.setSmartClipResultHandler(resultHandler);
    
public voidsetVerticalScrollbarOverlay(boolean overlay)

        if (checkNeedsPost()) {
            mRunQueue.addTask(new Runnable() {
                @Override
                public void run() {
                    setVerticalScrollbarOverlay(overlay);
                }
            });
            return;
        }
        mAwContents.setVerticalScrollbarOverlay(overlay);
    
public voidsetWebChromeClient(android.webkit.WebChromeClient client)

        mWebSettings.getAwSettings().setFullscreenSupported(doesSupportFullscreen(client));
        mContentsClientAdapter.setWebChromeClient(client);
    
public voidsetWebViewClient(android.webkit.WebViewClient client)

        mContentsClientAdapter.setWebViewClient(client);
    
public booleanshouldDelayChildPressedState()

        mFactory.startYourEngines(false);
        if (checkNeedsPost()) {
            boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() {
                @Override
                public Boolean call() {
                    return shouldDelayChildPressedState();
                }
            });
            return ret;
        }
        return true;
    
public booleanshowFindDialog(java.lang.String text, boolean showIme)

        mFactory.startYourEngines(false);
        if (checkNeedsPost()) {
            return false;
        }
        if (mWebView.getParent() == null) {
            return false;
        }

        FindActionModeCallback findAction = new FindActionModeCallback(mWebView.getContext());
        if (findAction == null) {
            return false;
        }

        mWebView.startActionMode(findAction);
        findAction.setWebView(mWebView);
        if (showIme) {
            findAction.showSoftInput();
        }

        if (text != null) {
            findAction.setText(text);
            findAction.findAll();
        }

        return true;
    
voidstartYourEngine()

        mRunQueue.drainQueue();
    
public voidstopLoading()

        if (checkNeedsPost()) {
            mRunQueue.addTask(new Runnable() {
                @Override
                public void run() {
                    stopLoading();
                }
            });
            return;
        }

        mAwContents.stopLoading();
    
public booleanzoomBy(float factor)

        mFactory.startYourEngines(true);
        // This is an L API and therefore we can enforce stricter threading constraints.
        checkThread();
        return mAwContents.zoomBy(factor);
    
public booleanzoomIn()

        mFactory.startYourEngines(true);
        if (checkNeedsPost()) {
            boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() {
                @Override
                public Boolean call() {
                    return zoomIn();
                }
            });
            return ret;
        }
        return mAwContents.zoomIn();
    
public booleanzoomOut()

        mFactory.startYourEngines(true);
        if (checkNeedsPost()) {
            boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() {
                @Override
                public Boolean call() {
                    return zoomOut();
                }
            });
            return ret;
        }
        return mAwContents.zoomOut();