WebViewChromium.java revision 53fc207e8b5079af5edfef849996a7e5dda01364
1/* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.webview.chromium; 18 19import android.content.res.Configuration; 20import android.graphics.Bitmap; 21import android.graphics.Canvas; 22import android.graphics.Paint; 23import android.graphics.Picture; 24import android.graphics.Rect; 25import android.graphics.drawable.Drawable; 26import android.net.http.SslCertificate; 27import android.os.Build; 28import android.os.Bundle; 29import android.os.Message; 30import android.print.PrintDocumentAdapter; 31import android.text.TextUtils; 32import android.util.Base64; 33import android.util.Log; 34import android.view.HardwareCanvas; 35import android.view.KeyEvent; 36import android.view.MotionEvent; 37import android.view.View; 38import android.view.View.MeasureSpec; 39import android.view.ViewGroup; 40import android.view.accessibility.AccessibilityEvent; 41import android.view.accessibility.AccessibilityNodeInfo; 42import android.view.accessibility.AccessibilityNodeProvider; 43import android.view.inputmethod.EditorInfo; 44import android.view.inputmethod.InputConnection; 45import android.webkit.DownloadListener; 46import android.webkit.FindActionModeCallback; 47import android.webkit.JavascriptInterface; 48import android.webkit.ValueCallback; 49import android.webkit.WebBackForwardList; 50import android.webkit.WebChromeClient; 51import android.webkit.WebSettings; 52import android.webkit.WebView; 53import android.webkit.WebViewClient; 54import android.webkit.WebViewProvider; 55import android.widget.TextView; 56 57import org.chromium.android_webview.AwBrowserContext; 58import org.chromium.android_webview.AwContents; 59import org.chromium.android_webview.AwLayoutSizer; 60import org.chromium.base.ThreadUtils; 61import org.chromium.content.browser.LoadUrlParams; 62import org.chromium.net.NetworkChangeNotifier; 63 64import java.io.BufferedWriter; 65import java.io.File; 66import java.lang.annotation.Annotation; 67import java.util.concurrent.Callable; 68import java.util.concurrent.FutureTask; 69import java.util.concurrent.TimeUnit; 70import java.util.HashMap; 71import java.util.Map; 72 73/** 74 * This class is the delegate to which WebViewProxy forwards all API calls. 75 * 76 * Most of the actual functionality is implemented by AwContents (or ContentViewCore within 77 * it). This class also contains WebView-specific APIs that require the creation of other 78 * adapters (otherwise org.chromium.content would depend on the webview.chromium package) 79 * and a small set of no-op deprecated APIs. 80 */ 81class WebViewChromium implements WebViewProvider, 82 WebViewProvider.ScrollDelegate, WebViewProvider.ViewDelegate { 83 84 private static final String TAG = WebViewChromium.class.getSimpleName(); 85 86 // The WebView that this WebViewChromium is the provider for. 87 WebView mWebView; 88 // Lets us access protected View-derived methods on the WebView instance we're backing. 89 WebView.PrivateAccess mWebViewPrivate; 90 // The client adapter class. 91 private WebViewContentsClientAdapter mContentsClientAdapter; 92 93 // Variables for functionality provided by this adapter --------------------------------------- 94 // WebSettings adapter, lazily initialized in the getter 95 private WebSettings mWebSettings; 96 // The WebView wrapper for ContentViewCore and required browser compontents. 97 private AwContents mAwContents; 98 // Non-null if this webview is using the GL accelerated draw path. 99 private DrawGLFunctor mGLfunctor; 100 101 private AwBrowserContext mBrowserContext; 102 103 private final WebView.HitTestResult mHitTestResult; 104 105 private final int mAppTargetSdkVersion; 106 107 // This does not touch any global / non-threadsafe state, but note that 108 // init is ofter called right after and is NOT threadsafe. 109 public WebViewChromium(WebView webView, WebView.PrivateAccess webViewPrivate, 110 AwBrowserContext browserContext) { 111 mWebView = webView; 112 mWebViewPrivate = webViewPrivate; 113 mHitTestResult = new WebView.HitTestResult(); 114 mBrowserContext = browserContext; 115 mAppTargetSdkVersion = mWebView.getContext().getApplicationInfo().targetSdkVersion; 116 } 117 118 static void completeWindowCreation(WebView parent, WebView child) { 119 AwContents parentContents = ((WebViewChromium) parent.getWebViewProvider()).mAwContents; 120 AwContents childContents = 121 child == null ? null : ((WebViewChromium) child.getWebViewProvider()).mAwContents; 122 parentContents.supplyContentsForPopup(childContents); 123 } 124 125 private static <T> T runBlockingFuture(FutureTask<T> task) { 126 if (ThreadUtils.runningOnUiThread()) { 127 throw new IllegalStateException("This method should only be called off the UI thread"); 128 } 129 ThreadUtils.postOnUiThread(task); 130 try { 131 return task.get(4, TimeUnit.SECONDS); 132 } catch (Exception e) { // Timeout is one of the possible exceptions here 133 throw new RuntimeException("Probable deadlock detected due to WebView API being called " 134 + "on incorrect thread while the UI thread is blocked.", e); 135 } 136 } 137 138 // We have a 4 second timeout to try to detect deadlocks to detect and aid in debuggin 139 // deadlocks. 140 // Do not call this method while on the UI thread! 141 private void runVoidTaskOnUiThreadBlocking(Runnable r) { 142 FutureTask<Void> task = new FutureTask<Void>(r, null); 143 runBlockingFuture(task); 144 } 145 146 private static <T> T runOnUiThreadBlocking(Callable<T> c) { 147 return runBlockingFuture(new FutureTask<T>(c)); 148 } 149 150 // WebViewProvider methods -------------------------------------------------------------------- 151 152 @Override 153 public void init(final Map<String, Object> javaScriptInterfaces, 154 final boolean privateBrowsing) { 155 if (!ThreadUtils.runningOnUiThread()) { 156 runVoidTaskOnUiThreadBlocking(new Runnable() { 157 @Override 158 public void run() { 159 init(javaScriptInterfaces, privateBrowsing); 160 } 161 }); 162 return; 163 } 164 // BUG=6790250 |javaScriptInterfaces| was only ever used by the obsolete DumpRenderTree 165 // so is ignored. TODO: remove it from WebViewProvider. 166 final boolean isAccessFromFileURLsGrantedByDefault = 167 mAppTargetSdkVersion < Build.VERSION_CODES.JELLY_BEAN; 168 final boolean areLegacyQuirksEnabled = 169 mAppTargetSdkVersion < Build.VERSION_CODES.KITKAT; 170 mContentsClientAdapter = new WebViewContentsClientAdapter(mWebView); 171 mAwContents = new AwContents(mBrowserContext, mWebView, new InternalAccessAdapter(), 172 mContentsClientAdapter, isAccessFromFileURLsGrantedByDefault, 173 new AwLayoutSizer(), areLegacyQuirksEnabled); 174 mWebSettings = new ContentSettingsAdapter(mAwContents.getSettings()); 175 176 if (privateBrowsing) { 177 final String msg = "Private browsing is not supported in WebView."; 178 if (mAppTargetSdkVersion >= Build.VERSION_CODES.KITKAT) { 179 throw new IllegalArgumentException(msg); 180 } else { 181 Log.w(TAG, msg); 182 // Intentionally irreversibly disable the webview instance, so that private 183 // user data cannot leak through misuse of a non-privateBrowing WebView instance. 184 // Can't just null out mAwContents as we never null-check it before use. 185 mAwContents.destroy(); 186 TextView warningLabel = new TextView(mWebView.getContext()); 187 warningLabel.setText(mWebView.getContext().getString( 188 com.android.internal.R.string.webviewchromium_private_browsing_warning)); 189 mWebView.addView(warningLabel); 190 } 191 } 192 193 } 194 195 private RuntimeException createThreadException() { 196 return new IllegalStateException( 197 "Calling View methods on another thread than the UI thread."); 198 } 199 200 // Intentionally not static, as no need to check thread on static methods 201 private void checkThread() { 202 if (!ThreadUtils.runningOnUiThread()) { 203 final RuntimeException threadViolation = createThreadException(); 204 ThreadUtils.postOnUiThread(new Runnable() { 205 @Override 206 public void run() { 207 throw threadViolation; 208 } 209 }); 210 throw createThreadException(); 211 } 212 } 213 214 @Override 215 public void setHorizontalScrollbarOverlay(final boolean overlay) { 216 if (!ThreadUtils.runningOnUiThread()) { 217 ThreadUtils.postOnUiThread(new Runnable() { 218 @Override 219 public void run() { 220 setHorizontalScrollbarOverlay(overlay); 221 } 222 }); 223 return; 224 } 225 mAwContents.setHorizontalScrollbarOverlay(overlay); 226 } 227 228 @Override 229 public void setVerticalScrollbarOverlay(final boolean overlay) { 230 if (!ThreadUtils.runningOnUiThread()) { 231 ThreadUtils.postOnUiThread(new Runnable() { 232 @Override 233 public void run() { 234 setVerticalScrollbarOverlay(overlay); 235 } 236 }); 237 return; 238 } 239 mAwContents.setVerticalScrollbarOverlay(overlay); 240 } 241 242 @Override 243 public boolean overlayHorizontalScrollbar() { 244 if (!ThreadUtils.runningOnUiThread()) { 245 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 246 @Override 247 public Boolean call() { 248 return overlayHorizontalScrollbar(); 249 } 250 }); 251 return ret; 252 } 253 return mAwContents.overlayHorizontalScrollbar(); 254 } 255 256 @Override 257 public boolean overlayVerticalScrollbar() { 258 if (!ThreadUtils.runningOnUiThread()) { 259 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 260 @Override 261 public Boolean call() { 262 return overlayVerticalScrollbar(); 263 } 264 }); 265 return ret; 266 } 267 return mAwContents.overlayVerticalScrollbar(); 268 } 269 270 @Override 271 public int getVisibleTitleHeight() { 272 // This is deprecated in WebView and should always return 0. 273 return 0; 274 } 275 276 @Override 277 public SslCertificate getCertificate() { 278 if (!ThreadUtils.runningOnUiThread()) { 279 SslCertificate ret = runOnUiThreadBlocking(new Callable<SslCertificate>() { 280 @Override 281 public SslCertificate call() { 282 return getCertificate(); 283 } 284 }); 285 return ret; 286 } 287 return mAwContents.getCertificate(); 288 } 289 290 @Override 291 public void setCertificate(SslCertificate certificate) { 292 // intentional no-op 293 } 294 295 @Override 296 public void savePassword(String host, String username, String password) { 297 // This is a deprecated API: intentional no-op. 298 } 299 300 @Override 301 public void setHttpAuthUsernamePassword(final String host, final String realm, 302 final String username, final String password) { 303 if (!ThreadUtils.runningOnUiThread()) { 304 ThreadUtils.postOnUiThread(new Runnable() { 305 @Override 306 public void run() { 307 setHttpAuthUsernamePassword(host, realm, username, password); 308 } 309 }); 310 return; 311 } 312 mAwContents.setHttpAuthUsernamePassword(host, realm, username, password); 313 } 314 315 @Override 316 public String[] getHttpAuthUsernamePassword(final String host, final String realm) { 317 if (!ThreadUtils.runningOnUiThread()) { 318 String[] ret = runOnUiThreadBlocking(new Callable<String[]>() { 319 @Override 320 public String[] call() { 321 return getHttpAuthUsernamePassword(host, realm); 322 } 323 }); 324 return ret; 325 } 326 return mAwContents.getHttpAuthUsernamePassword(host, realm); 327 } 328 329 @Override 330 public void destroy() { 331 if (!ThreadUtils.runningOnUiThread()) { 332 ThreadUtils.postOnUiThread(new Runnable() { 333 @Override 334 public void run() { 335 destroy(); 336 } 337 }); 338 return; 339 } 340 341 mAwContents.destroy(); 342 if (mGLfunctor != null) { 343 mGLfunctor.destroy(); 344 mGLfunctor = null; 345 } 346 } 347 348 @Override 349 public void setNetworkAvailable(final boolean networkUp) { 350 // Note that this purely toggles the JS navigator.online property. 351 // It does not in affect chromium or network stack state in any way. 352 if (!ThreadUtils.runningOnUiThread()) { 353 ThreadUtils.postOnUiThread(new Runnable() { 354 @Override 355 public void run() { 356 setNetworkAvailable(networkUp); 357 } 358 }); 359 return; 360 } 361 mAwContents.setNetworkAvailable(networkUp); 362 } 363 364 @Override 365 public WebBackForwardList saveState(final Bundle outState) { 366 if (!ThreadUtils.runningOnUiThread()) { 367 WebBackForwardList ret = runOnUiThreadBlocking(new Callable<WebBackForwardList>() { 368 @Override 369 public WebBackForwardList call() { 370 return saveState(outState); 371 } 372 }); 373 return ret; 374 } 375 if (outState == null) return null; 376 if (!mAwContents.saveState(outState)) return null; 377 return copyBackForwardList(); 378 } 379 380 @Override 381 public boolean savePicture(Bundle b, File dest) { 382 // Intentional no-op: hidden method on WebView. 383 return false; 384 } 385 386 @Override 387 public boolean restorePicture(Bundle b, File src) { 388 // Intentional no-op: hidden method on WebView. 389 return false; 390 } 391 392 @Override 393 public WebBackForwardList restoreState(final Bundle inState) { 394 if (!ThreadUtils.runningOnUiThread()) { 395 WebBackForwardList ret = runOnUiThreadBlocking(new Callable<WebBackForwardList>() { 396 @Override 397 public WebBackForwardList call() { 398 return restoreState(inState); 399 } 400 }); 401 return ret; 402 } 403 if (inState == null) return null; 404 if (!mAwContents.restoreState(inState)) return null; 405 return copyBackForwardList(); 406 } 407 408 @Override 409 public void loadUrl(String url, Map<String, String> additionalHttpHeaders) { 410 // TODO: We may actually want to do some sanity checks here (like filter about://chrome). 411 412 // For backwards compatibility, apps targeting less than K will have JS URLs evaluated 413 // directly and any result of the evaluation will not replace the current page content. 414 // Matching Chrome behavior more closely; apps targetting >= K that load a JS URL will 415 // have the result of that URL replace the content of the current page. 416 final String JAVASCRIPT_SCHEME = "javascript:"; 417 if (mAppTargetSdkVersion < Build.VERSION_CODES.KITKAT && 418 url != null && url.startsWith(JAVASCRIPT_SCHEME)) { 419 mAwContents.evaluateJavaScriptEvenIfNotYetNavigated( 420 url.substring(JAVASCRIPT_SCHEME.length())); 421 return; 422 } 423 424 LoadUrlParams params = new LoadUrlParams(url); 425 if (additionalHttpHeaders != null) params.setExtraHeaders(additionalHttpHeaders); 426 loadUrlOnUiThread(params); 427 } 428 429 @Override 430 public void loadUrl(String url) { 431 // Early out to match old WebView implementation 432 if (url == null) { 433 return; 434 } 435 loadUrl(url, null); 436 } 437 438 @Override 439 public void postUrl(String url, byte[] postData) { 440 LoadUrlParams params = LoadUrlParams.createLoadHttpPostParams(url, postData); 441 Map<String,String> headers = new HashMap<String,String>(); 442 headers.put("Content-Type", "application/x-www-form-urlencoded"); 443 params.setExtraHeaders(headers); 444 loadUrlOnUiThread(params); 445 } 446 447 private static String fixupMimeType(String mimeType) { 448 return TextUtils.isEmpty(mimeType) ? "text/html" : mimeType; 449 } 450 451 private static String fixupData(String data) { 452 return TextUtils.isEmpty(data) ? "" : data; 453 } 454 455 private static String fixupBase(String url) { 456 return TextUtils.isEmpty(url) ? "about:blank" : url; 457 } 458 459 private static String fixupHistory(String url) { 460 return TextUtils.isEmpty(url) ? "about:blank" : url; 461 } 462 463 private static boolean isBase64Encoded(String encoding) { 464 return "base64".equals(encoding); 465 } 466 467 @Override 468 public void loadData(String data, String mimeType, String encoding) { 469 loadUrlOnUiThread(LoadUrlParams.createLoadDataParams( 470 fixupData(data), fixupMimeType(mimeType), isBase64Encoded(encoding))); 471 } 472 473 @Override 474 public void loadDataWithBaseURL(String baseUrl, String data, String mimeType, String encoding, 475 String historyUrl) { 476 data = fixupData(data); 477 mimeType = fixupMimeType(mimeType); 478 LoadUrlParams loadUrlParams; 479 baseUrl = fixupBase(baseUrl); 480 historyUrl = fixupHistory(historyUrl); 481 482 if (baseUrl.startsWith("data:")) { 483 // For backwards compatibility with WebViewClassic, we use the value of |encoding| 484 // as the charset, as long as it's not "base64". 485 boolean isBase64 = isBase64Encoded(encoding); 486 loadUrlParams = LoadUrlParams.createLoadDataParamsWithBaseUrl( 487 data, mimeType, isBase64, baseUrl, historyUrl, isBase64 ? null : encoding); 488 } else { 489 // When loading data with a non-data: base URL, the classic WebView would effectively 490 // "dump" that string of data into the WebView without going through regular URL 491 // loading steps such as decoding URL-encoded entities. We achieve this same behavior by 492 // base64 encoding the data that is passed here and then loading that as a data: URL. 493 try { 494 loadUrlParams = LoadUrlParams.createLoadDataParamsWithBaseUrl( 495 Base64.encodeToString(data.getBytes("utf-8"), Base64.DEFAULT), mimeType, 496 true, baseUrl, historyUrl, "utf-8"); 497 } catch (java.io.UnsupportedEncodingException e) { 498 Log.wtf(TAG, "Unable to load data string " + data, e); 499 return; 500 } 501 } 502 loadUrlOnUiThread(loadUrlParams); 503 504 // Data url's with a base url will be resolved in Blink, and not cause an onPageStarted 505 // event to be sent. Sending the callback directly from here. 506 final String finalBaseUrl = loadUrlParams.getBaseUrl(); 507 ThreadUtils.postOnUiThread(new Runnable() { 508 @Override 509 public void run() { 510 mContentsClientAdapter.onPageStarted(finalBaseUrl); 511 } 512 }); 513 } 514 515 private void loadUrlOnUiThread(final LoadUrlParams loadUrlParams) { 516 if (ThreadUtils.runningOnUiThread()) { 517 mAwContents.loadUrl(loadUrlParams); 518 } else { 519 // Disallowed in WebView API for apps targetting a new SDK 520 assert mAppTargetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2; 521 ThreadUtils.postOnUiThread(new Runnable() { 522 @Override 523 public void run() { 524 mAwContents.loadUrl(loadUrlParams); 525 } 526 }); 527 } 528 } 529 530 public void evaluateJavaScript(String script, ValueCallback<String> resultCallback) { 531 checkThread(); 532 mAwContents.evaluateJavaScript(script, resultCallback); 533 } 534 535 @Override 536 public void saveWebArchive(String filename) { 537 saveWebArchive(filename, false, null); 538 } 539 540 @Override 541 public void saveWebArchive(final String basename, final boolean autoname, 542 final ValueCallback<String> callback) { 543 if (!ThreadUtils.runningOnUiThread()) { 544 ThreadUtils.postOnUiThread(new Runnable() { 545 @Override 546 public void run() { 547 saveWebArchive(basename, autoname, callback); 548 } 549 }); 550 return; 551 } 552 mAwContents.saveWebArchive(basename, autoname, callback); 553 } 554 555 @Override 556 public void stopLoading() { 557 if (!ThreadUtils.runningOnUiThread()) { 558 ThreadUtils.postOnUiThread(new Runnable() { 559 @Override 560 public void run() { 561 stopLoading(); 562 } 563 }); 564 return; 565 } 566 567 mAwContents.stopLoading(); 568 } 569 570 @Override 571 public void reload() { 572 if (!ThreadUtils.runningOnUiThread()) { 573 ThreadUtils.postOnUiThread(new Runnable() { 574 @Override 575 public void run() { 576 reload(); 577 } 578 }); 579 return; 580 } 581 mAwContents.reload(); 582 } 583 584 @Override 585 public boolean canGoBack() { 586 if (!ThreadUtils.runningOnUiThread()) { 587 Boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 588 @Override 589 public Boolean call() { 590 return canGoBack(); 591 } 592 }); 593 return ret; 594 } 595 return mAwContents.canGoBack(); 596 } 597 598 @Override 599 public void goBack() { 600 if (!ThreadUtils.runningOnUiThread()) { 601 ThreadUtils.postOnUiThread(new Runnable() { 602 @Override 603 public void run() { 604 goBack(); 605 } 606 }); 607 return; 608 } 609 mAwContents.goBack(); 610 } 611 612 @Override 613 public boolean canGoForward() { 614 if (!ThreadUtils.runningOnUiThread()) { 615 Boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 616 @Override 617 public Boolean call() { 618 return canGoForward(); 619 } 620 }); 621 return ret; 622 } 623 return mAwContents.canGoForward(); 624 } 625 626 @Override 627 public void goForward() { 628 if (!ThreadUtils.runningOnUiThread()) { 629 ThreadUtils.postOnUiThread(new Runnable() { 630 @Override 631 public void run() { 632 goForward(); 633 } 634 }); 635 return; 636 } 637 mAwContents.goForward(); 638 } 639 640 @Override 641 public boolean canGoBackOrForward(final int steps) { 642 if (!ThreadUtils.runningOnUiThread()) { 643 Boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 644 @Override 645 public Boolean call() { 646 return canGoBackOrForward(steps); 647 } 648 }); 649 return ret; 650 } 651 return mAwContents.canGoBackOrForward(steps); 652 } 653 654 @Override 655 public void goBackOrForward(final int steps) { 656 if (!ThreadUtils.runningOnUiThread()) { 657 ThreadUtils.postOnUiThread(new Runnable() { 658 @Override 659 public void run() { 660 goBackOrForward(steps); 661 } 662 }); 663 return; 664 } 665 mAwContents.goBackOrForward(steps); 666 } 667 668 @Override 669 public boolean isPrivateBrowsingEnabled() { 670 // Not supported in this WebView implementation. 671 return false; 672 } 673 674 @Override 675 public boolean pageUp(final boolean top) { 676 if (!ThreadUtils.runningOnUiThread()) { 677 Boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 678 @Override 679 public Boolean call() { 680 return pageUp(top); 681 } 682 }); 683 return ret; 684 } 685 return mAwContents.pageUp(top); 686 } 687 688 @Override 689 public boolean pageDown(final boolean bottom) { 690 if (!ThreadUtils.runningOnUiThread()) { 691 Boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 692 @Override 693 public Boolean call() { 694 return pageDown(bottom); 695 } 696 }); 697 return ret; 698 } 699 return mAwContents.pageDown(bottom); 700 } 701 702 @Override 703 public void clearView() { 704 if (!ThreadUtils.runningOnUiThread()) { 705 ThreadUtils.postOnUiThread(new Runnable() { 706 @Override 707 public void run() { 708 clearView(); 709 } 710 }); 711 return; 712 } 713 UnimplementedWebViewApi.invoke(); 714 } 715 716 @Override 717 public Picture capturePicture() { 718 if (!ThreadUtils.runningOnUiThread()) { 719 Picture ret = runOnUiThreadBlocking(new Callable<Picture>() { 720 @Override 721 public Picture call() { 722 return capturePicture(); 723 } 724 }); 725 return ret; 726 } 727 return mAwContents.capturePicture(); 728 } 729 730 @Override 731 public PrintDocumentAdapter createPrintDocumentAdapter() { 732 checkThread(); 733 // TODO(sgurun) fix this after upstream part lands 734 return null; 735 } 736 737 @Override 738 public float getScale() { 739 // No checkThread() as it is mostly thread safe (workaround for b/10652991). 740 return mAwContents.getScale(); 741 } 742 743 @Override 744 public void setInitialScale(final int scaleInPercent) { 745 if (!ThreadUtils.runningOnUiThread()) { 746 ThreadUtils.postOnUiThread(new Runnable() { 747 @Override 748 public void run() { 749 setInitialScale(scaleInPercent); 750 } 751 }); 752 return; 753 } 754 mAwContents.getSettings().setInitialPageScale(scaleInPercent); 755 } 756 757 @Override 758 public void invokeZoomPicker() { 759 if (!ThreadUtils.runningOnUiThread()) { 760 ThreadUtils.postOnUiThread(new Runnable() { 761 @Override 762 public void run() { 763 invokeZoomPicker(); 764 } 765 }); 766 return; 767 } 768 mAwContents.invokeZoomPicker(); 769 } 770 771 @Override 772 public WebView.HitTestResult getHitTestResult() { 773 if (!ThreadUtils.runningOnUiThread()) { 774 WebView.HitTestResult ret = runOnUiThreadBlocking( 775 new Callable<WebView.HitTestResult>() { 776 @Override 777 public WebView.HitTestResult call() { 778 return getHitTestResult(); 779 } 780 }); 781 return ret; 782 } 783 AwContents.HitTestData data = mAwContents.getLastHitTestResult(); 784 mHitTestResult.setType(data.hitTestResultType); 785 mHitTestResult.setExtra(data.hitTestResultExtraData); 786 return mHitTestResult; 787 } 788 789 @Override 790 public void requestFocusNodeHref(final Message hrefMsg) { 791 if (!ThreadUtils.runningOnUiThread()) { 792 ThreadUtils.postOnUiThread(new Runnable() { 793 @Override 794 public void run() { 795 requestFocusNodeHref(hrefMsg); 796 } 797 }); 798 return; 799 } 800 mAwContents.requestFocusNodeHref(hrefMsg); 801 } 802 803 @Override 804 public void requestImageRef(final Message msg) { 805 if (!ThreadUtils.runningOnUiThread()) { 806 ThreadUtils.postOnUiThread(new Runnable() { 807 @Override 808 public void run() { 809 requestImageRef(msg); 810 } 811 }); 812 return; 813 } 814 mAwContents.requestImageRef(msg); 815 } 816 817 @Override 818 public String getUrl() { 819 if (!ThreadUtils.runningOnUiThread()) { 820 String ret = runOnUiThreadBlocking(new Callable<String>() { 821 @Override 822 public String call() { 823 return getUrl(); 824 } 825 }); 826 return ret; 827 } 828 String url = mAwContents.getUrl(); 829 if (url == null || url.trim().isEmpty()) return null; 830 return url; 831 } 832 833 @Override 834 public String getOriginalUrl() { 835 if (!ThreadUtils.runningOnUiThread()) { 836 String ret = runOnUiThreadBlocking(new Callable<String>() { 837 @Override 838 public String call() { 839 return getOriginalUrl(); 840 } 841 }); 842 return ret; 843 } 844 String url = mAwContents.getOriginalUrl(); 845 if (url == null || url.trim().isEmpty()) return null; 846 return url; 847 } 848 849 @Override 850 public String getTitle() { 851 if (!ThreadUtils.runningOnUiThread()) { 852 String ret = runOnUiThreadBlocking(new Callable<String>() { 853 @Override 854 public String call() { 855 return getTitle(); 856 } 857 }); 858 return ret; 859 } 860 return mAwContents.getTitle(); 861 } 862 863 @Override 864 public Bitmap getFavicon() { 865 if (!ThreadUtils.runningOnUiThread()) { 866 Bitmap ret = runOnUiThreadBlocking(new Callable<Bitmap>() { 867 @Override 868 public Bitmap call() { 869 return getFavicon(); 870 } 871 }); 872 return ret; 873 } 874 return mAwContents.getFavicon(); 875 } 876 877 @Override 878 public String getTouchIconUrl() { 879 // Intentional no-op: hidden method on WebView. 880 return null; 881 } 882 883 @Override 884 public int getProgress() { 885 // No checkThread() because the value is cached java side (workaround for b/10533304). 886 return mAwContents.getMostRecentProgress(); 887 } 888 889 @Override 890 public int getContentHeight() { 891 // No checkThread() as it is mostly thread safe (workaround for b/10594869). 892 return mAwContents.getContentHeightCss(); 893 } 894 895 @Override 896 public int getContentWidth() { 897 // No checkThread() as it is mostly thread safe (workaround for b/10594869). 898 return mAwContents.getContentWidthCss(); 899 } 900 901 @Override 902 public void pauseTimers() { 903 if (!ThreadUtils.runningOnUiThread()) { 904 ThreadUtils.postOnUiThread(new Runnable() { 905 @Override 906 public void run() { 907 pauseTimers(); 908 } 909 }); 910 return; 911 } 912 mAwContents.pauseTimers(); 913 } 914 915 @Override 916 public void resumeTimers() { 917 if (!ThreadUtils.runningOnUiThread()) { 918 ThreadUtils.postOnUiThread(new Runnable() { 919 @Override 920 public void run() { 921 resumeTimers(); 922 } 923 }); 924 return; 925 } 926 mAwContents.resumeTimers(); 927 } 928 929 @Override 930 public void onPause() { 931 if (!ThreadUtils.runningOnUiThread()) { 932 ThreadUtils.postOnUiThread(new Runnable() { 933 @Override 934 public void run() { 935 onPause(); 936 } 937 }); 938 return; 939 } 940 mAwContents.onPause(); 941 } 942 943 @Override 944 public void onResume() { 945 if (!ThreadUtils.runningOnUiThread()) { 946 ThreadUtils.postOnUiThread(new Runnable() { 947 @Override 948 public void run() { 949 onResume(); 950 } 951 }); 952 return; 953 } 954 mAwContents.onResume(); 955 } 956 957 @Override 958 public boolean isPaused() { 959 if (!ThreadUtils.runningOnUiThread()) { 960 Boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 961 @Override 962 public Boolean call() { 963 return isPaused(); 964 } 965 }); 966 return ret; 967 } 968 return mAwContents.isPaused(); 969 } 970 971 @Override 972 public void freeMemory() { 973 // Intentional no-op. Memory is managed automatically by Chromium. 974 } 975 976 @Override 977 public void clearCache(final boolean includeDiskFiles) { 978 if (!ThreadUtils.runningOnUiThread()) { 979 ThreadUtils.postOnUiThread(new Runnable() { 980 @Override 981 public void run() { 982 clearCache(includeDiskFiles); 983 } 984 }); 985 return; 986 } 987 mAwContents.clearCache(includeDiskFiles); 988 } 989 990 /** 991 * This is a poorly named method, but we keep it for historical reasons. 992 */ 993 @Override 994 public void clearFormData() { 995 if (!ThreadUtils.runningOnUiThread()) { 996 ThreadUtils.postOnUiThread(new Runnable() { 997 @Override 998 public void run() { 999 clearFormData(); 1000 } 1001 }); 1002 return; 1003 } 1004 mAwContents.hideAutofillPopup(); 1005 } 1006 1007 @Override 1008 public void clearHistory() { 1009 if (!ThreadUtils.runningOnUiThread()) { 1010 ThreadUtils.postOnUiThread(new Runnable() { 1011 @Override 1012 public void run() { 1013 clearHistory(); 1014 } 1015 }); 1016 return; 1017 } 1018 mAwContents.clearHistory(); 1019 } 1020 1021 @Override 1022 public void clearSslPreferences() { 1023 if (!ThreadUtils.runningOnUiThread()) { 1024 ThreadUtils.postOnUiThread(new Runnable() { 1025 @Override 1026 public void run() { 1027 clearSslPreferences(); 1028 } 1029 }); 1030 return; 1031 } 1032 mAwContents.clearSslPreferences(); 1033 } 1034 1035 @Override 1036 public WebBackForwardList copyBackForwardList() { 1037 if (!ThreadUtils.runningOnUiThread()) { 1038 WebBackForwardList ret = runOnUiThreadBlocking(new Callable<WebBackForwardList>() { 1039 @Override 1040 public WebBackForwardList call() { 1041 return copyBackForwardList(); 1042 } 1043 }); 1044 return ret; 1045 } 1046 return new WebBackForwardListChromium( 1047 mAwContents.getNavigationHistory()); 1048 } 1049 1050 @Override 1051 public void setFindListener(WebView.FindListener listener) { 1052 mContentsClientAdapter.setFindListener(listener); 1053 } 1054 1055 @Override 1056 public void findNext(final boolean forwards) { 1057 if (!ThreadUtils.runningOnUiThread()) { 1058 ThreadUtils.postOnUiThread(new Runnable() { 1059 @Override 1060 public void run() { 1061 findNext(forwards); 1062 } 1063 }); 1064 return; 1065 } 1066 mAwContents.findNext(forwards); 1067 } 1068 1069 @Override 1070 public int findAll(final String searchString) { 1071 findAllAsync(searchString); 1072 return 0; 1073 } 1074 1075 @Override 1076 public void findAllAsync(final String searchString) { 1077 if (!ThreadUtils.runningOnUiThread()) { 1078 ThreadUtils.postOnUiThread(new Runnable() { 1079 @Override 1080 public void run() { 1081 findAllAsync(searchString); 1082 } 1083 }); 1084 return; 1085 } 1086 mAwContents.findAllAsync(searchString); 1087 } 1088 1089 @Override 1090 public boolean showFindDialog(final String text, final boolean showIme) { 1091 if (!ThreadUtils.runningOnUiThread()) { 1092 return false; 1093 } 1094 if (mWebView.getParent() == null) { 1095 return false; 1096 } 1097 1098 FindActionModeCallback findAction = new FindActionModeCallback(mWebView.getContext()); 1099 if (findAction == null) { 1100 return false; 1101 } 1102 1103 mWebView.startActionMode(findAction); 1104 findAction.setWebView(mWebView); 1105 if (showIme) { 1106 findAction.showSoftInput(); 1107 } 1108 1109 if (text != null) { 1110 findAction.setText(text); 1111 findAction.findAll(); 1112 } 1113 1114 return true; 1115 } 1116 1117 @Override 1118 public void notifyFindDialogDismissed() { 1119 if (!ThreadUtils.runningOnUiThread()) { 1120 ThreadUtils.postOnUiThread(new Runnable() { 1121 @Override 1122 public void run() { 1123 notifyFindDialogDismissed(); 1124 } 1125 }); 1126 return; 1127 } 1128 clearMatches(); 1129 } 1130 1131 @Override 1132 public void clearMatches() { 1133 if (!ThreadUtils.runningOnUiThread()) { 1134 ThreadUtils.postOnUiThread(new Runnable() { 1135 @Override 1136 public void run() { 1137 clearMatches(); 1138 } 1139 }); 1140 return; 1141 } 1142 mAwContents.clearMatches(); 1143 } 1144 1145 @Override 1146 public void documentHasImages(final Message response) { 1147 if (!ThreadUtils.runningOnUiThread()) { 1148 ThreadUtils.postOnUiThread(new Runnable() { 1149 @Override 1150 public void run() { 1151 documentHasImages(response); 1152 } 1153 }); 1154 return; 1155 } 1156 mAwContents.documentHasImages(response); 1157 } 1158 1159 @Override 1160 public void setWebViewClient(WebViewClient client) { 1161 mContentsClientAdapter.setWebViewClient(client); 1162 } 1163 1164 @Override 1165 public void setDownloadListener(DownloadListener listener) { 1166 mContentsClientAdapter.setDownloadListener(listener); 1167 } 1168 1169 @Override 1170 public void setWebChromeClient(WebChromeClient client) { 1171 mContentsClientAdapter.setWebChromeClient(client); 1172 } 1173 1174 @Override 1175 public void setPictureListener(final WebView.PictureListener listener) { 1176 if (!ThreadUtils.runningOnUiThread()) { 1177 ThreadUtils.postOnUiThread(new Runnable() { 1178 @Override 1179 public void run() { 1180 setPictureListener(listener); 1181 } 1182 }); 1183 return; 1184 } 1185 mContentsClientAdapter.setPictureListener(listener); 1186 mAwContents.enableOnNewPicture(listener != null, 1187 mAppTargetSdkVersion >= Build.VERSION_CODES.JELLY_BEAN_MR2); 1188 } 1189 1190 @Override 1191 public void addJavascriptInterface(final Object obj, final String interfaceName) { 1192 if (!ThreadUtils.runningOnUiThread()) { 1193 ThreadUtils.postOnUiThread(new Runnable() { 1194 @Override 1195 public void run() { 1196 addJavascriptInterface(obj, interfaceName); 1197 } 1198 }); 1199 return; 1200 } 1201 Class<? extends Annotation> requiredAnnotation = null; 1202 if (mAppTargetSdkVersion >= Build.VERSION_CODES.JELLY_BEAN_MR1) { 1203 requiredAnnotation = JavascriptInterface.class; 1204 } 1205 mAwContents.addPossiblyUnsafeJavascriptInterface(obj, interfaceName, requiredAnnotation); 1206 } 1207 1208 @Override 1209 public void removeJavascriptInterface(final String interfaceName) { 1210 if (!ThreadUtils.runningOnUiThread()) { 1211 ThreadUtils.postOnUiThread(new Runnable() { 1212 @Override 1213 public void run() { 1214 removeJavascriptInterface(interfaceName); 1215 } 1216 }); 1217 return; 1218 } 1219 mAwContents.removeJavascriptInterface(interfaceName); 1220 } 1221 1222 @Override 1223 public WebSettings getSettings() { 1224 return mWebSettings; 1225 } 1226 1227 @Override 1228 public void setMapTrackballToArrowKeys(boolean setMap) { 1229 // This is a deprecated API: intentional no-op. 1230 } 1231 1232 @Override 1233 public void flingScroll(final int vx, final int vy) { 1234 if (!ThreadUtils.runningOnUiThread()) { 1235 ThreadUtils.postOnUiThread(new Runnable() { 1236 @Override 1237 public void run() { 1238 flingScroll(vx, vy); 1239 } 1240 }); 1241 return; 1242 } 1243 mAwContents.flingScroll(vx, vy); 1244 } 1245 1246 @Override 1247 public View getZoomControls() { 1248 if (!ThreadUtils.runningOnUiThread()) { 1249 return null; 1250 } 1251 1252 // This was deprecated in 2009 and hidden in JB MR1, so just provide the minimum needed 1253 // to stop very out-dated applications from crashing. 1254 Log.w(TAG, "WebView doesn't support getZoomControls"); 1255 return mAwContents.getSettings().supportZoom() ? new View(mWebView.getContext()) : null; 1256 } 1257 1258 @Override 1259 public boolean canZoomIn() { 1260 if (!ThreadUtils.runningOnUiThread()) { 1261 return false; 1262 } 1263 return mAwContents.canZoomIn(); 1264 } 1265 1266 @Override 1267 public boolean canZoomOut() { 1268 if (!ThreadUtils.runningOnUiThread()) { 1269 return false; 1270 } 1271 return mAwContents.canZoomOut(); 1272 } 1273 1274 @Override 1275 public boolean zoomIn() { 1276 if (!ThreadUtils.runningOnUiThread()) { 1277 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1278 @Override 1279 public Boolean call() { 1280 return zoomIn(); 1281 } 1282 }); 1283 return ret; 1284 } 1285 return mAwContents.zoomIn(); 1286 } 1287 1288 @Override 1289 public boolean zoomOut() { 1290 if (!ThreadUtils.runningOnUiThread()) { 1291 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1292 @Override 1293 public Boolean call() { 1294 return zoomOut(); 1295 } 1296 }); 1297 return ret; 1298 } 1299 return mAwContents.zoomOut(); 1300 } 1301 1302 @Override 1303 public void dumpViewHierarchyWithProperties(BufferedWriter out, int level) { 1304 // Intentional no-op 1305 } 1306 1307 @Override 1308 public View findHierarchyView(String className, int hashCode) { 1309 // Intentional no-op 1310 return null; 1311 } 1312 1313 // WebViewProvider glue methods --------------------------------------------------------------- 1314 1315 @Override 1316 // This needs to be kept thread safe! 1317 public WebViewProvider.ViewDelegate getViewDelegate() { 1318 return this; 1319 } 1320 1321 @Override 1322 // This needs to be kept thread safe! 1323 public WebViewProvider.ScrollDelegate getScrollDelegate() { 1324 return this; 1325 } 1326 1327 1328 // WebViewProvider.ViewDelegate implementation ------------------------------------------------ 1329 1330 // TODO: remove from WebViewProvider and use default implementation from 1331 // ViewGroup. 1332 // @Override 1333 public boolean shouldDelayChildPressedState() { 1334 if (!ThreadUtils.runningOnUiThread()) { 1335 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1336 @Override 1337 public Boolean call() { 1338 return shouldDelayChildPressedState(); 1339 } 1340 }); 1341 return ret; 1342 } 1343 return true; 1344 } 1345 1346// @Override 1347 public AccessibilityNodeProvider getAccessibilityNodeProvider() { 1348 if (!ThreadUtils.runningOnUiThread()) { 1349 AccessibilityNodeProvider ret = runOnUiThreadBlocking( 1350 new Callable<AccessibilityNodeProvider>() { 1351 @Override 1352 public AccessibilityNodeProvider call() { 1353 return getAccessibilityNodeProvider(); 1354 } 1355 }); 1356 return ret; 1357 } 1358 return mAwContents.getAccessibilityNodeProvider(); 1359 } 1360 1361 @Override 1362 public void onInitializeAccessibilityNodeInfo(final AccessibilityNodeInfo info) { 1363 if (!ThreadUtils.runningOnUiThread()) { 1364 runVoidTaskOnUiThreadBlocking(new Runnable() { 1365 @Override 1366 public void run() { 1367 onInitializeAccessibilityNodeInfo(info); 1368 } 1369 }); 1370 return; 1371 } 1372 mAwContents.onInitializeAccessibilityNodeInfo(info); 1373 } 1374 1375 @Override 1376 public void onInitializeAccessibilityEvent(final AccessibilityEvent event) { 1377 if (!ThreadUtils.runningOnUiThread()) { 1378 runVoidTaskOnUiThreadBlocking(new Runnable() { 1379 @Override 1380 public void run() { 1381 onInitializeAccessibilityEvent(event); 1382 } 1383 }); 1384 return; 1385 } 1386 mAwContents.onInitializeAccessibilityEvent(event); 1387 } 1388 1389 @Override 1390 public boolean performAccessibilityAction(final int action, final Bundle arguments) { 1391 if (!ThreadUtils.runningOnUiThread()) { 1392 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1393 @Override 1394 public Boolean call() { 1395 return performAccessibilityAction(action, arguments); 1396 } 1397 }); 1398 return ret; 1399 } 1400 if (mAwContents.supportsAccessibilityAction(action)) { 1401 return mAwContents.performAccessibilityAction(action, arguments); 1402 } 1403 return mWebViewPrivate.super_performAccessibilityAction(action, arguments); 1404 } 1405 1406 @Override 1407 public void setOverScrollMode(final int mode) { 1408 if (!ThreadUtils.runningOnUiThread()) { 1409 ThreadUtils.postOnUiThread(new Runnable() { 1410 @Override 1411 public void run() { 1412 setOverScrollMode(mode); 1413 } 1414 }); 1415 return; 1416 } 1417 // This gets called from the android.view.View c'tor that WebView inherits from. This 1418 // causes the method to be called when mAwContents == null. 1419 // It's safe to ignore these calls however since AwContents will read the current value of 1420 // this setting when it's created. 1421 if (mAwContents != null) { 1422 mAwContents.setOverScrollMode(mode); 1423 } 1424 } 1425 1426 @Override 1427 public void setScrollBarStyle(final int style) { 1428 if (!ThreadUtils.runningOnUiThread()) { 1429 ThreadUtils.postOnUiThread(new Runnable() { 1430 @Override 1431 public void run() { 1432 setScrollBarStyle(style); 1433 } 1434 }); 1435 return; 1436 } 1437 mAwContents.setScrollBarStyle(style); 1438 } 1439 1440 @Override 1441 public void onDrawVerticalScrollBar(final Canvas canvas, final Drawable scrollBar, final int l, 1442 final int t, final int r, final int b) { 1443 if (!ThreadUtils.runningOnUiThread()) { 1444 runVoidTaskOnUiThreadBlocking(new Runnable() { 1445 @Override 1446 public void run() { 1447 onDrawVerticalScrollBar(canvas, scrollBar, l, t, r, b); 1448 } 1449 }); 1450 return; 1451 } 1452 // WebViewClassic was overriding this method to handle rubberband over-scroll. Since 1453 // WebViewChromium doesn't support that the vanilla implementation of this method can be 1454 // used. 1455 mWebViewPrivate.super_onDrawVerticalScrollBar(canvas, scrollBar, l, t, r, b); 1456 } 1457 1458 @Override 1459 public void onOverScrolled(final int scrollX, final int scrollY, final boolean clampedX, 1460 final boolean clampedY) { 1461 if (!ThreadUtils.runningOnUiThread()) { 1462 ThreadUtils.postOnUiThread(new Runnable() { 1463 @Override 1464 public void run() { 1465 onOverScrolled(scrollX, scrollY, clampedX, clampedY); 1466 } 1467 }); 1468 return; 1469 } 1470 mAwContents.onContainerViewOverScrolled(scrollX, scrollY, clampedX, clampedY); 1471 } 1472 1473 @Override 1474 public void onWindowVisibilityChanged(final int visibility) { 1475 if (!ThreadUtils.runningOnUiThread()) { 1476 ThreadUtils.postOnUiThread(new Runnable() { 1477 @Override 1478 public void run() { 1479 onWindowVisibilityChanged(visibility); 1480 } 1481 }); 1482 return; 1483 } 1484 mAwContents.onWindowVisibilityChanged(visibility); 1485 } 1486 1487 @Override 1488 public void onDraw(final Canvas canvas) { 1489 if (!ThreadUtils.runningOnUiThread()) { 1490 runVoidTaskOnUiThreadBlocking(new Runnable() { 1491 @Override 1492 public void run() { 1493 onDraw(canvas); 1494 } 1495 }); 1496 return; 1497 } 1498 mAwContents.onDraw(canvas); 1499 } 1500 1501 @Override 1502 public void setLayoutParams(final ViewGroup.LayoutParams layoutParams) { 1503 if (!ThreadUtils.runningOnUiThread()) { 1504 ThreadUtils.postOnUiThread(new Runnable() { 1505 @Override 1506 public void run() { 1507 setLayoutParams(layoutParams); 1508 } 1509 }); 1510 return; 1511 } 1512 mWebViewPrivate.super_setLayoutParams(layoutParams); 1513 } 1514 1515 @Override 1516 public boolean performLongClick() { 1517 if (!ThreadUtils.runningOnUiThread()) { 1518 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1519 @Override 1520 public Boolean call() { 1521 return performLongClick(); 1522 } 1523 }); 1524 return ret; 1525 } 1526 return mWebViewPrivate.super_performLongClick(); 1527 } 1528 1529 @Override 1530 public void onConfigurationChanged(final Configuration newConfig) { 1531 if (!ThreadUtils.runningOnUiThread()) { 1532 ThreadUtils.postOnUiThread(new Runnable() { 1533 @Override 1534 public void run() { 1535 onConfigurationChanged(newConfig); 1536 } 1537 }); 1538 return; 1539 } 1540 mAwContents.onConfigurationChanged(newConfig); 1541 } 1542 1543 @Override 1544 public InputConnection onCreateInputConnection(final EditorInfo outAttrs) { 1545 if (!ThreadUtils.runningOnUiThread()) { 1546 InputConnection ret = runOnUiThreadBlocking(new Callable<InputConnection>() { 1547 @Override 1548 public InputConnection call() { 1549 return onCreateInputConnection(outAttrs); 1550 } 1551 }); 1552 return ret; 1553 } 1554 return mAwContents.onCreateInputConnection(outAttrs); 1555 } 1556 1557 @Override 1558 public boolean onKeyMultiple(final int keyCode, final int repeatCount, final KeyEvent event) { 1559 if (!ThreadUtils.runningOnUiThread()) { 1560 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1561 @Override 1562 public Boolean call() { 1563 return onKeyMultiple(keyCode, repeatCount, event); 1564 } 1565 }); 1566 return ret; 1567 } 1568 UnimplementedWebViewApi.invoke(); 1569 return false; 1570 } 1571 1572 @Override 1573 public boolean onKeyDown(final int keyCode, final KeyEvent event) { 1574 if (!ThreadUtils.runningOnUiThread()) { 1575 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1576 @Override 1577 public Boolean call() { 1578 return onKeyDown(keyCode, event); 1579 } 1580 }); 1581 return ret; 1582 } 1583 UnimplementedWebViewApi.invoke(); 1584 return false; 1585 } 1586 1587 @Override 1588 public boolean onKeyUp(final int keyCode, final KeyEvent event) { 1589 if (!ThreadUtils.runningOnUiThread()) { 1590 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1591 @Override 1592 public Boolean call() { 1593 return onKeyUp(keyCode, event); 1594 } 1595 }); 1596 return ret; 1597 } 1598 return mAwContents.onKeyUp(keyCode, event); 1599 } 1600 1601 @Override 1602 public void onAttachedToWindow() { 1603 if (!ThreadUtils.runningOnUiThread()) { 1604 ThreadUtils.postOnUiThread(new Runnable() { 1605 @Override 1606 public void run() { 1607 onAttachedToWindow(); 1608 } 1609 }); 1610 return; 1611 } 1612 mAwContents.onAttachedToWindow(); 1613 } 1614 1615 @Override 1616 public void onDetachedFromWindow() { 1617 if (!ThreadUtils.runningOnUiThread()) { 1618 ThreadUtils.postOnUiThread(new Runnable() { 1619 @Override 1620 public void run() { 1621 onDetachedFromWindow(); 1622 } 1623 }); 1624 return; 1625 } 1626 mAwContents.onDetachedFromWindow(); 1627 if (mGLfunctor != null) { 1628 mGLfunctor.detach(); 1629 } 1630 } 1631 1632 @Override 1633 public void onVisibilityChanged(final View changedView, final int visibility) { 1634 if (!ThreadUtils.runningOnUiThread()) { 1635 ThreadUtils.postOnUiThread(new Runnable() { 1636 @Override 1637 public void run() { 1638 onVisibilityChanged(changedView, visibility); 1639 } 1640 }); 1641 return; 1642 } 1643 // The AwContents will find out the container view visibility before the first draw so we 1644 // can safely ignore onVisibilityChanged callbacks that happen before init(). 1645 if (mAwContents != null) { 1646 mAwContents.onVisibilityChanged(changedView, visibility); 1647 } 1648 } 1649 1650 @Override 1651 public void onWindowFocusChanged(final boolean hasWindowFocus) { 1652 if (!ThreadUtils.runningOnUiThread()) { 1653 ThreadUtils.postOnUiThread(new Runnable() { 1654 @Override 1655 public void run() { 1656 onWindowFocusChanged(hasWindowFocus); 1657 } 1658 }); 1659 return; 1660 } 1661 mAwContents.onWindowFocusChanged(hasWindowFocus); 1662 } 1663 1664 @Override 1665 public void onFocusChanged(final boolean focused, final int direction, 1666 final Rect previouslyFocusedRect) { 1667 if (!ThreadUtils.runningOnUiThread()) { 1668 ThreadUtils.postOnUiThread(new Runnable() { 1669 @Override 1670 public void run() { 1671 onFocusChanged(focused, direction, previouslyFocusedRect); 1672 } 1673 }); 1674 return; 1675 } 1676 mAwContents.onFocusChanged(focused, direction, previouslyFocusedRect); 1677 } 1678 1679 @Override 1680 public boolean setFrame(final int left, final int top, final int right, final int bottom) { 1681 if (!ThreadUtils.runningOnUiThread()) { 1682 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1683 @Override 1684 public Boolean call() { 1685 return setFrame(left, top, right, bottom); 1686 } 1687 }); 1688 return ret; 1689 } 1690 return mWebViewPrivate.super_setFrame(left, top, right, bottom); 1691 } 1692 1693 @Override 1694 public void onSizeChanged(final int w, final int h, final int ow, final int oh) { 1695 if (!ThreadUtils.runningOnUiThread()) { 1696 ThreadUtils.postOnUiThread(new Runnable() { 1697 @Override 1698 public void run() { 1699 onSizeChanged(w, h, ow, oh); 1700 } 1701 }); 1702 return; 1703 } 1704 mAwContents.onSizeChanged(w, h, ow, oh); 1705 } 1706 1707 @Override 1708 public void onScrollChanged(int l, int t, int oldl, int oldt) { 1709 } 1710 1711 @Override 1712 public boolean dispatchKeyEvent(final KeyEvent event) { 1713 if (!ThreadUtils.runningOnUiThread()) { 1714 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1715 @Override 1716 public Boolean call() { 1717 return dispatchKeyEvent(event); 1718 } 1719 }); 1720 return ret; 1721 } 1722 return mAwContents.dispatchKeyEvent(event); 1723 } 1724 1725 @Override 1726 public boolean onTouchEvent(final MotionEvent ev) { 1727 if (!ThreadUtils.runningOnUiThread()) { 1728 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1729 @Override 1730 public Boolean call() { 1731 return onTouchEvent(ev); 1732 } 1733 }); 1734 return ret; 1735 } 1736 return mAwContents.onTouchEvent(ev); 1737 } 1738 1739 @Override 1740 public boolean onHoverEvent(final MotionEvent event) { 1741 if (!ThreadUtils.runningOnUiThread()) { 1742 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1743 @Override 1744 public Boolean call() { 1745 return onHoverEvent(event); 1746 } 1747 }); 1748 return ret; 1749 } 1750 return mAwContents.onHoverEvent(event); 1751 } 1752 1753 @Override 1754 public boolean onGenericMotionEvent(final MotionEvent event) { 1755 if (!ThreadUtils.runningOnUiThread()) { 1756 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1757 @Override 1758 public Boolean call() { 1759 return onGenericMotionEvent(event); 1760 } 1761 }); 1762 return ret; 1763 } 1764 return mAwContents.onGenericMotionEvent(event); 1765 } 1766 1767 @Override 1768 public boolean onTrackballEvent(MotionEvent ev) { 1769 // Trackball event not handled, which eventually gets converted to DPAD keyevents 1770 return false; 1771 } 1772 1773 @Override 1774 public boolean requestFocus(final int direction, final Rect previouslyFocusedRect) { 1775 if (!ThreadUtils.runningOnUiThread()) { 1776 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1777 @Override 1778 public Boolean call() { 1779 return requestFocus(direction, previouslyFocusedRect); 1780 } 1781 }); 1782 return ret; 1783 } 1784 mAwContents.requestFocus(); 1785 return mWebViewPrivate.super_requestFocus(direction, previouslyFocusedRect); 1786 } 1787 1788 @Override 1789 public void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) { 1790 if (!ThreadUtils.runningOnUiThread()) { 1791 ThreadUtils.postOnUiThread(new Runnable() { 1792 @Override 1793 public void run() { 1794 onMeasure(widthMeasureSpec, heightMeasureSpec); 1795 } 1796 }); 1797 return; 1798 } 1799 mAwContents.onMeasure(widthMeasureSpec, heightMeasureSpec); 1800 } 1801 1802 @Override 1803 public boolean requestChildRectangleOnScreen(final View child, final Rect rect, 1804 final boolean immediate) { 1805 if (!ThreadUtils.runningOnUiThread()) { 1806 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1807 @Override 1808 public Boolean call() { 1809 return requestChildRectangleOnScreen(child, rect, immediate); 1810 } 1811 }); 1812 return ret; 1813 } 1814 return mAwContents.requestChildRectangleOnScreen(child, rect, immediate); 1815 } 1816 1817 @Override 1818 public void setBackgroundColor(final int color) { 1819 if (!ThreadUtils.runningOnUiThread()) { 1820 ThreadUtils.postOnUiThread(new Runnable() { 1821 @Override 1822 public void run() { 1823 setBackgroundColor(color); 1824 } 1825 }); 1826 return; 1827 } 1828 mAwContents.setBackgroundColor(color); 1829 } 1830 1831 @Override 1832 public void setLayerType(int layerType, Paint paint) { 1833 // Intentional no-op 1834 } 1835 1836 // Remove from superclass 1837 public void preDispatchDraw(Canvas canvas) { 1838 // TODO(leandrogracia): remove this method from WebViewProvider if we think 1839 // we won't need it again. 1840 } 1841 1842 // WebViewProvider.ScrollDelegate implementation ---------------------------------------------- 1843 1844 @Override 1845 public int computeHorizontalScrollRange() { 1846 if (!ThreadUtils.runningOnUiThread()) { 1847 int ret = runOnUiThreadBlocking(new Callable<Integer>() { 1848 @Override 1849 public Integer call() { 1850 return computeHorizontalScrollRange(); 1851 } 1852 }); 1853 return ret; 1854 } 1855 return mAwContents.computeHorizontalScrollRange(); 1856 } 1857 1858 @Override 1859 public int computeHorizontalScrollOffset() { 1860 if (!ThreadUtils.runningOnUiThread()) { 1861 int ret = runOnUiThreadBlocking(new Callable<Integer>() { 1862 @Override 1863 public Integer call() { 1864 return computeHorizontalScrollOffset(); 1865 } 1866 }); 1867 return ret; 1868 } 1869 return mAwContents.computeHorizontalScrollOffset(); 1870 } 1871 1872 @Override 1873 public int computeVerticalScrollRange() { 1874 if (!ThreadUtils.runningOnUiThread()) { 1875 int ret = runOnUiThreadBlocking(new Callable<Integer>() { 1876 @Override 1877 public Integer call() { 1878 return computeVerticalScrollRange(); 1879 } 1880 }); 1881 return ret; 1882 } 1883 return mAwContents.computeVerticalScrollRange(); 1884 } 1885 1886 @Override 1887 public int computeVerticalScrollOffset() { 1888 if (!ThreadUtils.runningOnUiThread()) { 1889 int ret = runOnUiThreadBlocking(new Callable<Integer>() { 1890 @Override 1891 public Integer call() { 1892 return computeVerticalScrollOffset(); 1893 } 1894 }); 1895 return ret; 1896 } 1897 return mAwContents.computeVerticalScrollOffset(); 1898 } 1899 1900 @Override 1901 public int computeVerticalScrollExtent() { 1902 if (!ThreadUtils.runningOnUiThread()) { 1903 int ret = runOnUiThreadBlocking(new Callable<Integer>() { 1904 @Override 1905 public Integer call() { 1906 return computeVerticalScrollExtent(); 1907 } 1908 }); 1909 return ret; 1910 } 1911 return mAwContents.computeVerticalScrollExtent(); 1912 } 1913 1914 @Override 1915 public void computeScroll() { 1916 if (!ThreadUtils.runningOnUiThread()) { 1917 ThreadUtils.postOnUiThread(new Runnable() { 1918 @Override 1919 public void run() { 1920 computeScroll(); 1921 } 1922 }); 1923 return; 1924 } 1925 mAwContents.computeScroll(); 1926 } 1927 1928 // AwContents.InternalAccessDelegate implementation -------------------------------------- 1929 private class InternalAccessAdapter implements AwContents.InternalAccessDelegate { 1930 @Override 1931 public boolean drawChild(Canvas arg0, View arg1, long arg2) { 1932 UnimplementedWebViewApi.invoke(); 1933 return false; 1934 } 1935 1936 @Override 1937 public boolean super_onKeyUp(int arg0, KeyEvent arg1) { 1938 // Intentional no-op 1939 return false; 1940 } 1941 1942 @Override 1943 public boolean super_dispatchKeyEventPreIme(KeyEvent arg0) { 1944 UnimplementedWebViewApi.invoke(); 1945 return false; 1946 } 1947 1948 @Override 1949 public boolean super_dispatchKeyEvent(KeyEvent event) { 1950 return mWebViewPrivate.super_dispatchKeyEvent(event); 1951 } 1952 1953 @Override 1954 public boolean super_onGenericMotionEvent(MotionEvent arg0) { 1955 UnimplementedWebViewApi.invoke(); 1956 return false; 1957 } 1958 1959 @Override 1960 public void super_onConfigurationChanged(Configuration arg0) { 1961 // Intentional no-op 1962 } 1963 1964 @Override 1965 public int super_getScrollBarStyle() { 1966 return mWebViewPrivate.super_getScrollBarStyle(); 1967 } 1968 1969 @Override 1970 public boolean awakenScrollBars() { 1971 mWebViewPrivate.awakenScrollBars(0); 1972 // TODO: modify the WebView.PrivateAccess to provide a return value. 1973 return true; 1974 } 1975 1976 @Override 1977 public boolean super_awakenScrollBars(int arg0, boolean arg1) { 1978 // TODO: need method on WebView.PrivateAccess? 1979 UnimplementedWebViewApi.invoke(); 1980 return false; 1981 } 1982 1983 @Override 1984 public void onScrollChanged(int l, int t, int oldl, int oldt) { 1985 mWebViewPrivate.setScrollXRaw(l); 1986 mWebViewPrivate.setScrollYRaw(t); 1987 mWebViewPrivate.onScrollChanged(l, t, oldl, oldt); 1988 } 1989 1990 @Override 1991 public void overScrollBy(int deltaX, int deltaY, 1992 int scrollX, int scrollY, 1993 int scrollRangeX, int scrollRangeY, 1994 int maxOverScrollX, int maxOverScrollY, 1995 boolean isTouchEvent) { 1996 mWebViewPrivate.overScrollBy(deltaX, deltaY, scrollX, scrollY, 1997 scrollRangeX, scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent); 1998 } 1999 2000 @Override 2001 public void super_scrollTo(int scrollX, int scrollY) { 2002 mWebViewPrivate.super_scrollTo(scrollX, scrollY); 2003 } 2004 2005 @Override 2006 public void setMeasuredDimension(int measuredWidth, int measuredHeight) { 2007 mWebViewPrivate.setMeasuredDimension(measuredWidth, measuredHeight); 2008 } 2009 2010 @Override 2011 public boolean requestDrawGL(Canvas canvas) { 2012 if (mGLfunctor == null) { 2013 mGLfunctor = new DrawGLFunctor(mAwContents.getAwDrawGLViewContext()); 2014 } 2015 return mGLfunctor.requestDrawGL((HardwareCanvas)canvas, mWebView.getViewRootImpl()); 2016 } 2017 } 2018} 2019