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