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