1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 package com.android.webview.chromium;
6 
7 import android.annotation.SuppressLint;
8 import android.annotation.TargetApi;
9 import android.content.Context;
10 import android.content.Intent;
11 import android.content.res.Configuration;
12 import android.graphics.Bitmap;
13 import android.graphics.Canvas;
14 import android.graphics.Paint;
15 import android.graphics.Picture;
16 import android.graphics.Rect;
17 import android.graphics.drawable.Drawable;
18 import android.net.Uri;
19 import android.net.http.SslCertificate;
20 import android.os.Build;
21 import android.os.Bundle;
22 import android.os.Handler;
23 import android.os.Looper;
24 import android.os.Message;
25 import android.os.SystemClock;
26 import android.print.PrintDocumentAdapter;
27 import android.util.Log;
28 import android.util.SparseArray;
29 import android.view.DragEvent;
30 import android.view.KeyEvent;
31 import android.view.MotionEvent;
32 import android.view.View;
33 import android.view.ViewGroup;
34 import android.view.ViewStructure;
35 import android.view.accessibility.AccessibilityEvent;
36 import android.view.accessibility.AccessibilityNodeInfo;
37 import android.view.accessibility.AccessibilityNodeProvider;
38 import android.view.autofill.AutofillValue;
39 import android.view.inputmethod.EditorInfo;
40 import android.view.inputmethod.InputConnection;
41 import android.view.textclassifier.TextClassifier;
42 import android.webkit.DownloadListener;
43 import android.webkit.FindActionModeCallback;
44 import android.webkit.ValueCallback;
45 import android.webkit.WebBackForwardList;
46 import android.webkit.WebChromeClient;
47 import android.webkit.WebChromeClient.CustomViewCallback;
48 import android.webkit.WebMessage;
49 import android.webkit.WebMessagePort;
50 import android.webkit.WebSettings;
51 import android.webkit.WebView;
52 import android.webkit.WebView.VisualStateCallback;
53 import android.webkit.WebViewClient;
54 import android.webkit.WebViewProvider;
55 import android.webkit.WebViewRenderProcess;
56 import android.webkit.WebViewRenderProcessClient;
57 import android.widget.TextView;
58 
59 import androidx.annotation.IntDef;
60 
61 import org.chromium.android_webview.AwContents;
62 import org.chromium.android_webview.AwContentsStatics;
63 import org.chromium.android_webview.AwPrintDocumentAdapter;
64 import org.chromium.android_webview.AwSettings;
65 import org.chromium.android_webview.AwThreadUtils;
66 import org.chromium.android_webview.gfx.AwDrawFnImpl;
67 import org.chromium.android_webview.renderer_priority.RendererPriority;
68 import org.chromium.base.BuildInfo;
69 import org.chromium.base.ThreadUtils;
70 import org.chromium.base.metrics.RecordHistogram;
71 import org.chromium.base.metrics.ScopedSysTraceEvent;
72 import org.chromium.components.autofill.AutofillProvider;
73 import org.chromium.components.content_capture.ContentCaptureConsumerImpl;
74 import org.chromium.components.content_capture.ContentCaptureFeatures;
75 import org.chromium.components.embedder_support.application.ClassLoaderContextWrapperFactory;
76 import org.chromium.content_public.browser.NavigationHistory;
77 import org.chromium.content_public.browser.SmartClipProvider;
78 import org.chromium.url.GURL;
79 
80 import java.io.BufferedWriter;
81 import java.io.File;
82 import java.lang.reflect.Field;
83 import java.lang.reflect.Method;
84 import java.util.Map;
85 import java.util.concurrent.Callable;
86 import java.util.concurrent.Executor;
87 
88 /**
89  * This class is the delegate to which WebViewProxy forwards all API calls.
90  *
91  * Most of the actual functionality is implemented by AwContents (or WebContents within
92  * it). This class also contains WebView-specific APIs that require the creation of other
93  * adapters (otherwise org.chromium.content would depend on the webview.chromium package)
94  * and a small set of no-op deprecated APIs.
95  */
96 @SuppressWarnings("deprecation")
97 class WebViewChromium implements WebViewProvider, WebViewProvider.ScrollDelegate,
98                                  WebViewProvider.ViewDelegate, SmartClipProvider {
99 
100     private static final String TAG = WebViewChromium.class.getSimpleName();
101 
102     // The WebView that this WebViewChromium is the provider for.
103     WebView mWebView;
104     // Lets us access protected View-derived methods on the WebView instance we're backing.
105     WebView.PrivateAccess mWebViewPrivate;
106     // The client adapter class.
107     private WebViewContentsClientAdapter mContentsClientAdapter;
108     // The wrapped Context.
109     private Context mContext;
110 
111     // Variables for functionality provided by this adapter ---------------------------------------
112     private ContentSettingsAdapter mWebSettings;
113     // The WebView wrapper for WebContents and required browser components.
114     AwContents mAwContents;
115 
116     private final WebView.HitTestResult mHitTestResult;
117 
118     private final int mAppTargetSdkVersion;
119 
120     protected WebViewChromiumFactoryProvider mFactory;
121 
122     protected final SharedWebViewChromium mSharedWebViewChromium;
123 
124     private final boolean mShouldDisableThreadChecking;
125 
126     private static boolean sRecordWholeDocumentEnabledByApi;
enableSlowWholeDocumentDraw()127     static void enableSlowWholeDocumentDraw() {
128         sRecordWholeDocumentEnabledByApi = true;
129     }
130 
131     // Used to record the UMA histogram WebView.WebViewApiCall. Since these values are persisted to
132     // logs, they should never be renumbered or reused.
133     @IntDef({ApiCall.ADD_JAVASCRIPT_INTERFACE, ApiCall.AUTOFILL, ApiCall.CAN_GO_BACK,
134             ApiCall.CAN_GO_BACK_OR_FORWARD, ApiCall.CAN_GO_FORWARD, ApiCall.CAN_ZOOM_IN,
135             ApiCall.CAN_ZOOM_OUT, ApiCall.CAPTURE_PICTURE, ApiCall.CLEAR_CACHE,
136             ApiCall.CLEAR_FORM_DATA, ApiCall.CLEAR_HISTORY, ApiCall.CLEAR_MATCHES,
137             ApiCall.CLEAR_SSL_PREFERENCES, ApiCall.CLEAR_VIEW, ApiCall.COPY_BACK_FORWARD_LIST,
138             ApiCall.CREATE_PRINT_DOCUMENT_ADAPTER, ApiCall.CREATE_WEBMESSAGE_CHANNEL,
139             ApiCall.DOCUMENT_HAS_IMAGES, ApiCall.DOES_SUPPORT_FULLSCREEN,
140             ApiCall.EVALUATE_JAVASCRIPT, ApiCall.EXTRACT_SMART_CLIP_DATA, ApiCall.FIND_NEXT,
141             ApiCall.GET_CERTIFICATE, ApiCall.GET_CONTENT_HEIGHT, ApiCall.GET_CONTENT_WIDTH,
142             ApiCall.GET_FAVICON, ApiCall.GET_HIT_TEST_RESULT,
143             ApiCall.GET_HTTP_AUTH_USERNAME_PASSWORD, ApiCall.GET_ORIGINAL_URL, ApiCall.GET_PROGRESS,
144             ApiCall.GET_SCALE, ApiCall.GET_SETTINGS, ApiCall.GET_TEXT_CLASSIFIER, ApiCall.GET_TITLE,
145             ApiCall.GET_URL, ApiCall.GET_WEBCHROME_CLIENT, ApiCall.GET_WEBVIEW_CLIENT,
146             ApiCall.GO_BACK, ApiCall.GO_BACK_OR_FORWARD, ApiCall.GO_FORWARD,
147             ApiCall.INSERT_VISUAL_STATE_CALLBACK, ApiCall.INVOKE_ZOOM_PICKER, ApiCall.IS_PAUSED,
148             ApiCall.IS_PRIVATE_BROWSING_ENABLED, ApiCall.LOAD_DATA, ApiCall.LOAD_DATA_WITH_BASE_URL,
149             ApiCall.NOTIFY_FIND_DIALOG_DISMISSED, ApiCall.ON_PAUSE,
150             ApiCall.ON_PROVIDE_AUTOFILL_VIRTUAL_STRUCTURE, ApiCall.ON_RESUME,
151             ApiCall.OVERLAY_HORIZONTAL_SCROLLBAR, ApiCall.OVERLAY_VERTICAL_SCROLLBAR,
152             ApiCall.PAGE_DOWN, ApiCall.PAGE_UP, ApiCall.PAUSE_TIMERS,
153             ApiCall.POST_MESSAGE_TO_MAIN_FRAME, ApiCall.POST_URL, ApiCall.RELOAD,
154             ApiCall.REMOVE_JAVASCRIPT_INTERFACE, ApiCall.REQUEST_FOCUS_NODE_HREF,
155             ApiCall.REQUEST_IMAGE_REF, ApiCall.RESTORE_STATE, ApiCall.RESUME_TIMERS,
156             ApiCall.SAVE_STATE, ApiCall.SET_DOWNLOAD_LISTENER, ApiCall.SET_FIND_LISTENER,
157             ApiCall.SET_HORIZONTAL_SCROLLBAR_OVERLAY, ApiCall.SET_HTTP_AUTH_USERNAME_PASSWORD,
158             ApiCall.SET_INITIAL_SCALE, ApiCall.SET_NETWORK_AVAILABLE, ApiCall.SET_PICTURE_LISTENER,
159             ApiCall.SET_SMART_CLIP_RESULT_HANDLER, ApiCall.SET_TEXT_CLASSIFIER,
160             ApiCall.SET_VERTICAL_SCROLLBAR_OVERLAY, ApiCall.SET_WEBCHROME_CLIENT,
161             ApiCall.SET_WEBVIEW_CLIENT, ApiCall.SHOW_FIND_DIALOG, ApiCall.STOP_LOADING})
162     @interface ApiCall {
163         int ADD_JAVASCRIPT_INTERFACE = 0;
164         int AUTOFILL = 1;
165         int CAN_GO_BACK = 2;
166         int CAN_GO_BACK_OR_FORWARD = 3;
167         int CAN_GO_FORWARD = 4;
168         int CAN_ZOOM_IN = 5;
169         int CAN_ZOOM_OUT = 6;
170         int CAPTURE_PICTURE = 7;
171         int CLEAR_CACHE = 8;
172         int CLEAR_FORM_DATA = 9;
173         int CLEAR_HISTORY = 10;
174         int CLEAR_MATCHES = 11;
175         int CLEAR_SSL_PREFERENCES = 12;
176         int CLEAR_VIEW = 13;
177         int COPY_BACK_FORWARD_LIST = 14;
178         int CREATE_PRINT_DOCUMENT_ADAPTER = 15;
179         int CREATE_WEBMESSAGE_CHANNEL = 16;
180         int DOCUMENT_HAS_IMAGES = 17;
181         int DOES_SUPPORT_FULLSCREEN = 18;
182         int EVALUATE_JAVASCRIPT = 19;
183         int EXTRACT_SMART_CLIP_DATA = 20;
184         int FIND_NEXT = 21;
185         int GET_CERTIFICATE = 22;
186         int GET_CONTENT_HEIGHT = 23;
187         int GET_CONTENT_WIDTH = 24;
188         int GET_FAVICON = 25;
189         int GET_HIT_TEST_RESULT = 26;
190         int GET_HTTP_AUTH_USERNAME_PASSWORD = 27;
191         int GET_ORIGINAL_URL = 28;
192         int GET_PROGRESS = 29;
193         int GET_SCALE = 30;
194         int GET_SETTINGS = 31;
195         int GET_TEXT_CLASSIFIER = 32;
196         int GET_TITLE = 33;
197         int GET_URL = 34;
198         int GET_WEBCHROME_CLIENT = 35;
199         int GET_WEBVIEW_CLIENT = 36;
200         int GO_BACK = 37;
201         int GO_BACK_OR_FORWARD = 38;
202         int GO_FORWARD = 39;
203         int INSERT_VISUAL_STATE_CALLBACK = 40;
204         int INVOKE_ZOOM_PICKER = 41;
205         int IS_PAUSED = 42;
206         int IS_PRIVATE_BROWSING_ENABLED = 43;
207         int LOAD_DATA = 44;
208         int LOAD_DATA_WITH_BASE_URL = 45;
209         int NOTIFY_FIND_DIALOG_DISMISSED = 46;
210         int ON_PAUSE = 47;
211         int ON_PROVIDE_AUTOFILL_VIRTUAL_STRUCTURE = 48;
212         int ON_RESUME = 49;
213         int OVERLAY_HORIZONTAL_SCROLLBAR = 50;
214         int OVERLAY_VERTICAL_SCROLLBAR = 51;
215         int PAGE_DOWN = 52;
216         int PAGE_UP = 53;
217         int PAUSE_TIMERS = 54;
218         int POST_MESSAGE_TO_MAIN_FRAME = 55;
219         int POST_URL = 56;
220         int RELOAD = 57;
221         int REMOVE_JAVASCRIPT_INTERFACE = 58;
222         int REQUEST_FOCUS_NODE_HREF = 59;
223         int REQUEST_IMAGE_REF = 60;
224         int RESTORE_STATE = 61;
225         int RESUME_TIMERS = 62;
226         int SAVE_STATE = 63;
227         int SET_DOWNLOAD_LISTENER = 64;
228         int SET_FIND_LISTENER = 65;
229         int SET_HORIZONTAL_SCROLLBAR_OVERLAY = 66;
230         int SET_HTTP_AUTH_USERNAME_PASSWORD = 67;
231         int SET_INITIAL_SCALE = 68;
232         int SET_NETWORK_AVAILABLE = 69;
233         int SET_PICTURE_LISTENER = 70;
234         int SET_SMART_CLIP_RESULT_HANDLER = 71;
235         int SET_TEXT_CLASSIFIER = 72;
236         int SET_VERTICAL_SCROLLBAR_OVERLAY = 73;
237         int SET_WEBCHROME_CLIENT = 74;
238         int SET_WEBVIEW_CLIENT = 75;
239         int SHOW_FIND_DIALOG = 76;
240         int STOP_LOADING = 77;
241         int COUNT = 78;
242     }
243 
recordWebViewApiCall(@piCall int sample)244     private static void recordWebViewApiCall(@ApiCall int sample) {
245         RecordHistogram.recordEnumeratedHistogram("WebView.ApiCall", sample, ApiCall.COUNT);
246     }
247 
248     // This does not touch any global / non-threadsafe state, but note that
249     // init is ofter called right after and is NOT threadsafe.
WebViewChromium(WebViewChromiumFactoryProvider factory, WebView webView, WebView.PrivateAccess webViewPrivate, boolean shouldDisableThreadChecking)250     public WebViewChromium(WebViewChromiumFactoryProvider factory, WebView webView,
251             WebView.PrivateAccess webViewPrivate, boolean shouldDisableThreadChecking) {
252         try (ScopedSysTraceEvent e1 = ScopedSysTraceEvent.scoped("WebViewChromium.constructor")) {
253             WebViewChromiumFactoryProvider.checkStorageIsNotDeviceProtected(webView.getContext());
254             mWebView = webView;
255             mWebViewPrivate = webViewPrivate;
256             mHitTestResult = new WebView.HitTestResult();
257             mContext = ClassLoaderContextWrapperFactory.get(mWebView.getContext());
258             mAppTargetSdkVersion = mContext.getApplicationInfo().targetSdkVersion;
259             mFactory = factory;
260             mShouldDisableThreadChecking = shouldDisableThreadChecking;
261             factory.getWebViewDelegate().addWebViewAssetPath(mWebView.getContext());
262             mSharedWebViewChromium =
263                     new SharedWebViewChromium(mFactory.getRunQueue(), mFactory.getAwInit());
264         }
265     }
266 
267     // See //android_webview/docs/how-does-on-create-window-work.md for more details.
completeWindowCreation(WebView parent, WebView child)268     static void completeWindowCreation(WebView parent, WebView child) {
269         AwContents parentContents = ((WebViewChromium) parent.getWebViewProvider()).mAwContents;
270         AwContents childContents =
271                 child == null ? null : ((WebViewChromium) child.getWebViewProvider()).mAwContents;
272         parentContents.supplyContentsForPopup(childContents);
273     }
274 
275     // WebViewProvider methods --------------------------------------------------------------------
276 
277     @Override
278     // BUG=6790250 |javaScriptInterfaces| was only ever used by the obsolete DumpRenderTree
279     // so is ignored. TODO: remove it from WebViewProvider.
init(final Map<String, Object> javaScriptInterfaces, final boolean privateBrowsing)280     public void init(final Map<String, Object> javaScriptInterfaces,
281             final boolean privateBrowsing) {
282         long startTime = SystemClock.elapsedRealtime();
283         boolean isFirstWebViewInit = !mFactory.hasStarted();
284         try (ScopedSysTraceEvent e1 = ScopedSysTraceEvent.scoped("WebViewChromium.init")) {
285             if (privateBrowsing) {
286                 mFactory.startYourEngines(true);
287                 final String msg = "Private browsing is not supported in WebView.";
288                 if (mAppTargetSdkVersion >= Build.VERSION_CODES.KITKAT) {
289                     throw new IllegalArgumentException(msg);
290                 } else {
291                     Log.w(TAG, msg);
292                     TextView warningLabel = new TextView(mContext);
293                     warningLabel.setText(mContext.getString(
294                             org.chromium.android_webview.R.string.private_browsing_warning));
295                     mWebView.addView(warningLabel);
296                 }
297             }
298 
299             // We will defer real initialization until we know which thread to do it on, unless:
300             // - we are on the main thread already (common case),
301             // - the app is targeting >= JB MR2, in which case checkThread enforces that all usage
302             //   comes from a single thread. (Note in JB MR2 this exception was in WebView.java).
303             if (mAppTargetSdkVersion >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
304                 mFactory.startYourEngines(false);
305                 checkThread();
306             } else if (!mFactory.hasStarted()) {
307                 if (Looper.myLooper() == Looper.getMainLooper()) {
308                     mFactory.startYourEngines(true);
309                 } else {
310                     // Record which thread we're on now so we can track whether the final UI thread
311                     // decision differed.
312                     mFactory.getAwInit().setFirstWebViewConstructedOn(Looper.myLooper());
313                 }
314             }
315 
316             final boolean isAccessFromFileURLsGrantedByDefault =
317                     mAppTargetSdkVersion < Build.VERSION_CODES.JELLY_BEAN;
318             final boolean areLegacyQuirksEnabled =
319                     mAppTargetSdkVersion < Build.VERSION_CODES.KITKAT;
320             final boolean allowEmptyDocumentPersistence =
321                     mAppTargetSdkVersion <= Build.VERSION_CODES.M;
322             final boolean allowGeolocationOnInsecureOrigins =
323                     mAppTargetSdkVersion <= Build.VERSION_CODES.M;
324 
325             // https://crbug.com/698752
326             final boolean doNotUpdateSelectionOnMutatingSelectionRange =
327                     mAppTargetSdkVersion <= Build.VERSION_CODES.M;
328 
329             mContentsClientAdapter =
330                     mFactory.createWebViewContentsClientAdapter(mWebView, mContext);
331             try (ScopedSysTraceEvent e2 =
332                             ScopedSysTraceEvent.scoped("WebViewChromium.ContentSettingsAdapter")) {
333                 mWebSettings = mFactory.createContentSettingsAdapter(new AwSettings(mContext,
334                         isAccessFromFileURLsGrantedByDefault, areLegacyQuirksEnabled,
335                         allowEmptyDocumentPersistence, allowGeolocationOnInsecureOrigins,
336                         doNotUpdateSelectionOnMutatingSelectionRange));
337             }
338 
339             if (mAppTargetSdkVersion < Build.VERSION_CODES.LOLLIPOP) {
340                 // Prior to Lollipop we always allowed third party cookies and mixed content.
341                 mWebSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
342                 mWebSettings.setAcceptThirdPartyCookies(true);
343                 mWebSettings.getAwSettings().setZeroLayoutHeightDisablesViewportQuirk(true);
344             }
345 
346             if (mAppTargetSdkVersion >= Build.VERSION_CODES.P) {
347                 mWebSettings.getAwSettings().setCSSHexAlphaColorEnabled(true);
348                 mWebSettings.getAwSettings().setScrollTopLeftInteropEnabled(true);
349             }
350 
351             if (mShouldDisableThreadChecking) disableThreadChecking();
352 
353             mSharedWebViewChromium.init(mContentsClientAdapter);
354 
355             mFactory.addTask(new Runnable() {
356                 @Override
357                 public void run() {
358                     initForReal();
359                     if (privateBrowsing) {
360                         // Intentionally irreversibly disable the webview instance, so that private
361                         // user data cannot leak through misuse of a non-private-browsing WebView
362                         // instance. Can't just null out mAwContents as we never null-check it
363                         // before use.
364                         destroy();
365                     }
366                 }
367             });
368         }
369 
370         // If initialization hasn't been deferred, record a startup time histogram entry.
371         if (mFactory.hasStarted()) {
372             if (isFirstWebViewInit) {
373                 RecordHistogram.recordTimesHistogram(
374                         "Android.WebView.Startup.CreationTime.Stage2.ProviderInit.Cold",
375                         SystemClock.elapsedRealtime() - startTime);
376             } else {
377                 RecordHistogram.recordTimesHistogram(
378                         "Android.WebView.Startup.CreationTime.Stage2.ProviderInit.Warm",
379                         SystemClock.elapsedRealtime() - startTime);
380             }
381         }
382     }
383 
384     // This is a workaround for https://crbug.com/622151.
385     // In HTC's email app, InputConnection.setComposingText() will call WebView.evaluateJavaScript,
386     // and thread assertion will occur. We turn off WebView thread assertion for this app.
387     private void disableThreadChecking() {
388         try {
389             Class<?> webViewClass = Class.forName("android.webkit.WebView");
390             Field field = webViewClass.getDeclaredField("sEnforceThreadChecking");
391             field.setAccessible(true);
392             field.setBoolean(null, false);
393             field.setAccessible(false);
394         } catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException
395                 | IllegalArgumentException e) {
396             Log.w(TAG, "Failed to disable thread checking.");
397         }
398     }
399 
400     private void initForReal() {
401         try (ScopedSysTraceEvent e1 = ScopedSysTraceEvent.scoped("WebViewChromium.initForReal")) {
402             AwContentsStatics.setRecordFullDocument(sRecordWholeDocumentEnabledByApi
403                     || mAppTargetSdkVersion < Build.VERSION_CODES.LOLLIPOP);
404 
405             mAwContents = new AwContents(mFactory.getBrowserContextOnUiThread(), mWebView, mContext,
406                     new InternalAccessAdapter(), new WebViewNativeDrawFunctorFactory(),
407                     mContentsClientAdapter, mWebSettings.getAwSettings(),
408                     new AwContents.DependencyFactory() {
409                         @Override
410                         public AutofillProvider createAutofillProvider(
411                                 Context context, ViewGroup containerView) {
412                             return mFactory.createAutofillProvider(context, mWebView);
413                         }
414                     });
415             if (mAppTargetSdkVersion >= Build.VERSION_CODES.KITKAT) {
416                 // On KK and above, favicons are automatically downloaded as the method
417                 // old apps use to enable that behavior is deprecated.
418                 AwContents.setShouldDownloadFavicons();
419             }
420 
421             if (mAppTargetSdkVersion < Build.VERSION_CODES.LOLLIPOP) {
422                 // Prior to Lollipop, JavaScript objects injected via addJavascriptInterface
423                 // were not inspectable.
424                 mAwContents.disableJavascriptInterfacesInspection();
425             }
426 
427             // TODO: This assumes AwContents ignores second Paint param.
428             mAwContents.setLayerType(mWebView.getLayerType(), null);
429 
430             mSharedWebViewChromium.initForReal(mAwContents);
431         }
432     }
433 
434     private RuntimeException createThreadException() {
435         return new IllegalStateException(
436                 "Calling View methods on another thread than the UI thread.");
437     }
438 
439     protected boolean checkNeedsPost() {
440         return mSharedWebViewChromium.checkNeedsPost();
441     }
442 
443     //  Intentionally not static, as no need to check thread on static methods
444     private void checkThread() {
445         if (!ThreadUtils.runningOnUiThread()) {
446             final RuntimeException threadViolation = createThreadException();
447             AwThreadUtils.postToUiThreadLooper(() -> { throw threadViolation; });
448             throw createThreadException();
449         }
450     }
451 
452     @Override
453     public void setHorizontalScrollbarOverlay(final boolean overlay) {
454         if (checkNeedsPost()) {
455             mFactory.addTask(new Runnable() {
456                 @Override
457                 public void run() {
458                     setHorizontalScrollbarOverlay(overlay);
459                 }
460             });
461             return;
462         }
463         recordWebViewApiCall(ApiCall.SET_HORIZONTAL_SCROLLBAR_OVERLAY);
464         mAwContents.setHorizontalScrollbarOverlay(overlay);
465     }
466 
467     @Override
468     public void setVerticalScrollbarOverlay(final boolean overlay) {
469         if (checkNeedsPost()) {
470             mFactory.addTask(new Runnable() {
471                 @Override
472                 public void run() {
473                     setVerticalScrollbarOverlay(overlay);
474                 }
475             });
476             return;
477         }
478         recordWebViewApiCall(ApiCall.SET_VERTICAL_SCROLLBAR_OVERLAY);
479         mAwContents.setVerticalScrollbarOverlay(overlay);
480     }
481 
482     @Override
483     public boolean overlayHorizontalScrollbar() {
484         mFactory.startYourEngines(false);
485         if (checkNeedsPost()) {
486             boolean ret = mFactory.runOnUiThreadBlocking(new Callable<Boolean>() {
487                 @Override
488                 public Boolean call() {
489                     return overlayHorizontalScrollbar();
490                 }
491             });
492             return ret;
493         }
494         recordWebViewApiCall(ApiCall.OVERLAY_HORIZONTAL_SCROLLBAR);
495         return mAwContents.overlayHorizontalScrollbar();
496     }
497 
498     @Override
499     public boolean overlayVerticalScrollbar() {
500         mFactory.startYourEngines(false);
501         if (checkNeedsPost()) {
502             boolean ret = mFactory.runOnUiThreadBlocking(new Callable<Boolean>() {
503                 @Override
504                 public Boolean call() {
505                     return overlayVerticalScrollbar();
506                 }
507             });
508             return ret;
509         }
510         recordWebViewApiCall(ApiCall.OVERLAY_VERTICAL_SCROLLBAR);
511         return mAwContents.overlayVerticalScrollbar();
512     }
513 
514     @Override
515     public int getVisibleTitleHeight() {
516         // This is deprecated in WebView and should always return 0.
517         return 0;
518     }
519 
520     @Override
521     public SslCertificate getCertificate() {
522         mFactory.startYourEngines(true);
523         if (checkNeedsPost()) {
524             SslCertificate ret = mFactory.runOnUiThreadBlocking(new Callable<SslCertificate>() {
525                 @Override
526                 public SslCertificate call() {
527                     return getCertificate();
528                 }
529             });
530             return ret;
531         }
532         recordWebViewApiCall(ApiCall.GET_CERTIFICATE);
533         return mAwContents.getCertificate();
534     }
535 
536     @Override
537     public void setCertificate(SslCertificate certificate) {
538         // intentional no-op
539     }
540 
541     @Override
542     public void savePassword(String host, String username, String password) {
543         // This is a deprecated API: intentional no-op.
544     }
545 
546     @Override
547     public void setHttpAuthUsernamePassword(
548             final String host, final String realm, final String username, final String password) {
549         if (checkNeedsPost()) {
550             mFactory.addTask(new Runnable() {
551                 @Override
552                 public void run() {
553                     setHttpAuthUsernamePassword(host, realm, username, password);
554                 }
555             });
556             return;
557         }
558         recordWebViewApiCall(ApiCall.SET_HTTP_AUTH_USERNAME_PASSWORD);
559         ((WebViewDatabaseAdapter) mFactory.getWebViewDatabase(mContext))
560                 .setHttpAuthUsernamePassword(host, realm, username, password);
561     }
562 
563     @Override
564     public String[] getHttpAuthUsernamePassword(final String host, final String realm) {
565         mFactory.startYourEngines(true);
566         if (checkNeedsPost()) {
567             String[] ret = mFactory.runOnUiThreadBlocking(new Callable<String[]>() {
568                 @Override
569                 public String[] call() {
570                     return getHttpAuthUsernamePassword(host, realm);
571                 }
572             });
573             return ret;
574         }
575         recordWebViewApiCall(ApiCall.GET_HTTP_AUTH_USERNAME_PASSWORD);
576         return ((WebViewDatabaseAdapter) mFactory.getWebViewDatabase(mContext))
577                 .getHttpAuthUsernamePassword(host, realm);
578     }
579 
580     @Override
581     public void destroy() {
582         if (checkNeedsPost()) {
583             mFactory.addTask(new Runnable() {
584                 @Override
585                 public void run() {
586                     destroy();
587                 }
588             });
589             return;
590         }
591 
592         // Make sure that we do not trigger any callbacks after destruction
593         setWebChromeClient(null);
594         setWebViewClient(null);
595         mContentsClientAdapter.setPictureListener(null, true);
596         mContentsClientAdapter.setFindListener(null);
597         mContentsClientAdapter.setDownloadListener(null);
598 
599         mAwContents.destroy();
600     }
601 
602     @Override
603     public void setNetworkAvailable(final boolean networkUp) {
604         // Note that this purely toggles the JS navigator.online property.
605         // It does not in affect chromium or network stack state in any way.
606         if (checkNeedsPost()) {
607             mFactory.addTask(new Runnable() {
608                 @Override
609                 public void run() {
610                     setNetworkAvailable(networkUp);
611                 }
612             });
613             return;
614         }
615         recordWebViewApiCall(ApiCall.SET_NETWORK_AVAILABLE);
616         mAwContents.setNetworkAvailable(networkUp);
617     }
618 
619     @Override
620     public WebBackForwardList saveState(final Bundle outState) {
621         mFactory.startYourEngines(true);
622         if (checkNeedsPost()) {
623             WebBackForwardList ret =
624                     mFactory.runOnUiThreadBlocking(new Callable<WebBackForwardList>() {
625                         @Override
626                         public WebBackForwardList call() {
627                             return saveState(outState);
628                         }
629                     });
630             return ret;
631         }
632         recordWebViewApiCall(ApiCall.SAVE_STATE);
633         if (outState == null) return null;
634         if (!mAwContents.saveState(outState)) return null;
635         return copyBackForwardList();
636     }
637 
638     @Override
639     public boolean savePicture(Bundle b, File dest) {
640         // Intentional no-op: hidden method on WebView.
641         return false;
642     }
643 
644     @Override
645     public boolean restorePicture(Bundle b, File src) {
646         // Intentional no-op: hidden method on WebView.
647         return false;
648     }
649 
650     @Override
651     public WebBackForwardList restoreState(final Bundle inState) {
652         mFactory.startYourEngines(true);
653         if (checkNeedsPost()) {
654             WebBackForwardList ret =
655                     mFactory.runOnUiThreadBlocking(new Callable<WebBackForwardList>() {
656                         @Override
657                         public WebBackForwardList call() {
658                             return restoreState(inState);
659                         }
660                     });
661             return ret;
662         }
663         recordWebViewApiCall(ApiCall.RESTORE_STATE);
664         if (inState == null) return null;
665         if (!mAwContents.restoreState(inState)) return null;
666         return copyBackForwardList();
667     }
668 
669     @Override
670     public void loadUrl(final String url, final Map<String, String> additionalHttpHeaders) {
671         mFactory.startYourEngines(true);
672         if (checkNeedsPost()) {
673             // Disallowed in WebView API for apps targeting a new SDK
674             assert mAppTargetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2;
675             mFactory.addTask(new Runnable() {
676                 @Override
677                 public void run() {
678                     mAwContents.loadUrl(url, additionalHttpHeaders);
679                 }
680             });
681             return;
682         }
683         mAwContents.loadUrl(url, additionalHttpHeaders);
684     }
685 
686     @Override
687     public void loadUrl(final String url) {
688         mFactory.startYourEngines(true);
689         if (checkNeedsPost()) {
690             // Disallowed in WebView API for apps targeting a new SDK
691             assert mAppTargetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2;
692             mFactory.addTask(new Runnable() {
693                 @Override
694                 public void run() {
695                     mAwContents.loadUrl(url);
696                 }
697             });
698             return;
699         }
700         mAwContents.loadUrl(url);
701     }
702 
703     @Override
704     public void postUrl(final String url, final byte[] postData) {
705         mFactory.startYourEngines(true);
706         if (checkNeedsPost()) {
707             // Disallowed in WebView API for apps targeting a new SDK
708             assert mAppTargetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2;
709             mFactory.addTask(new Runnable() {
710                 @Override
711                 public void run() {
712                     recordWebViewApiCall(ApiCall.POST_URL);
713                     mAwContents.postUrl(url, postData);
714                 }
715             });
716             return;
717         }
718         recordWebViewApiCall(ApiCall.POST_URL);
719         mAwContents.postUrl(url, postData);
720     }
721 
722     @Override
723     public void loadData(final String data, final String mimeType, final String encoding) {
724         mFactory.startYourEngines(true);
725         if (checkNeedsPost()) {
726             // Disallowed in WebView API for apps targeting a new SDK
727             assert mAppTargetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2;
728             mFactory.addTask(new Runnable() {
729                 @Override
730                 public void run() {
731                     recordWebViewApiCall(ApiCall.LOAD_DATA);
732                     mAwContents.loadData(data, mimeType, encoding);
733                 }
734             });
735             return;
736         }
737         recordWebViewApiCall(ApiCall.LOAD_DATA);
738         mAwContents.loadData(data, mimeType, encoding);
739     }
740 
741     @Override
742     public void loadDataWithBaseURL(final String baseUrl, final String data, final String mimeType,
743             final String encoding, final String historyUrl) {
744         mFactory.startYourEngines(true);
745         if (checkNeedsPost()) {
746             // Disallowed in WebView API for apps targeting a new SDK
747             assert mAppTargetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2;
748             mFactory.addTask(new Runnable() {
749                 @Override
750                 public void run() {
751                     recordWebViewApiCall(ApiCall.LOAD_DATA_WITH_BASE_URL);
752                     mAwContents.loadDataWithBaseURL(baseUrl, data, mimeType, encoding, historyUrl);
753                 }
754             });
755             return;
756         }
757         recordWebViewApiCall(ApiCall.LOAD_DATA_WITH_BASE_URL);
758         mAwContents.loadDataWithBaseURL(baseUrl, data, mimeType, encoding, historyUrl);
759     }
760 
761     @Override
762     public void evaluateJavaScript(
763             final String script, final ValueCallback<String> resultCallback) {
764         if (mShouldDisableThreadChecking && checkNeedsPost()) {
765             // This is a workaround for https://crbug.com/622151.
766             mFactory.addTask(new Runnable() {
767                 @Override
768                 public void run() {
769                     recordWebViewApiCall(ApiCall.EVALUATE_JAVASCRIPT);
770                     mAwContents.evaluateJavaScript(
771                             script, CallbackConverter.fromValueCallback(resultCallback));
772                 }
773             });
774         } else {
775             recordWebViewApiCall(ApiCall.EVALUATE_JAVASCRIPT);
776             checkThread();
777             mAwContents.evaluateJavaScript(
778                     script, CallbackConverter.fromValueCallback(resultCallback));
779         }
780     }
781 
782     @Override
783     public void saveWebArchive(String filename) {
784         saveWebArchive(filename, false, null);
785     }
786 
787     @Override
788     public void saveWebArchive(final String basename, final boolean autoname,
789             final ValueCallback<String> callback) {
790         if (checkNeedsPost()) {
791             mFactory.addTask(new Runnable() {
792                 @Override
793                 public void run() {
794                     saveWebArchive(basename, autoname, callback);
795                 }
796             });
797             return;
798         }
799         mAwContents.saveWebArchive(
800                 basename, autoname, CallbackConverter.fromValueCallback(callback));
801     }
802 
803     @Override
804     public void stopLoading() {
805         if (checkNeedsPost()) {
806             mFactory.addTask(new Runnable() {
807                 @Override
808                 public void run() {
809                     stopLoading();
810                 }
811             });
812             return;
813         }
814 
815         recordWebViewApiCall(ApiCall.STOP_LOADING);
816         mAwContents.stopLoading();
817     }
818 
819     @Override
820     public void reload() {
821         if (checkNeedsPost()) {
822             mFactory.addTask(new Runnable() {
823                 @Override
824                 public void run() {
825                     reload();
826                 }
827             });
828             return;
829         }
830         recordWebViewApiCall(ApiCall.RELOAD);
831         mAwContents.reload();
832     }
833 
834     @Override
835     public boolean canGoBack() {
836         mFactory.startYourEngines(true);
837         if (checkNeedsPost()) {
838             Boolean ret = mFactory.runOnUiThreadBlocking(new Callable<Boolean>() {
839                 @Override
840                 public Boolean call() {
841                     return canGoBack();
842                 }
843             });
844             return ret;
845         }
846         recordWebViewApiCall(ApiCall.CAN_GO_BACK);
847         return mAwContents.canGoBack();
848     }
849 
850     @Override
851     public void goBack() {
852         if (checkNeedsPost()) {
853             mFactory.addTask(new Runnable() {
854                 @Override
855                 public void run() {
856                     goBack();
857                 }
858             });
859             return;
860         }
861         recordWebViewApiCall(ApiCall.GO_BACK);
862         mAwContents.goBack();
863     }
864 
865     @Override
866     public boolean canGoForward() {
867         mFactory.startYourEngines(true);
868         if (checkNeedsPost()) {
869             Boolean ret = mFactory.runOnUiThreadBlocking(new Callable<Boolean>() {
870                 @Override
871                 public Boolean call() {
872                     return canGoForward();
873                 }
874             });
875             return ret;
876         }
877         recordWebViewApiCall(ApiCall.CAN_GO_FORWARD);
878         return mAwContents.canGoForward();
879     }
880 
881     @Override
882     public void goForward() {
883         if (checkNeedsPost()) {
884             mFactory.addTask(new Runnable() {
885                 @Override
886                 public void run() {
887                     goForward();
888                 }
889             });
890             return;
891         }
892         recordWebViewApiCall(ApiCall.GO_FORWARD);
893         mAwContents.goForward();
894     }
895 
896     @Override
897     public boolean canGoBackOrForward(final int steps) {
898         mFactory.startYourEngines(true);
899         if (checkNeedsPost()) {
900             Boolean ret = mFactory.runOnUiThreadBlocking(new Callable<Boolean>() {
901                 @Override
902                 public Boolean call() {
903                     return canGoBackOrForward(steps);
904                 }
905             });
906             return ret;
907         }
908         recordWebViewApiCall(ApiCall.CAN_GO_BACK_OR_FORWARD);
909         return mAwContents.canGoBackOrForward(steps);
910     }
911 
912     @Override
913     public void goBackOrForward(final int steps) {
914         if (checkNeedsPost()) {
915             mFactory.addTask(new Runnable() {
916                 @Override
917                 public void run() {
918                     goBackOrForward(steps);
919                 }
920             });
921             return;
922         }
923         recordWebViewApiCall(ApiCall.GO_BACK_OR_FORWARD);
924         mAwContents.goBackOrForward(steps);
925     }
926 
927     @Override
928     public boolean isPrivateBrowsingEnabled() {
929         // Not supported in this WebView implementation.
930         recordWebViewApiCall(ApiCall.IS_PRIVATE_BROWSING_ENABLED);
931         return false;
932     }
933 
934     @Override
935     public boolean pageUp(final boolean top) {
936         mFactory.startYourEngines(true);
937         if (checkNeedsPost()) {
938             Boolean ret = mFactory.runOnUiThreadBlocking(new Callable<Boolean>() {
939                 @Override
940                 public Boolean call() {
941                     return pageUp(top);
942                 }
943             });
944             return ret;
945         }
946         recordWebViewApiCall(ApiCall.PAGE_UP);
947         return mAwContents.pageUp(top);
948     }
949 
950     @Override
951     public boolean pageDown(final boolean bottom) {
952         mFactory.startYourEngines(true);
953         if (checkNeedsPost()) {
954             Boolean ret = mFactory.runOnUiThreadBlocking(new Callable<Boolean>() {
955                 @Override
956                 public Boolean call() {
957                     return pageDown(bottom);
958                 }
959             });
960             return ret;
961         }
962         recordWebViewApiCall(ApiCall.PAGE_DOWN);
963         return mAwContents.pageDown(bottom);
964     }
965 
966     @Override
967     @TargetApi(Build.VERSION_CODES.M)
968     public void insertVisualStateCallback(
969             final long requestId, final VisualStateCallback callback) {
970         recordWebViewApiCall(ApiCall.INSERT_VISUAL_STATE_CALLBACK);
971         mSharedWebViewChromium.insertVisualStateCallback(
972                 requestId, callback == null ? null : new AwContents.VisualStateCallback() {
973                     @Override
974                     public void onComplete(long requestId) {
975                         callback.onComplete(requestId);
976                     }
977                 });
978     }
979 
980     @Override
981     public void clearView() {
982         if (checkNeedsPost()) {
983             mFactory.addTask(new Runnable() {
984                 @Override
985                 public void run() {
986                     clearView();
987                 }
988             });
989             return;
990         }
991         recordWebViewApiCall(ApiCall.CLEAR_VIEW);
992         mAwContents.clearView();
993     }
994 
995     @Override
996     public Picture capturePicture() {
997         mFactory.startYourEngines(true);
998         if (checkNeedsPost()) {
999             Picture ret = mFactory.runOnUiThreadBlocking(new Callable<Picture>() {
1000                 @Override
1001                 public Picture call() {
1002                     return capturePicture();
1003                 }
1004             });
1005             return ret;
1006         }
1007         recordWebViewApiCall(ApiCall.CAPTURE_PICTURE);
1008         return mAwContents.capturePicture();
1009     }
1010 
1011     @Override
1012     public float getScale() {
1013         recordWebViewApiCall(ApiCall.GET_SCALE);
1014         // No checkThread() as it is mostly thread safe (workaround for b/10652991).
1015         mFactory.startYourEngines(true);
1016         return mAwContents.getScale();
1017     }
1018 
1019     @Override
1020     public void setInitialScale(final int scaleInPercent) {
1021         recordWebViewApiCall(ApiCall.SET_INITIAL_SCALE);
1022         // No checkThread() as it is thread safe
1023         mWebSettings.getAwSettings().setInitialPageScale(scaleInPercent);
1024     }
1025 
1026     @Override
1027     public void invokeZoomPicker() {
1028         if (checkNeedsPost()) {
1029             mFactory.addTask(new Runnable() {
1030                 @Override
1031                 public void run() {
1032                     invokeZoomPicker();
1033                 }
1034             });
1035             return;
1036         }
1037         recordWebViewApiCall(ApiCall.INVOKE_ZOOM_PICKER);
1038         mAwContents.invokeZoomPicker();
1039     }
1040 
1041     @Override
1042     public WebView.HitTestResult getHitTestResult() {
1043         mFactory.startYourEngines(true);
1044         if (checkNeedsPost()) {
1045             WebView.HitTestResult ret =
1046                     mFactory.runOnUiThreadBlocking(new Callable<WebView.HitTestResult>() {
1047                         @Override
1048                         public WebView.HitTestResult call() {
1049                             return getHitTestResult();
1050                         }
1051                     });
1052             return ret;
1053         }
1054         recordWebViewApiCall(ApiCall.GET_HIT_TEST_RESULT);
1055         AwContents.HitTestData data = mAwContents.getLastHitTestResult();
1056         mHitTestResult.setType(data.hitTestResultType);
1057         mHitTestResult.setExtra(data.hitTestResultExtraData);
1058         return mHitTestResult;
1059     }
1060 
1061     @Override
1062     public void requestFocusNodeHref(final Message hrefMsg) {
1063         if (checkNeedsPost()) {
1064             mFactory.addTask(new Runnable() {
1065                 @Override
1066                 public void run() {
1067                     requestFocusNodeHref(hrefMsg);
1068                 }
1069             });
1070             return;
1071         }
1072         recordWebViewApiCall(ApiCall.REQUEST_FOCUS_NODE_HREF);
1073         mAwContents.requestFocusNodeHref(hrefMsg);
1074     }
1075 
1076     @Override
1077     public void requestImageRef(final Message msg) {
1078         if (checkNeedsPost()) {
1079             mFactory.addTask(new Runnable() {
1080                 @Override
1081                 public void run() {
1082                     requestImageRef(msg);
1083                 }
1084             });
1085             return;
1086         }
1087         recordWebViewApiCall(ApiCall.REQUEST_IMAGE_REF);
1088         mAwContents.requestImageRef(msg);
1089     }
1090 
1091     @Override
1092     public String getUrl() {
1093         mFactory.startYourEngines(true);
1094         if (checkNeedsPost()) {
1095             String ret = mFactory.runOnUiThreadBlocking(new Callable<String>() {
1096                 @Override
1097                 public String call() {
1098                     return getUrl();
1099                 }
1100             });
1101             return ret;
1102         }
1103         recordWebViewApiCall(ApiCall.GET_URL);
1104         GURL url = mAwContents.getUrl();
1105         return url == null ? null : url.getSpec();
1106     }
1107 
1108     @Override
1109     public String getOriginalUrl() {
1110         mFactory.startYourEngines(true);
1111         if (checkNeedsPost()) {
1112             String ret = mFactory.runOnUiThreadBlocking(new Callable<String>() {
1113                 @Override
1114                 public String call() {
1115                     return getOriginalUrl();
1116                 }
1117             });
1118             return ret;
1119         }
1120         recordWebViewApiCall(ApiCall.GET_ORIGINAL_URL);
1121         return mAwContents.getOriginalUrl();
1122     }
1123 
1124     @Override
1125     public String getTitle() {
1126         mFactory.startYourEngines(true);
1127         if (checkNeedsPost()) {
1128             String ret = mFactory.runOnUiThreadBlocking(new Callable<String>() {
1129                 @Override
1130                 public String call() {
1131                     return getTitle();
1132                 }
1133             });
1134             return ret;
1135         }
1136         recordWebViewApiCall(ApiCall.GET_TITLE);
1137         return mAwContents.getTitle();
1138     }
1139 
1140     @Override
1141     public Bitmap getFavicon() {
1142         mFactory.startYourEngines(true);
1143         if (checkNeedsPost()) {
1144             Bitmap ret = mFactory.runOnUiThreadBlocking(new Callable<Bitmap>() {
1145                 @Override
1146                 public Bitmap call() {
1147                     return getFavicon();
1148                 }
1149             });
1150             return ret;
1151         }
1152         recordWebViewApiCall(ApiCall.GET_FAVICON);
1153         return mAwContents.getFavicon();
1154     }
1155 
1156     @Override
1157     public String getTouchIconUrl() {
1158         // Intentional no-op: hidden method on WebView.
1159         return null;
1160     }
1161 
1162     @Override
1163     public int getProgress() {
1164         recordWebViewApiCall(ApiCall.GET_PROGRESS);
1165         if (mAwContents == null) return 100;
1166         // No checkThread() because the value is cached java side (workaround for b/10533304).
1167         return mAwContents.getMostRecentProgress();
1168     }
1169 
1170     @Override
1171     public int getContentHeight() {
1172         recordWebViewApiCall(ApiCall.GET_CONTENT_HEIGHT);
1173         if (mAwContents == null) return 0;
1174         // No checkThread() as it is mostly thread safe (workaround for b/10594869).
1175         return mAwContents.getContentHeightCss();
1176     }
1177 
1178     @Override
1179     public int getContentWidth() {
1180         recordWebViewApiCall(ApiCall.GET_CONTENT_WIDTH);
1181         if (mAwContents == null) return 0;
1182         // No checkThread() as it is mostly thread safe (workaround for b/10594869).
1183         return mAwContents.getContentWidthCss();
1184     }
1185 
1186     @Override
1187     public void pauseTimers() {
1188         if (checkNeedsPost()) {
1189             mFactory.addTask(new Runnable() {
1190                 @Override
1191                 public void run() {
1192                     pauseTimers();
1193                 }
1194             });
1195             return;
1196         }
1197         recordWebViewApiCall(ApiCall.PAUSE_TIMERS);
1198         mAwContents.pauseTimers();
1199     }
1200 
1201     @Override
1202     public void resumeTimers() {
1203         if (checkNeedsPost()) {
1204             mFactory.addTask(new Runnable() {
1205                 @Override
1206                 public void run() {
1207                     resumeTimers();
1208                 }
1209             });
1210             return;
1211         }
1212         recordWebViewApiCall(ApiCall.RESUME_TIMERS);
1213         mAwContents.resumeTimers();
1214     }
1215 
1216     @Override
1217     public void onPause() {
1218         if (checkNeedsPost()) {
1219             mFactory.addTask(new Runnable() {
1220                 @Override
1221                 public void run() {
1222                     onPause();
1223                 }
1224             });
1225             return;
1226         }
1227         recordWebViewApiCall(ApiCall.ON_PAUSE);
1228         mAwContents.onPause();
1229     }
1230 
1231     @Override
1232     public void onResume() {
1233         if (checkNeedsPost()) {
1234             mFactory.addTask(new Runnable() {
1235                 @Override
1236                 public void run() {
1237                     onResume();
1238                 }
1239             });
1240             return;
1241         }
1242         recordWebViewApiCall(ApiCall.ON_RESUME);
1243         mAwContents.onResume();
1244     }
1245 
1246     @Override
1247     public boolean isPaused() {
1248         mFactory.startYourEngines(true);
1249         if (checkNeedsPost()) {
1250             Boolean ret = mFactory.runOnUiThreadBlocking(new Callable<Boolean>() {
1251                 @Override
1252                 public Boolean call() {
1253                     return isPaused();
1254                 }
1255             });
1256             return ret;
1257         }
1258         recordWebViewApiCall(ApiCall.IS_PAUSED);
1259         return mAwContents.isPaused();
1260     }
1261 
1262     @Override
1263     public void freeMemory() {
1264         // Intentional no-op. Memory is managed automatically by Chromium.
1265     }
1266 
1267     @Override
1268     public void clearCache(final boolean includeDiskFiles) {
1269         if (checkNeedsPost()) {
1270             mFactory.addTask(new Runnable() {
1271                 @Override
1272                 public void run() {
1273                     clearCache(includeDiskFiles);
1274                 }
1275             });
1276             return;
1277         }
1278         recordWebViewApiCall(ApiCall.CLEAR_CACHE);
1279         mAwContents.clearCache(includeDiskFiles);
1280     }
1281 
1282     /**
1283      * This is a poorly named method, but we keep it for historical reasons.
1284      */
1285     @Override
1286     public void clearFormData() {
1287         if (checkNeedsPost()) {
1288             mFactory.addTask(new Runnable() {
1289                 @Override
1290                 public void run() {
1291                     clearFormData();
1292                 }
1293             });
1294             return;
1295         }
1296         recordWebViewApiCall(ApiCall.CLEAR_FORM_DATA);
1297         mAwContents.hideAutofillPopup();
1298     }
1299 
1300     @Override
1301     public void clearHistory() {
1302         if (checkNeedsPost()) {
1303             mFactory.addTask(new Runnable() {
1304                 @Override
1305                 public void run() {
1306                     clearHistory();
1307                 }
1308             });
1309             return;
1310         }
1311         recordWebViewApiCall(ApiCall.CLEAR_HISTORY);
1312         mAwContents.clearHistory();
1313     }
1314 
1315     @Override
1316     public void clearSslPreferences() {
1317         if (checkNeedsPost()) {
1318             mFactory.addTask(new Runnable() {
1319                 @Override
1320                 public void run() {
1321                     clearSslPreferences();
1322                 }
1323             });
1324             return;
1325         }
1326         recordWebViewApiCall(ApiCall.CLEAR_SSL_PREFERENCES);
1327         mAwContents.clearSslPreferences();
1328     }
1329 
1330     @Override
1331     public WebBackForwardList copyBackForwardList() {
1332         mFactory.startYourEngines(true);
1333         if (checkNeedsPost()) {
1334             WebBackForwardList ret =
1335                     mFactory.runOnUiThreadBlocking(new Callable<WebBackForwardList>() {
1336                         @Override
1337                         public WebBackForwardList call() {
1338                             return copyBackForwardList();
1339                         }
1340                     });
1341             return ret;
1342         }
1343         recordWebViewApiCall(ApiCall.COPY_BACK_FORWARD_LIST);
1344         // mAwContents.getNavigationHistory() can be null here if mAwContents has been destroyed,
1345         // and we do not handle passing null to the WebBackForwardListChromium constructor.
1346         NavigationHistory navHistory = mAwContents.getNavigationHistory();
1347         if (navHistory == null) navHistory = new NavigationHistory();
1348         return new WebBackForwardListChromium(navHistory);
1349     }
1350 
1351     @Override
1352     public void setFindListener(WebView.FindListener listener) {
1353         recordWebViewApiCall(ApiCall.SET_FIND_LISTENER);
1354         mContentsClientAdapter.setFindListener(listener);
1355     }
1356 
1357     @Override
1358     public void findNext(final boolean forwards) {
1359         if (checkNeedsPost()) {
1360             mFactory.addTask(new Runnable() {
1361                 @Override
1362                 public void run() {
1363                     findNext(forwards);
1364                 }
1365             });
1366             return;
1367         }
1368         recordWebViewApiCall(ApiCall.FIND_NEXT);
1369         mAwContents.findNext(forwards);
1370     }
1371 
1372     @Override
1373     public int findAll(final String searchString) {
1374         findAllAsync(searchString);
1375         return 0;
1376     }
1377 
1378     @Override
1379     public void findAllAsync(final String searchString) {
1380         if (checkNeedsPost()) {
1381             mFactory.addTask(new Runnable() {
1382                 @Override
1383                 public void run() {
1384                     findAllAsync(searchString);
1385                 }
1386             });
1387             return;
1388         }
1389         mAwContents.findAllAsync(searchString);
1390     }
1391 
1392     @Override
1393     public boolean showFindDialog(final String text, final boolean showIme) {
1394         recordWebViewApiCall(ApiCall.SHOW_FIND_DIALOG);
1395         mFactory.startYourEngines(false);
1396         if (checkNeedsPost()) {
1397             return false;
1398         }
1399         if (mWebView.getParent() == null) {
1400             return false;
1401         }
1402 
1403         FindActionModeCallback findAction = new FindActionModeCallback(mContext);
1404         if (findAction == null) {
1405             return false;
1406         }
1407 
1408         mWebView.startActionMode(findAction);
1409         findAction.setWebView(mWebView);
1410         if (showIme) {
1411             findAction.showSoftInput();
1412         }
1413 
1414         if (text != null) {
1415             findAction.setText(text);
1416             findAction.findAll();
1417         }
1418 
1419         return true;
1420     }
1421 
1422     @Override
1423     public void notifyFindDialogDismissed() {
1424         if (checkNeedsPost()) {
1425             mFactory.addTask(new Runnable() {
1426                 @Override
1427                 public void run() {
1428                     notifyFindDialogDismissed();
1429                 }
1430             });
1431             return;
1432         }
1433         recordWebViewApiCall(ApiCall.NOTIFY_FIND_DIALOG_DISMISSED);
1434         clearMatches();
1435     }
1436 
1437     @Override
1438     public void clearMatches() {
1439         if (checkNeedsPost()) {
1440             mFactory.addTask(new Runnable() {
1441                 @Override
1442                 public void run() {
1443                     clearMatches();
1444                 }
1445             });
1446             return;
1447         }
1448         recordWebViewApiCall(ApiCall.CLEAR_MATCHES);
1449         mAwContents.clearMatches();
1450     }
1451 
1452     @Override
1453     public void documentHasImages(final Message response) {
1454         if (checkNeedsPost()) {
1455             mFactory.addTask(new Runnable() {
1456                 @Override
1457                 public void run() {
1458                     documentHasImages(response);
1459                 }
1460             });
1461             return;
1462         }
1463         recordWebViewApiCall(ApiCall.DOCUMENT_HAS_IMAGES);
1464         mAwContents.documentHasImages(response);
1465     }
1466 
1467     @Override
1468     public void setWebViewClient(WebViewClient client) {
1469         recordWebViewApiCall(ApiCall.SET_WEBVIEW_CLIENT);
1470         mSharedWebViewChromium.setWebViewClient(client);
1471         mContentsClientAdapter.setWebViewClient(mSharedWebViewChromium.getWebViewClient());
1472     }
1473 
1474     @Override
1475     public WebViewClient getWebViewClient() {
1476         recordWebViewApiCall(ApiCall.GET_WEBVIEW_CLIENT);
1477         return mSharedWebViewChromium.getWebViewClient();
1478     }
1479 
1480     @Override
1481     public WebViewRenderProcess getWebViewRenderProcess() {
1482         return GlueApiHelperForQ.getWebViewRenderProcess(mSharedWebViewChromium.getRenderProcess());
1483     }
1484 
1485     @Override
1486     public void setWebViewRenderProcessClient(
1487             Executor executor, WebViewRenderProcessClient webViewRenderProcessClient) {
1488         if (webViewRenderProcessClient == null) {
1489             mSharedWebViewChromium.setWebViewRendererClientAdapter(null);
1490         } else {
1491             if (executor == null) {
1492                 executor = (Runnable r) -> r.run();
1493             }
1494             GlueApiHelperForQ.setWebViewRenderProcessClient(
1495                     mSharedWebViewChromium, executor, webViewRenderProcessClient);
1496         }
1497     }
1498 
1499     @Override
1500     public WebViewRenderProcessClient getWebViewRenderProcessClient() {
1501         SharedWebViewRendererClientAdapter adapter =
1502                 mSharedWebViewChromium.getWebViewRendererClientAdapter();
1503         if (adapter == null || !(adapter instanceof WebViewRenderProcessClientAdapter)) {
1504             return null;
1505         }
1506         return GlueApiHelperForQ.getWebViewRenderProcessClient(adapter);
1507     }
1508 
1509     @Override
1510     public void setDownloadListener(DownloadListener listener) {
1511         recordWebViewApiCall(ApiCall.SET_DOWNLOAD_LISTENER);
1512         mContentsClientAdapter.setDownloadListener(listener);
1513     }
1514 
1515     @Override
1516     public void setWebChromeClient(WebChromeClient client) {
1517         recordWebViewApiCall(ApiCall.SET_WEBCHROME_CLIENT);
1518         mWebSettings.getAwSettings().setFullscreenSupported(doesSupportFullscreen(client));
1519         mSharedWebViewChromium.setWebChromeClient(client);
1520         mContentsClientAdapter.setWebChromeClient(mSharedWebViewChromium.getWebChromeClient());
1521     }
1522 
1523     @Override
1524     public WebChromeClient getWebChromeClient() {
1525         recordWebViewApiCall(ApiCall.GET_WEBCHROME_CLIENT);
1526         return mSharedWebViewChromium.getWebChromeClient();
1527     }
1528 
1529     /**
1530      * Returns true if the supplied {@link WebChromeClient} supports fullscreen.
1531      *
1532      * <p>For fullscreen support, implementations of {@link WebChromeClient#onShowCustomView}
1533      * and {@link WebChromeClient#onHideCustomView()} are required.
1534      */
1535     private boolean doesSupportFullscreen(WebChromeClient client) {
1536         recordWebViewApiCall(ApiCall.DOES_SUPPORT_FULLSCREEN);
1537         if (client == null) {
1538             return false;
1539         }
1540         Class<?> clientClass = client.getClass();
1541         boolean foundShowMethod = false;
1542         boolean foundHideMethod = false;
1543         while (clientClass != WebChromeClient.class && (!foundShowMethod || !foundHideMethod)) {
1544             if (!foundShowMethod) {
1545                 try {
1546                     clientClass.getDeclaredMethod(
1547                             "onShowCustomView", View.class, CustomViewCallback.class);
1548                     foundShowMethod = true;
1549                 } catch (NoSuchMethodException e) {
1550                     // Intentionally empty.
1551                 }
1552             }
1553 
1554             if (!foundHideMethod) {
1555                 try {
1556                     clientClass.getDeclaredMethod("onHideCustomView");
1557                     foundHideMethod = true;
1558                 } catch (NoSuchMethodException e) {
1559                     // Intentionally empty.
1560                 }
1561             }
1562             clientClass = clientClass.getSuperclass();
1563         }
1564         return foundShowMethod && foundHideMethod;
1565     }
1566 
1567     @Override
1568     @SuppressWarnings("deprecation")
1569     public void setPictureListener(final WebView.PictureListener listener) {
1570         if (checkNeedsPost()) {
1571             mFactory.addTask(new Runnable() {
1572                 @Override
1573                 public void run() {
1574                     setPictureListener(listener);
1575                 }
1576             });
1577             return;
1578         }
1579         recordWebViewApiCall(ApiCall.SET_PICTURE_LISTENER);
1580         boolean invalidateOnly = mAppTargetSdkVersion >= Build.VERSION_CODES.JELLY_BEAN_MR2;
1581         mContentsClientAdapter.setPictureListener(listener, invalidateOnly);
1582         mAwContents.enableOnNewPicture(listener != null, invalidateOnly);
1583     }
1584 
1585     @Override
1586     public void addJavascriptInterface(final Object obj, final String interfaceName) {
1587         if (checkNeedsPost()) {
1588             mFactory.addTask(new Runnable() {
1589                 @Override
1590                 public void run() {
1591                     addJavascriptInterface(obj, interfaceName);
1592                 }
1593             });
1594             return;
1595         }
1596         recordWebViewApiCall(ApiCall.ADD_JAVASCRIPT_INTERFACE);
1597         mAwContents.addJavascriptInterface(obj, interfaceName);
1598     }
1599 
1600     @Override
1601     public void removeJavascriptInterface(final String interfaceName) {
1602         if (checkNeedsPost()) {
1603             mFactory.addTask(new Runnable() {
1604                 @Override
1605                 public void run() {
1606                     removeJavascriptInterface(interfaceName);
1607                 }
1608             });
1609             return;
1610         }
1611         recordWebViewApiCall(ApiCall.REMOVE_JAVASCRIPT_INTERFACE);
1612         mAwContents.removeJavascriptInterface(interfaceName);
1613     }
1614 
1615     @Override
1616     public WebMessagePort[] createWebMessageChannel() {
1617         recordWebViewApiCall(ApiCall.CREATE_WEBMESSAGE_CHANNEL);
1618         return WebMessagePortAdapter.fromMessagePorts(
1619                 mSharedWebViewChromium.createWebMessageChannel());
1620     }
1621 
1622     @Override
1623     @TargetApi(Build.VERSION_CODES.M)
1624     public void postMessageToMainFrame(final WebMessage message, final Uri targetOrigin) {
1625         recordWebViewApiCall(ApiCall.POST_MESSAGE_TO_MAIN_FRAME);
1626         mSharedWebViewChromium.postMessageToMainFrame(message.getData(), targetOrigin.toString(),
1627                 WebMessagePortAdapter.toMessagePorts(message.getPorts()));
1628     }
1629 
1630     @Override
1631     public WebSettings getSettings() {
1632         recordWebViewApiCall(ApiCall.GET_SETTINGS);
1633         return mWebSettings;
1634     }
1635 
1636     @Override
1637     public void setMapTrackballToArrowKeys(boolean setMap) {
1638         // This is a deprecated API: intentional no-op.
1639     }
1640 
1641     @Override
1642     public void flingScroll(final int vx, final int vy) {
1643         if (checkNeedsPost()) {
1644             mFactory.addTask(new Runnable() {
1645                 @Override
1646                 public void run() {
1647                     flingScroll(vx, vy);
1648                 }
1649             });
1650             return;
1651         }
1652         mAwContents.flingScroll(vx, vy);
1653     }
1654 
1655     @Override
1656     public View getZoomControls() {
1657         mFactory.startYourEngines(false);
1658         if (checkNeedsPost()) {
1659             return null;
1660         }
1661 
1662         // This was deprecated in 2009 and hidden in JB MR1, so just provide the minimum needed
1663         // to stop very out-dated applications from crashing.
1664         Log.w(TAG, "WebView doesn't support getZoomControls");
1665         return mAwContents.getSettings().supportZoom() ? new View(mContext) : null;
1666     }
1667 
1668     @Override
1669     public boolean canZoomIn() {
1670         recordWebViewApiCall(ApiCall.CAN_ZOOM_IN);
1671         if (checkNeedsPost()) {
1672             return false;
1673         }
1674         return mAwContents.canZoomIn();
1675     }
1676 
1677     @Override
1678     public boolean canZoomOut() {
1679         recordWebViewApiCall(ApiCall.CAN_ZOOM_OUT);
1680         if (checkNeedsPost()) {
1681             return false;
1682         }
1683         return mAwContents.canZoomOut();
1684     }
1685 
1686     @Override
1687     public boolean zoomIn() {
1688         mFactory.startYourEngines(true);
1689         if (checkNeedsPost()) {
1690             boolean ret = mFactory.runOnUiThreadBlocking(new Callable<Boolean>() {
1691                 @Override
1692                 public Boolean call() {
1693                     return zoomIn();
1694                 }
1695             });
1696             return ret;
1697         }
1698         return mAwContents.zoomIn();
1699     }
1700 
1701     @Override
1702     public boolean zoomOut() {
1703         mFactory.startYourEngines(true);
1704         if (checkNeedsPost()) {
1705             boolean ret = mFactory.runOnUiThreadBlocking(new Callable<Boolean>() {
1706                 @Override
1707                 public Boolean call() {
1708                     return zoomOut();
1709                 }
1710             });
1711             return ret;
1712         }
1713         return mAwContents.zoomOut();
1714     }
1715 
1716     // TODO(paulmiller) Return void for consistency with AwContents.zoomBy and WebView.zoomBy -
1717     // tricky because frameworks WebViewProvider.zoomBy must change simultaneously
1718     @Override
1719     public boolean zoomBy(float factor) {
1720         mFactory.startYourEngines(true);
1721         // This is an L API and therefore we can enforce stricter threading constraints.
1722         checkThread();
1723         mAwContents.zoomBy(factor);
1724         return true;
1725     }
1726 
1727     @Override
1728     public void dumpViewHierarchyWithProperties(BufferedWriter out, int level) {
1729         // Intentional no-op
1730     }
1731 
1732     @Override
1733     public View findHierarchyView(String className, int hashCode) {
1734         // Intentional no-op
1735         return null;
1736     }
1737 
1738     @Override
1739     public void setRendererPriorityPolicy(
1740             int rendererRequestedPriority, boolean waivedWhenNotVisible) {
1741         @RendererPriority
1742         int awRendererRequestedPriority;
1743         switch (rendererRequestedPriority) {
1744             case WebView.RENDERER_PRIORITY_WAIVED:
1745                 awRendererRequestedPriority = RendererPriority.WAIVED;
1746                 break;
1747             case WebView.RENDERER_PRIORITY_BOUND:
1748                 awRendererRequestedPriority = RendererPriority.LOW;
1749                 break;
1750             default:
1751             case WebView.RENDERER_PRIORITY_IMPORTANT:
1752                 awRendererRequestedPriority = RendererPriority.HIGH;
1753                 break;
1754         }
1755         mAwContents.setRendererPriorityPolicy(awRendererRequestedPriority, waivedWhenNotVisible);
1756     }
1757 
1758     @Override
1759     public int getRendererRequestedPriority() {
1760         @RendererPriority
1761         final int awRendererRequestedPriority = mAwContents.getRendererRequestedPriority();
1762         switch (awRendererRequestedPriority) {
1763             case RendererPriority.WAIVED:
1764                 return WebView.RENDERER_PRIORITY_WAIVED;
1765             case RendererPriority.LOW:
1766                 return WebView.RENDERER_PRIORITY_BOUND;
1767             default:
1768             case RendererPriority.HIGH:
1769                 return WebView.RENDERER_PRIORITY_IMPORTANT;
1770         }
1771     }
1772 
1773     @Override
1774     public boolean getRendererPriorityWaivedWhenNotVisible() {
1775         return mAwContents.getRendererPriorityWaivedWhenNotVisible();
1776     }
1777 
1778     @Override
1779     public void setTextClassifier(TextClassifier textClassifier) {
1780         recordWebViewApiCall(ApiCall.SET_TEXT_CLASSIFIER);
1781         mAwContents.setTextClassifier(textClassifier);
1782     }
1783 
1784     @Override
1785     public TextClassifier getTextClassifier() {
1786         recordWebViewApiCall(ApiCall.GET_TEXT_CLASSIFIER);
1787         return mAwContents.getTextClassifier();
1788     }
1789 
1790     @Override
1791     public void autofill(final SparseArray<AutofillValue> values) {
1792         mFactory.startYourEngines(false);
1793         if (checkNeedsPost()) {
1794             mFactory.runVoidTaskOnUiThreadBlocking(new Runnable() {
1795                 @Override
1796                 public void run() {
1797                     autofill(values);
1798                 }
1799             });
1800         }
1801         recordWebViewApiCall(ApiCall.AUTOFILL);
1802         mAwContents.autofill(values);
1803     }
1804 
1805     @Override
1806     public void onProvideAutofillVirtualStructure(final ViewStructure structure, final int flags) {
1807         mFactory.startYourEngines(false);
1808         if (checkNeedsPost()) {
1809             mFactory.runVoidTaskOnUiThreadBlocking(new Runnable() {
1810                 @Override
1811                 public void run() {
1812                     onProvideAutofillVirtualStructure(structure, flags);
1813                 }
1814             });
1815             return;
1816         }
1817         recordWebViewApiCall(ApiCall.ON_PROVIDE_AUTOFILL_VIRTUAL_STRUCTURE);
1818         mAwContents.onProvideAutoFillVirtualStructure(structure, flags);
1819     }
1820 
1821     @Override
1822     public void onProvideContentCaptureStructure(ViewStructure structure, int flags) {
1823         if (ContentCaptureFeatures.isDumpForTestingEnabled()) {
1824             Log.i("ContentCapture", "onProvideContentCaptureStructure");
1825         }
1826         mAwContents.setContentCaptureConsumer(ContentCaptureConsumerImpl.create(
1827                 ClassLoaderContextWrapperFactory.get(mWebView.getContext()), mWebView, structure,
1828                 mAwContents.getWebContents()));
1829     }
1830 
1831     // WebViewProvider glue methods ---------------------------------------------------------------
1832 
1833     @Override
1834     // This needs to be kept thread safe!
1835     public WebViewProvider.ViewDelegate getViewDelegate() {
1836         return this;
1837     }
1838 
1839     @Override
1840     // This needs to be kept thread safe!
1841     public WebViewProvider.ScrollDelegate getScrollDelegate() {
1842         return this;
1843     }
1844 
1845     // WebViewProvider.ViewDelegate implementation ------------------------------------------------
1846 
1847     // TODO: remove from WebViewProvider and use default implementation from
1848     // ViewGroup.
1849     @Override
1850     public boolean shouldDelayChildPressedState() {
1851         mFactory.startYourEngines(false);
1852         if (checkNeedsPost()) {
1853             boolean ret = mFactory.runOnUiThreadBlocking(new Callable<Boolean>() {
1854                 @Override
1855                 public Boolean call() {
1856                     return shouldDelayChildPressedState();
1857                 }
1858             });
1859             return ret;
1860         }
1861         return true;
1862     }
1863 
1864     @Override
1865     public AccessibilityNodeProvider getAccessibilityNodeProvider() {
1866         mFactory.startYourEngines(false);
1867         if (checkNeedsPost()) {
1868             AccessibilityNodeProvider ret =
1869                     mFactory.runOnUiThreadBlocking(new Callable<AccessibilityNodeProvider>() {
1870                         @Override
1871                         public AccessibilityNodeProvider call() {
1872                             return getAccessibilityNodeProvider();
1873                         }
1874                     });
1875             return ret;
1876         }
1877         return mAwContents.getAccessibilityNodeProvider();
1878     }
1879 
1880     @TargetApi(Build.VERSION_CODES.M)
1881     @Override
1882     public void onProvideVirtualStructure(final ViewStructure structure) {
1883         mFactory.startYourEngines(false);
1884         if (checkNeedsPost()) {
1885             mFactory.runVoidTaskOnUiThreadBlocking(new Runnable() {
1886                 @Override
1887                 public void run() {
1888                     onProvideVirtualStructure(structure);
1889                 }
1890             });
1891             return;
1892         }
1893         mAwContents.onProvideVirtualStructure(structure);
1894     }
1895 
1896     @Override
1897     public void onInitializeAccessibilityNodeInfo(final AccessibilityNodeInfo info) {
1898         // Intentional no-op. Chromium accessibility implementation currently does not need this
1899         // calls.
1900     }
1901 
1902     @Override
1903     public void onInitializeAccessibilityEvent(final AccessibilityEvent event) {
1904         // Intentional no-op. Chromium accessibility implementation currently does not need this
1905         // calls.
1906     }
1907 
1908     @Override
1909     public boolean performAccessibilityAction(final int action, final Bundle arguments) {
1910         mFactory.startYourEngines(false);
1911         if (checkNeedsPost()) {
1912             boolean ret = mFactory.runOnUiThreadBlocking(new Callable<Boolean>() {
1913                 @Override
1914                 public Boolean call() {
1915                     return performAccessibilityAction(action, arguments);
1916                 }
1917             });
1918             return ret;
1919         }
1920         if (mAwContents.supportsAccessibilityAction(action)) {
1921             return mAwContents.performAccessibilityAction(action, arguments);
1922         }
1923         return mWebViewPrivate.super_performAccessibilityAction(action, arguments);
1924     }
1925 
1926     @Override
1927     public void setOverScrollMode(final int mode) {
1928         // This gets called from the android.view.View c'tor that WebView inherits from. This
1929         // causes the method to be called when mAwContents == null.
1930         // It's safe to ignore these calls however since AwContents will read the current value of
1931         // this setting when it's created.
1932         if (mAwContents == null) return;
1933 
1934         if (checkNeedsPost()) {
1935             mFactory.addTask(new Runnable() {
1936                 @Override
1937                 public void run() {
1938                     setOverScrollMode(mode);
1939                 }
1940             });
1941             return;
1942         }
1943         mAwContents.setOverScrollMode(mode);
1944     }
1945 
1946     @Override
1947     public void setScrollBarStyle(final int style) {
1948         if (checkNeedsPost()) {
1949             mFactory.addTask(new Runnable() {
1950                 @Override
1951                 public void run() {
1952                     setScrollBarStyle(style);
1953                 }
1954             });
1955             return;
1956         }
1957         mAwContents.setScrollBarStyle(style);
1958     }
1959 
1960     @Override
1961     public void onDrawVerticalScrollBar(final Canvas canvas, final Drawable scrollBar, final int l,
1962             final int t, final int r, final int b) {
1963         // WebViewClassic was overriding this method to handle rubberband over-scroll. Since
1964         // WebViewChromium doesn't support that the vanilla implementation of this method can be
1965         // used.
1966         mWebViewPrivate.super_onDrawVerticalScrollBar(canvas, scrollBar, l, t, r, b);
1967     }
1968 
1969     @Override
1970     public void onOverScrolled(final int scrollX, final int scrollY,
1971             final boolean clampedX, final boolean clampedY) {
1972         if (checkNeedsPost()) {
1973             mFactory.addTask(new Runnable() {
1974                 @Override
1975                 public void run() {
1976                     onOverScrolled(scrollX, scrollY, clampedX, clampedY);
1977                 }
1978             });
1979             return;
1980         }
1981         mAwContents.onContainerViewOverScrolled(scrollX, scrollY, clampedX, clampedY);
1982     }
1983 
1984     @Override
1985     public void onWindowVisibilityChanged(final int visibility) {
1986         if (checkNeedsPost()) {
1987             mFactory.addTask(new Runnable() {
1988                 @Override
1989                 public void run() {
1990                     onWindowVisibilityChanged(visibility);
1991                 }
1992             });
1993             return;
1994         }
1995         mAwContents.onWindowVisibilityChanged(visibility);
1996     }
1997 
1998     @Override
1999     @SuppressLint("DrawAllocation")
2000     public void onDraw(final Canvas canvas) {
2001         mFactory.startYourEngines(true);
2002         if (checkNeedsPost()) {
2003             mFactory.runVoidTaskOnUiThreadBlocking(new Runnable() {
2004                 @Override
2005                 public void run() {
2006                     onDraw(canvas);
2007                 }
2008             });
2009             return;
2010         }
2011         mAwContents.onDraw(canvas);
2012     }
2013 
2014     @Override
2015     public void setLayoutParams(final ViewGroup.LayoutParams layoutParams) {
2016         // This API is our strongest signal from the View system that this
2017         // WebView is going to be bound to a View hierarchy and so at this
2018         // point we must bind Chromium's UI thread to the current thread.
2019         mFactory.startYourEngines(false);
2020         checkThread();
2021         mWebViewPrivate.super_setLayoutParams(layoutParams);
2022         if (checkNeedsPost()) {
2023             mFactory.runVoidTaskOnUiThreadBlocking(new Runnable() {
2024                 @Override
2025                 public void run() {
2026                     mAwContents.setLayoutParams(layoutParams);
2027                 }
2028             });
2029             return;
2030         }
2031         mAwContents.setLayoutParams(layoutParams);
2032     }
2033 
2034     @Override
2035     public void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
2036         if (checkNeedsPost()) {
2037             mFactory.addTask(new Runnable() {
2038                 @Override
2039                 public void run() {
2040                     onActivityResult(requestCode, resultCode, data);
2041                 }
2042             });
2043             return;
2044         }
2045         mAwContents.onActivityResult(requestCode, resultCode, data);
2046     }
2047 
2048     @Override
2049     public boolean performLongClick() {
2050         // Return false unless the WebView is attached to a View with a parent
2051         return mWebView.getParent() != null ? mWebViewPrivate.super_performLongClick() : false;
2052     }
2053 
2054     @Override
2055     public void onConfigurationChanged(final Configuration newConfig) {
2056         if (checkNeedsPost()) {
2057             mFactory.addTask(new Runnable() {
2058                 @Override
2059                 public void run() {
2060                     onConfigurationChanged(newConfig);
2061                 }
2062             });
2063             return;
2064         }
2065         mAwContents.onConfigurationChanged(newConfig);
2066     }
2067 
2068     @Override
2069     public boolean onDragEvent(final DragEvent event) {
2070         mFactory.startYourEngines(false);
2071         if (checkNeedsPost()) {
2072             boolean ret = mFactory.runOnUiThreadBlocking(new Callable<Boolean>() {
2073                 @Override
2074                 public Boolean call() {
2075                     return onDragEvent(event);
2076                 }
2077             });
2078             return ret;
2079         }
2080         return mAwContents.onDragEvent(event);
2081     }
2082 
2083     @Override
2084     public InputConnection onCreateInputConnection(final EditorInfo outAttrs) {
2085         mFactory.startYourEngines(false);
2086         if (checkNeedsPost()) {
2087             return null;
2088         }
2089         return mAwContents.onCreateInputConnection(outAttrs);
2090     }
2091 
2092     @Override
2093     public boolean onKeyMultiple(final int keyCode, final int repeatCount, final KeyEvent event) {
2094         mFactory.startYourEngines(false);
2095         if (checkNeedsPost()) {
2096             boolean ret = mFactory.runOnUiThreadBlocking(new Callable<Boolean>() {
2097                 @Override
2098                 public Boolean call() {
2099                     return onKeyMultiple(keyCode, repeatCount, event);
2100                 }
2101             });
2102             return ret;
2103         }
2104         return false;
2105     }
2106 
2107     @Override
2108     public boolean onKeyDown(final int keyCode, final KeyEvent event) {
2109         mFactory.startYourEngines(false);
2110         if (checkNeedsPost()) {
2111             boolean ret = mFactory.runOnUiThreadBlocking(new Callable<Boolean>() {
2112                 @Override
2113                 public Boolean call() {
2114                     return onKeyDown(keyCode, event);
2115                 }
2116             });
2117             return ret;
2118         }
2119         return false;
2120     }
2121 
2122     @Override
2123     public boolean onKeyUp(final int keyCode, final KeyEvent event) {
2124         mFactory.startYourEngines(false);
2125         if (checkNeedsPost()) {
2126             boolean ret = mFactory.runOnUiThreadBlocking(new Callable<Boolean>() {
2127                 @Override
2128                 public Boolean call() {
2129                     return onKeyUp(keyCode, event);
2130                 }
2131             });
2132             return ret;
2133         }
2134         return mAwContents.onKeyUp(keyCode, event);
2135     }
2136 
2137     @Override
2138     public void onAttachedToWindow() {
2139         // This API is our strongest signal from the View system that this
2140         // WebView is going to be bound to a View hierarchy and so at this
2141         // point we must bind Chromium's UI thread to the current thread.
2142         mFactory.startYourEngines(false);
2143         checkThread();
2144         mAwContents.onAttachedToWindow();
2145     }
2146 
2147     @Override
2148     public void onDetachedFromWindow() {
2149         if (checkNeedsPost()) {
2150             mFactory.addTask(new Runnable() {
2151                 @Override
2152                 public void run() {
2153                     onDetachedFromWindow();
2154                 }
2155             });
2156             return;
2157         }
2158 
2159         mAwContents.onDetachedFromWindow();
2160     }
2161 
2162     @Override
2163     public void onVisibilityChanged(final View changedView, final int visibility) {
2164         // The AwContents will find out the container view visibility before the first draw so we
2165         // can safely ignore onVisibilityChanged callbacks that happen before init().
2166         if (mAwContents == null) return;
2167 
2168         if (checkNeedsPost()) {
2169             mFactory.addTask(new Runnable() {
2170                 @Override
2171                 public void run() {
2172                     onVisibilityChanged(changedView, visibility);
2173                 }
2174             });
2175             return;
2176         }
2177         mAwContents.onVisibilityChanged(changedView, visibility);
2178     }
2179 
2180     @Override
2181     public void onWindowFocusChanged(final boolean hasWindowFocus) {
2182         if (checkNeedsPost()) {
2183             mFactory.addTask(new Runnable() {
2184                 @Override
2185                 public void run() {
2186                     onWindowFocusChanged(hasWindowFocus);
2187                 }
2188             });
2189             return;
2190         }
2191         mAwContents.onWindowFocusChanged(hasWindowFocus);
2192     }
2193 
2194     @Override
2195     public void onFocusChanged(
2196             final boolean focused, final int direction, final Rect previouslyFocusedRect) {
2197         if (checkNeedsPost()) {
2198             mFactory.addTask(new Runnable() {
2199                 @Override
2200                 public void run() {
2201                     onFocusChanged(focused, direction, previouslyFocusedRect);
2202                 }
2203             });
2204             return;
2205         }
2206         mAwContents.onFocusChanged(focused, direction, previouslyFocusedRect);
2207     }
2208 
2209     @Override
2210     public boolean setFrame(final int left, final int top, final int right, final int bottom) {
2211         return mWebViewPrivate.super_setFrame(left, top, right, bottom);
2212     }
2213 
2214     @Override
2215     public void onSizeChanged(final int w, final int h, final int ow, final int oh) {
2216         if (checkNeedsPost()) {
2217             mFactory.addTask(new Runnable() {
2218                 @Override
2219                 public void run() {
2220                     onSizeChanged(w, h, ow, oh);
2221                 }
2222             });
2223             return;
2224         }
2225         mAwContents.onSizeChanged(w, h, ow, oh);
2226     }
2227 
2228     @Override
2229     public void onScrollChanged(final int l, final int t, final int oldl, final int oldt) {
2230         if (checkNeedsPost()) {
2231             mFactory.addTask(new Runnable() {
2232                 @Override
2233                 public void run() {
2234                     onScrollChanged(l, t, oldl, oldt);
2235                 }
2236             });
2237             return;
2238         }
2239         mAwContents.onContainerViewScrollChanged(l, t, oldl, oldt);
2240     }
2241 
2242     @Override
2243     public boolean dispatchKeyEvent(final KeyEvent event) {
2244         mFactory.startYourEngines(false);
2245         if (checkNeedsPost()) {
2246             boolean ret = mFactory.runOnUiThreadBlocking(new Callable<Boolean>() {
2247                 @Override
2248                 public Boolean call() {
2249                     return dispatchKeyEvent(event);
2250                 }
2251             });
2252             return ret;
2253         }
2254         return mAwContents.dispatchKeyEvent(event);
2255     }
2256 
2257     @Override
2258     public boolean onTouchEvent(final MotionEvent ev) {
2259         mFactory.startYourEngines(false);
2260         if (checkNeedsPost()) {
2261             boolean ret = mFactory.runOnUiThreadBlocking(new Callable<Boolean>() {
2262                 @Override
2263                 public Boolean call() {
2264                     return onTouchEvent(ev);
2265                 }
2266             });
2267             return ret;
2268         }
2269         return mAwContents.onTouchEvent(ev);
2270     }
2271 
2272     @Override
2273     public boolean onHoverEvent(final MotionEvent event) {
2274         mFactory.startYourEngines(false);
2275         if (checkNeedsPost()) {
2276             boolean ret = mFactory.runOnUiThreadBlocking(new Callable<Boolean>() {
2277                 @Override
2278                 public Boolean call() {
2279                     return onHoverEvent(event);
2280                 }
2281             });
2282             return ret;
2283         }
2284         return mAwContents.onHoverEvent(event);
2285     }
2286 
2287     @Override
2288     public boolean onGenericMotionEvent(final MotionEvent event) {
2289         mFactory.startYourEngines(false);
2290         if (checkNeedsPost()) {
2291             boolean ret = mFactory.runOnUiThreadBlocking(new Callable<Boolean>() {
2292                 @Override
2293                 public Boolean call() {
2294                     return onGenericMotionEvent(event);
2295                 }
2296             });
2297             return ret;
2298         }
2299         return mAwContents.onGenericMotionEvent(event);
2300     }
2301 
2302     @Override
2303     public boolean onTrackballEvent(MotionEvent ev) {
2304         // Trackball event not handled, which eventually gets converted to DPAD keyevents
2305         return false;
2306     }
2307 
2308     @Override
2309     public boolean requestFocus(final int direction, final Rect previouslyFocusedRect) {
2310         mFactory.startYourEngines(false);
2311         if (checkNeedsPost()) {
2312             boolean ret = mFactory.runOnUiThreadBlocking(new Callable<Boolean>() {
2313                 @Override
2314                 public Boolean call() {
2315                     return requestFocus(direction, previouslyFocusedRect);
2316                 }
2317             });
2318             return ret;
2319         }
2320         mAwContents.requestFocus();
2321         return mWebViewPrivate.super_requestFocus(direction, previouslyFocusedRect);
2322     }
2323 
2324     @Override
2325     @SuppressLint("DrawAllocation")
2326     public void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
2327         mFactory.startYourEngines(false);
2328         if (checkNeedsPost()) {
2329             mFactory.runVoidTaskOnUiThreadBlocking(new Runnable() {
2330                 @Override
2331                 public void run() {
2332                     onMeasure(widthMeasureSpec, heightMeasureSpec);
2333                 }
2334             });
2335             return;
2336         }
2337         mAwContents.onMeasure(widthMeasureSpec, heightMeasureSpec);
2338     }
2339 
2340     @Override
2341     public boolean requestChildRectangleOnScreen(
2342             final View child, final Rect rect, final boolean immediate) {
2343         mFactory.startYourEngines(false);
2344         if (checkNeedsPost()) {
2345             boolean ret = mFactory.runOnUiThreadBlocking(new Callable<Boolean>() {
2346                 @Override
2347                 public Boolean call() {
2348                     return requestChildRectangleOnScreen(child, rect, immediate);
2349                 }
2350             });
2351             return ret;
2352         }
2353         return mAwContents.requestChildRectangleOnScreen(child, rect, immediate);
2354     }
2355 
2356     @Override
2357     public void setBackgroundColor(final int color) {
2358         mFactory.startYourEngines(false);
2359         if (checkNeedsPost()) {
2360             mFactory.addTask(new Runnable() {
2361                 @Override
2362                 public void run() {
2363                     setBackgroundColor(color);
2364                 }
2365             });
2366             return;
2367         }
2368         mAwContents.setBackgroundColor(color);
2369     }
2370 
2371     @Override
2372     public void setLayerType(final int layerType, final Paint paint) {
2373         // This can be called from WebView constructor in which case mAwContents
2374         // is still null. We set the layer type in initForReal in that case.
2375         if (mAwContents == null) return;
2376         if (checkNeedsPost()) {
2377             mFactory.addTask(new Runnable() {
2378                 @Override
2379                 public void run() {
2380                     setLayerType(layerType, paint);
2381                 }
2382             });
2383             return;
2384         }
2385         mAwContents.setLayerType(layerType, paint);
2386     }
2387 
2388     // Overrides method added to WebViewProvider.ViewDelegate interface
2389     // (not called in M and below)
2390     @Override
2391     public Handler getHandler(Handler originalHandler) {
2392         return originalHandler;
2393     }
2394 
2395     // Overrides method added to WebViewProvider.ViewDelegate interface
2396     // (not called in M and below)
2397     @Override
2398     public View findFocus(View originalFocusedView) {
2399         return originalFocusedView;
2400     }
2401 
2402     // Remove from superclass
2403     @Override
2404     public void preDispatchDraw(Canvas canvas) {
2405         // TODO(leandrogracia): remove this method from WebViewProvider if we think
2406         // we won't need it again.
2407     }
2408 
2409     @Override
2410     public void onStartTemporaryDetach() {
2411         mAwContents.onStartTemporaryDetach();
2412     }
2413 
2414     @Override
2415     public void onFinishTemporaryDetach() {
2416         mAwContents.onFinishTemporaryDetach();
2417     }
2418 
2419     @Override
2420     public boolean onCheckIsTextEditor() {
2421         mFactory.startYourEngines(false);
2422         if (checkNeedsPost()) {
2423             return mFactory.runOnUiThreadBlocking(new Callable<Boolean>() {
2424                 @Override
2425                 public Boolean call() {
2426                     return onCheckIsTextEditor();
2427                 }
2428             });
2429         }
2430         return mAwContents.onCheckIsTextEditor();
2431     }
2432 
2433     // WebViewProvider.ScrollDelegate implementation ----------------------------------------------
2434 
2435     @Override
2436     public int computeHorizontalScrollRange() {
2437         mFactory.startYourEngines(false);
2438         if (checkNeedsPost()) {
2439             int ret = mFactory.runOnUiThreadBlocking(new Callable<Integer>() {
2440                 @Override
2441                 public Integer call() {
2442                     return computeHorizontalScrollRange();
2443                 }
2444             });
2445             return ret;
2446         }
2447         return mAwContents.computeHorizontalScrollRange();
2448     }
2449 
2450     @Override
2451     public int computeHorizontalScrollOffset() {
2452         mFactory.startYourEngines(false);
2453         if (checkNeedsPost()) {
2454             int ret = mFactory.runOnUiThreadBlocking(new Callable<Integer>() {
2455                 @Override
2456                 public Integer call() {
2457                     return computeHorizontalScrollOffset();
2458                 }
2459             });
2460             return ret;
2461         }
2462         return mAwContents.computeHorizontalScrollOffset();
2463     }
2464 
2465     @Override
2466     public int computeVerticalScrollRange() {
2467         mFactory.startYourEngines(false);
2468         if (checkNeedsPost()) {
2469             int ret = mFactory.runOnUiThreadBlocking(new Callable<Integer>() {
2470                 @Override
2471                 public Integer call() {
2472                     return computeVerticalScrollRange();
2473                 }
2474             });
2475             return ret;
2476         }
2477         return mAwContents.computeVerticalScrollRange();
2478     }
2479 
2480     @Override
2481     public int computeVerticalScrollOffset() {
2482         mFactory.startYourEngines(false);
2483         if (checkNeedsPost()) {
2484             int ret = mFactory.runOnUiThreadBlocking(new Callable<Integer>() {
2485                 @Override
2486                 public Integer call() {
2487                     return computeVerticalScrollOffset();
2488                 }
2489             });
2490             return ret;
2491         }
2492         return mAwContents.computeVerticalScrollOffset();
2493     }
2494 
2495     @Override
2496     public int computeVerticalScrollExtent() {
2497         mFactory.startYourEngines(false);
2498         if (checkNeedsPost()) {
2499             int ret = mFactory.runOnUiThreadBlocking(new Callable<Integer>() {
2500                 @Override
2501                 public Integer call() {
2502                     return computeVerticalScrollExtent();
2503                 }
2504             });
2505             return ret;
2506         }
2507         return mAwContents.computeVerticalScrollExtent();
2508     }
2509 
2510     @Override
2511     public void computeScroll() {
2512         mFactory.startYourEngines(false);
2513         if (checkNeedsPost()) {
2514             mFactory.runVoidTaskOnUiThreadBlocking(new Runnable() {
2515                 @Override
2516                 public void run() {
2517                     computeScroll();
2518                 }
2519             });
2520             return;
2521         }
2522         mAwContents.computeScroll();
2523     }
2524 
2525     @Override
2526     public PrintDocumentAdapter createPrintDocumentAdapter(String documentName) {
2527         recordWebViewApiCall(ApiCall.CREATE_PRINT_DOCUMENT_ADAPTER);
2528         checkThread();
2529         return new AwPrintDocumentAdapter(mAwContents.getPdfExporter(), documentName);
2530     }
2531     // AwContents.NativeDrawFunctorFactory implementation ----------------------------------
2532     private class WebViewNativeDrawFunctorFactory implements AwContents.NativeDrawFunctorFactory {
2533         @Override
2534         public AwContents.NativeDrawGLFunctor createGLFunctor(long context) {
2535             return new DrawGLFunctor(context, mFactory.getWebViewDelegate());
2536         }
2537 
2538         @Override
2539         public AwDrawFnImpl.DrawFnAccess getDrawFnAccess() {
2540             if (BuildInfo.isAtLeastQ()) {
2541                 return mFactory.getWebViewDelegate();
2542             }
2543             return null;
2544         }
2545     }
2546 
2547     // AwContents.InternalAccessDelegate implementation --------------------------------------
2548     private class InternalAccessAdapter implements AwContents.InternalAccessDelegate {
2549         @Override
2550         public boolean super_onKeyUp(int arg0, KeyEvent arg1) {
2551             // Intentional no-op
2552             return false;
2553         }
2554 
2555         @Override
2556         public boolean super_dispatchKeyEvent(KeyEvent event) {
2557             return mWebViewPrivate.super_dispatchKeyEvent(event);
2558         }
2559 
2560         @Override
2561         public boolean super_onGenericMotionEvent(MotionEvent arg0) {
2562             return mWebViewPrivate.super_onGenericMotionEvent(arg0);
2563         }
2564 
2565         @Override
2566         public void super_onConfigurationChanged(Configuration arg0) {
2567             // Intentional no-op
2568         }
2569 
2570         @Override
2571         public int super_getScrollBarStyle() {
2572             return mWebViewPrivate.super_getScrollBarStyle();
2573         }
2574 
2575         @Override
2576         public void super_startActivityForResult(Intent intent, int requestCode) {
2577             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
2578                 GlueApiHelperForN.super_startActivityForResult(
2579                         mWebViewPrivate, intent, requestCode);
2580             } else {
2581                 try {
2582                     Method startActivityForResultMethod =
2583                             View.class.getMethod("startActivityForResult", Intent.class, int.class);
2584                     startActivityForResultMethod.invoke(mWebView, intent, requestCode);
2585                 } catch (Exception e) {
2586                     throw new RuntimeException("Invalid reflection", e);
2587                 }
2588             }
2589         }
2590 
2591         @Override
2592         public void onScrollChanged(int l, int t, int oldl, int oldt) {
2593             // Intentional no-op.
2594             // Chromium calls this directly to trigger accessibility events. That isn't needed
2595             // for WebView since super_scrollTo invokes onScrollChanged for us.
2596         }
2597 
2598         @Override
2599         public void overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX,
2600                 int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) {
2601             mWebViewPrivate.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX,
2602                     scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent);
2603         }
2604 
2605         @Override
2606         public void super_scrollTo(int scrollX, int scrollY) {
2607             mWebViewPrivate.super_scrollTo(scrollX, scrollY);
2608         }
2609 
2610         @Override
2611         public void setMeasuredDimension(int measuredWidth, int measuredHeight) {
2612             mWebViewPrivate.setMeasuredDimension(measuredWidth, measuredHeight);
2613         }
2614 
2615         // @Override
2616         public boolean super_onHoverEvent(MotionEvent event) {
2617             return mWebViewPrivate.super_onHoverEvent(event);
2618         }
2619     }
2620 
2621     // Implements SmartClipProvider
2622     @Override
2623     public void extractSmartClipData(int x, int y, int width, int height) {
2624         recordWebViewApiCall(ApiCall.EXTRACT_SMART_CLIP_DATA);
2625         checkThread();
2626         mAwContents.extractSmartClipData(x, y, width, height);
2627     }
2628 
2629     // Implements SmartClipProvider
2630     @Override
2631     public void setSmartClipResultHandler(final Handler resultHandler) {
2632         recordWebViewApiCall(ApiCall.SET_SMART_CLIP_RESULT_HANDLER);
2633         checkThread();
2634         mAwContents.setSmartClipResultHandler(resultHandler);
2635     }
2636 
2637     SharedWebViewChromium getSharedWebViewChromium() {
2638         return mSharedWebViewChromium;
2639     }
2640 }
2641