WebViewChromium.java revision 446527cc7e4f0a5df72ca9c4d68753a698e2895b
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("Calling View methods on another thread than the UI " + 197 "thread. PLEASE FILE A BUG! go/klp-webview-bug"); 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 505 private void loadUrlOnUiThread(final LoadUrlParams loadUrlParams) { 506 if (ThreadUtils.runningOnUiThread()) { 507 mAwContents.loadUrl(loadUrlParams); 508 } else { 509 // Disallowed in WebView API for apps targetting a new SDK 510 assert mAppTargetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2; 511 ThreadUtils.postOnUiThread(new Runnable() { 512 @Override 513 public void run() { 514 mAwContents.loadUrl(loadUrlParams); 515 } 516 }); 517 } 518 } 519 520 public void evaluateJavaScript(String script, ValueCallback<String> resultCallback) { 521 checkThread(); 522 mAwContents.evaluateJavaScript(script, resultCallback); 523 } 524 525 @Override 526 public void saveWebArchive(String filename) { 527 saveWebArchive(filename, false, null); 528 } 529 530 @Override 531 public void saveWebArchive(final String basename, final boolean autoname, 532 final ValueCallback<String> callback) { 533 if (!ThreadUtils.runningOnUiThread()) { 534 ThreadUtils.postOnUiThread(new Runnable() { 535 @Override 536 public void run() { 537 saveWebArchive(basename, autoname, callback); 538 } 539 }); 540 return; 541 } 542 mAwContents.saveWebArchive(basename, autoname, callback); 543 } 544 545 @Override 546 public void stopLoading() { 547 if (!ThreadUtils.runningOnUiThread()) { 548 ThreadUtils.postOnUiThread(new Runnable() { 549 @Override 550 public void run() { 551 stopLoading(); 552 } 553 }); 554 return; 555 } 556 557 mAwContents.stopLoading(); 558 } 559 560 @Override 561 public void reload() { 562 if (!ThreadUtils.runningOnUiThread()) { 563 ThreadUtils.postOnUiThread(new Runnable() { 564 @Override 565 public void run() { 566 reload(); 567 } 568 }); 569 return; 570 } 571 mAwContents.reload(); 572 } 573 574 @Override 575 public boolean canGoBack() { 576 if (!ThreadUtils.runningOnUiThread()) { 577 Boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 578 @Override 579 public Boolean call() { 580 return canGoBack(); 581 } 582 }); 583 return ret; 584 } 585 return mAwContents.canGoBack(); 586 } 587 588 @Override 589 public void goBack() { 590 if (!ThreadUtils.runningOnUiThread()) { 591 ThreadUtils.postOnUiThread(new Runnable() { 592 @Override 593 public void run() { 594 goBack(); 595 } 596 }); 597 return; 598 } 599 mAwContents.goBack(); 600 } 601 602 @Override 603 public boolean canGoForward() { 604 if (!ThreadUtils.runningOnUiThread()) { 605 Boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 606 @Override 607 public Boolean call() { 608 return canGoForward(); 609 } 610 }); 611 return ret; 612 } 613 return mAwContents.canGoForward(); 614 } 615 616 @Override 617 public void goForward() { 618 if (!ThreadUtils.runningOnUiThread()) { 619 ThreadUtils.postOnUiThread(new Runnable() { 620 @Override 621 public void run() { 622 goForward(); 623 } 624 }); 625 return; 626 } 627 mAwContents.goForward(); 628 } 629 630 @Override 631 public boolean canGoBackOrForward(final int steps) { 632 if (!ThreadUtils.runningOnUiThread()) { 633 Boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 634 @Override 635 public Boolean call() { 636 return canGoBackOrForward(steps); 637 } 638 }); 639 return ret; 640 } 641 return mAwContents.canGoBackOrForward(steps); 642 } 643 644 @Override 645 public void goBackOrForward(final int steps) { 646 if (!ThreadUtils.runningOnUiThread()) { 647 ThreadUtils.postOnUiThread(new Runnable() { 648 @Override 649 public void run() { 650 goBackOrForward(steps); 651 } 652 }); 653 return; 654 } 655 mAwContents.goBackOrForward(steps); 656 } 657 658 @Override 659 public boolean isPrivateBrowsingEnabled() { 660 // Not supported in this WebView implementation. 661 return false; 662 } 663 664 @Override 665 public boolean pageUp(final boolean top) { 666 if (!ThreadUtils.runningOnUiThread()) { 667 Boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 668 @Override 669 public Boolean call() { 670 return pageUp(top); 671 } 672 }); 673 return ret; 674 } 675 return mAwContents.pageUp(top); 676 } 677 678 @Override 679 public boolean pageDown(final boolean bottom) { 680 if (!ThreadUtils.runningOnUiThread()) { 681 Boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 682 @Override 683 public Boolean call() { 684 return pageDown(bottom); 685 } 686 }); 687 return ret; 688 } 689 return mAwContents.pageDown(bottom); 690 } 691 692 @Override 693 public void clearView() { 694 if (!ThreadUtils.runningOnUiThread()) { 695 ThreadUtils.postOnUiThread(new Runnable() { 696 @Override 697 public void run() { 698 clearView(); 699 } 700 }); 701 return; 702 } 703 UnimplementedWebViewApi.invoke(); 704 } 705 706 @Override 707 public Picture capturePicture() { 708 if (!ThreadUtils.runningOnUiThread()) { 709 Picture ret = runOnUiThreadBlocking(new Callable<Picture>() { 710 @Override 711 public Picture call() { 712 return capturePicture(); 713 } 714 }); 715 return ret; 716 } 717 return mAwContents.capturePicture(); 718 } 719 720 @Override 721 public PrintDocumentAdapter createPrintDocumentAdapter() { 722 checkThread(); 723 // TODO(sgurun) fix this after upstream part lands 724 return null; 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