WebViewChromium.java revision a622984698ea393f81ce968ec87bab75087af7dc
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( 198 "Calling View methods on another thread than the UI thread."); 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 // Data url's with a base url will be resolved in Blink, and not cause an onPageStarted 506 // event to be sent. Sending the callback directly from here. 507 final String finalBaseUrl = loadUrlParams.getBaseUrl(); 508 ThreadUtils.postOnUiThread(new Runnable() { 509 @Override 510 public void run() { 511 mContentsClientAdapter.onPageStarted(finalBaseUrl); 512 } 513 }); 514 } 515 516 private void loadUrlOnUiThread(final LoadUrlParams loadUrlParams) { 517 if (ThreadUtils.runningOnUiThread()) { 518 mAwContents.loadUrl(loadUrlParams); 519 } else { 520 // Disallowed in WebView API for apps targetting a new SDK 521 assert mAppTargetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2; 522 ThreadUtils.postOnUiThread(new Runnable() { 523 @Override 524 public void run() { 525 mAwContents.loadUrl(loadUrlParams); 526 } 527 }); 528 } 529 } 530 531 public void evaluateJavaScript(String script, ValueCallback<String> resultCallback) { 532 checkThread(); 533 mAwContents.evaluateJavaScript(script, resultCallback); 534 } 535 536 @Override 537 public void saveWebArchive(String filename) { 538 saveWebArchive(filename, false, null); 539 } 540 541 @Override 542 public void saveWebArchive(final String basename, final boolean autoname, 543 final ValueCallback<String> callback) { 544 if (!ThreadUtils.runningOnUiThread()) { 545 ThreadUtils.postOnUiThread(new Runnable() { 546 @Override 547 public void run() { 548 saveWebArchive(basename, autoname, callback); 549 } 550 }); 551 return; 552 } 553 mAwContents.saveWebArchive(basename, autoname, callback); 554 } 555 556 @Override 557 public void stopLoading() { 558 if (!ThreadUtils.runningOnUiThread()) { 559 ThreadUtils.postOnUiThread(new Runnable() { 560 @Override 561 public void run() { 562 stopLoading(); 563 } 564 }); 565 return; 566 } 567 568 mAwContents.stopLoading(); 569 } 570 571 @Override 572 public void reload() { 573 if (!ThreadUtils.runningOnUiThread()) { 574 ThreadUtils.postOnUiThread(new Runnable() { 575 @Override 576 public void run() { 577 reload(); 578 } 579 }); 580 return; 581 } 582 mAwContents.reload(); 583 } 584 585 @Override 586 public boolean canGoBack() { 587 if (!ThreadUtils.runningOnUiThread()) { 588 Boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 589 @Override 590 public Boolean call() { 591 return canGoBack(); 592 } 593 }); 594 return ret; 595 } 596 return mAwContents.canGoBack(); 597 } 598 599 @Override 600 public void goBack() { 601 if (!ThreadUtils.runningOnUiThread()) { 602 ThreadUtils.postOnUiThread(new Runnable() { 603 @Override 604 public void run() { 605 goBack(); 606 } 607 }); 608 return; 609 } 610 mAwContents.goBack(); 611 } 612 613 @Override 614 public boolean canGoForward() { 615 if (!ThreadUtils.runningOnUiThread()) { 616 Boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 617 @Override 618 public Boolean call() { 619 return canGoForward(); 620 } 621 }); 622 return ret; 623 } 624 return mAwContents.canGoForward(); 625 } 626 627 @Override 628 public void goForward() { 629 if (!ThreadUtils.runningOnUiThread()) { 630 ThreadUtils.postOnUiThread(new Runnable() { 631 @Override 632 public void run() { 633 goForward(); 634 } 635 }); 636 return; 637 } 638 mAwContents.goForward(); 639 } 640 641 @Override 642 public boolean canGoBackOrForward(final int steps) { 643 if (!ThreadUtils.runningOnUiThread()) { 644 Boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 645 @Override 646 public Boolean call() { 647 return canGoBackOrForward(steps); 648 } 649 }); 650 return ret; 651 } 652 return mAwContents.canGoBackOrForward(steps); 653 } 654 655 @Override 656 public void goBackOrForward(final int steps) { 657 if (!ThreadUtils.runningOnUiThread()) { 658 ThreadUtils.postOnUiThread(new Runnable() { 659 @Override 660 public void run() { 661 goBackOrForward(steps); 662 } 663 }); 664 return; 665 } 666 mAwContents.goBackOrForward(steps); 667 } 668 669 @Override 670 public boolean isPrivateBrowsingEnabled() { 671 // Not supported in this WebView implementation. 672 return false; 673 } 674 675 @Override 676 public boolean pageUp(final boolean top) { 677 if (!ThreadUtils.runningOnUiThread()) { 678 Boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 679 @Override 680 public Boolean call() { 681 return pageUp(top); 682 } 683 }); 684 return ret; 685 } 686 return mAwContents.pageUp(top); 687 } 688 689 @Override 690 public boolean pageDown(final boolean bottom) { 691 if (!ThreadUtils.runningOnUiThread()) { 692 Boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 693 @Override 694 public Boolean call() { 695 return pageDown(bottom); 696 } 697 }); 698 return ret; 699 } 700 return mAwContents.pageDown(bottom); 701 } 702 703 @Override 704 public void clearView() { 705 if (!ThreadUtils.runningOnUiThread()) { 706 ThreadUtils.postOnUiThread(new Runnable() { 707 @Override 708 public void run() { 709 clearView(); 710 } 711 }); 712 return; 713 } 714 UnimplementedWebViewApi.invoke(); 715 } 716 717 @Override 718 public Picture capturePicture() { 719 if (!ThreadUtils.runningOnUiThread()) { 720 Picture ret = runOnUiThreadBlocking(new Callable<Picture>() { 721 @Override 722 public Picture call() { 723 return capturePicture(); 724 } 725 }); 726 return ret; 727 } 728 return mAwContents.capturePicture(); 729 } 730 731 @Override 732 public PrintDocumentAdapter createPrintDocumentAdapter() { 733 checkThread(); 734 return new AwPrintDocumentAdapter(mAwContents.getPdfExporter()); 735 } 736 737 @Override 738 public float getScale() { 739 // No checkThread() as it is mostly thread safe (workaround for b/10652991). 740 return mAwContents.getScale(); 741 } 742 743 @Override 744 public void setInitialScale(final int scaleInPercent) { 745 if (!ThreadUtils.runningOnUiThread()) { 746 ThreadUtils.postOnUiThread(new Runnable() { 747 @Override 748 public void run() { 749 setInitialScale(scaleInPercent); 750 } 751 }); 752 return; 753 } 754 mAwContents.getSettings().setInitialPageScale(scaleInPercent); 755 } 756 757 @Override 758 public void invokeZoomPicker() { 759 if (!ThreadUtils.runningOnUiThread()) { 760 ThreadUtils.postOnUiThread(new Runnable() { 761 @Override 762 public void run() { 763 invokeZoomPicker(); 764 } 765 }); 766 return; 767 } 768 mAwContents.invokeZoomPicker(); 769 } 770 771 @Override 772 public WebView.HitTestResult getHitTestResult() { 773 if (!ThreadUtils.runningOnUiThread()) { 774 WebView.HitTestResult ret = runOnUiThreadBlocking( 775 new Callable<WebView.HitTestResult>() { 776 @Override 777 public WebView.HitTestResult call() { 778 return getHitTestResult(); 779 } 780 }); 781 return ret; 782 } 783 AwContents.HitTestData data = mAwContents.getLastHitTestResult(); 784 mHitTestResult.setType(data.hitTestResultType); 785 mHitTestResult.setExtra(data.hitTestResultExtraData); 786 return mHitTestResult; 787 } 788 789 @Override 790 public void requestFocusNodeHref(final Message hrefMsg) { 791 if (!ThreadUtils.runningOnUiThread()) { 792 ThreadUtils.postOnUiThread(new Runnable() { 793 @Override 794 public void run() { 795 requestFocusNodeHref(hrefMsg); 796 } 797 }); 798 return; 799 } 800 mAwContents.requestFocusNodeHref(hrefMsg); 801 } 802 803 @Override 804 public void requestImageRef(final Message msg) { 805 if (!ThreadUtils.runningOnUiThread()) { 806 ThreadUtils.postOnUiThread(new Runnable() { 807 @Override 808 public void run() { 809 requestImageRef(msg); 810 } 811 }); 812 return; 813 } 814 mAwContents.requestImageRef(msg); 815 } 816 817 @Override 818 public String getUrl() { 819 if (!ThreadUtils.runningOnUiThread()) { 820 String ret = runOnUiThreadBlocking(new Callable<String>() { 821 @Override 822 public String call() { 823 return getUrl(); 824 } 825 }); 826 return ret; 827 } 828 String url = mAwContents.getUrl(); 829 if (url == null || url.trim().isEmpty()) return null; 830 return url; 831 } 832 833 @Override 834 public String getOriginalUrl() { 835 if (!ThreadUtils.runningOnUiThread()) { 836 String ret = runOnUiThreadBlocking(new Callable<String>() { 837 @Override 838 public String call() { 839 return getOriginalUrl(); 840 } 841 }); 842 return ret; 843 } 844 String url = mAwContents.getOriginalUrl(); 845 if (url == null || url.trim().isEmpty()) return null; 846 return url; 847 } 848 849 @Override 850 public String getTitle() { 851 if (!ThreadUtils.runningOnUiThread()) { 852 String ret = runOnUiThreadBlocking(new Callable<String>() { 853 @Override 854 public String call() { 855 return getTitle(); 856 } 857 }); 858 return ret; 859 } 860 return mAwContents.getTitle(); 861 } 862 863 @Override 864 public Bitmap getFavicon() { 865 if (!ThreadUtils.runningOnUiThread()) { 866 Bitmap ret = runOnUiThreadBlocking(new Callable<Bitmap>() { 867 @Override 868 public Bitmap call() { 869 return getFavicon(); 870 } 871 }); 872 return ret; 873 } 874 return mAwContents.getFavicon(); 875 } 876 877 @Override 878 public String getTouchIconUrl() { 879 // Intentional no-op: hidden method on WebView. 880 return null; 881 } 882 883 @Override 884 public int getProgress() { 885 // No checkThread() because the value is cached java side (workaround for b/10533304). 886 return mAwContents.getMostRecentProgress(); 887 } 888 889 @Override 890 public int getContentHeight() { 891 // No checkThread() as it is mostly thread safe (workaround for b/10594869). 892 return mAwContents.getContentHeightCss(); 893 } 894 895 @Override 896 public int getContentWidth() { 897 // No checkThread() as it is mostly thread safe (workaround for b/10594869). 898 return mAwContents.getContentWidthCss(); 899 } 900 901 @Override 902 public void pauseTimers() { 903 if (!ThreadUtils.runningOnUiThread()) { 904 ThreadUtils.postOnUiThread(new Runnable() { 905 @Override 906 public void run() { 907 pauseTimers(); 908 } 909 }); 910 return; 911 } 912 mAwContents.pauseTimers(); 913 } 914 915 @Override 916 public void resumeTimers() { 917 if (!ThreadUtils.runningOnUiThread()) { 918 ThreadUtils.postOnUiThread(new Runnable() { 919 @Override 920 public void run() { 921 resumeTimers(); 922 } 923 }); 924 return; 925 } 926 mAwContents.resumeTimers(); 927 } 928 929 @Override 930 public void onPause() { 931 if (!ThreadUtils.runningOnUiThread()) { 932 ThreadUtils.postOnUiThread(new Runnable() { 933 @Override 934 public void run() { 935 onPause(); 936 } 937 }); 938 return; 939 } 940 mAwContents.onPause(); 941 } 942 943 @Override 944 public void onResume() { 945 if (!ThreadUtils.runningOnUiThread()) { 946 ThreadUtils.postOnUiThread(new Runnable() { 947 @Override 948 public void run() { 949 onResume(); 950 } 951 }); 952 return; 953 } 954 mAwContents.onResume(); 955 } 956 957 @Override 958 public boolean isPaused() { 959 if (!ThreadUtils.runningOnUiThread()) { 960 Boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 961 @Override 962 public Boolean call() { 963 return isPaused(); 964 } 965 }); 966 return ret; 967 } 968 return mAwContents.isPaused(); 969 } 970 971 @Override 972 public void freeMemory() { 973 // Intentional no-op. Memory is managed automatically by Chromium. 974 } 975 976 @Override 977 public void clearCache(final boolean includeDiskFiles) { 978 if (!ThreadUtils.runningOnUiThread()) { 979 ThreadUtils.postOnUiThread(new Runnable() { 980 @Override 981 public void run() { 982 clearCache(includeDiskFiles); 983 } 984 }); 985 return; 986 } 987 mAwContents.clearCache(includeDiskFiles); 988 } 989 990 /** 991 * This is a poorly named method, but we keep it for historical reasons. 992 */ 993 @Override 994 public void clearFormData() { 995 if (!ThreadUtils.runningOnUiThread()) { 996 ThreadUtils.postOnUiThread(new Runnable() { 997 @Override 998 public void run() { 999 clearFormData(); 1000 } 1001 }); 1002 return; 1003 } 1004 mAwContents.hideAutofillPopup(); 1005 } 1006 1007 @Override 1008 public void clearHistory() { 1009 if (!ThreadUtils.runningOnUiThread()) { 1010 ThreadUtils.postOnUiThread(new Runnable() { 1011 @Override 1012 public void run() { 1013 clearHistory(); 1014 } 1015 }); 1016 return; 1017 } 1018 mAwContents.clearHistory(); 1019 } 1020 1021 @Override 1022 public void clearSslPreferences() { 1023 if (!ThreadUtils.runningOnUiThread()) { 1024 ThreadUtils.postOnUiThread(new Runnable() { 1025 @Override 1026 public void run() { 1027 clearSslPreferences(); 1028 } 1029 }); 1030 return; 1031 } 1032 mAwContents.clearSslPreferences(); 1033 } 1034 1035 @Override 1036 public WebBackForwardList copyBackForwardList() { 1037 if (!ThreadUtils.runningOnUiThread()) { 1038 WebBackForwardList ret = runOnUiThreadBlocking(new Callable<WebBackForwardList>() { 1039 @Override 1040 public WebBackForwardList call() { 1041 return copyBackForwardList(); 1042 } 1043 }); 1044 return ret; 1045 } 1046 return new WebBackForwardListChromium( 1047 mAwContents.getNavigationHistory()); 1048 } 1049 1050 @Override 1051 public void setFindListener(WebView.FindListener listener) { 1052 mContentsClientAdapter.setFindListener(listener); 1053 } 1054 1055 @Override 1056 public void findNext(final boolean forwards) { 1057 if (!ThreadUtils.runningOnUiThread()) { 1058 ThreadUtils.postOnUiThread(new Runnable() { 1059 @Override 1060 public void run() { 1061 findNext(forwards); 1062 } 1063 }); 1064 return; 1065 } 1066 mAwContents.findNext(forwards); 1067 } 1068 1069 @Override 1070 public int findAll(final String searchString) { 1071 findAllAsync(searchString); 1072 return 0; 1073 } 1074 1075 @Override 1076 public void findAllAsync(final String searchString) { 1077 if (!ThreadUtils.runningOnUiThread()) { 1078 ThreadUtils.postOnUiThread(new Runnable() { 1079 @Override 1080 public void run() { 1081 findAllAsync(searchString); 1082 } 1083 }); 1084 return; 1085 } 1086 mAwContents.findAllAsync(searchString); 1087 } 1088 1089 @Override 1090 public boolean showFindDialog(final String text, final boolean showIme) { 1091 if (!ThreadUtils.runningOnUiThread()) { 1092 return false; 1093 } 1094 if (mWebView.getParent() == null) { 1095 return false; 1096 } 1097 1098 FindActionModeCallback findAction = new FindActionModeCallback(mWebView.getContext()); 1099 if (findAction == null) { 1100 return false; 1101 } 1102 1103 mWebView.startActionMode(findAction); 1104 findAction.setWebView(mWebView); 1105 if (showIme) { 1106 findAction.showSoftInput(); 1107 } 1108 1109 if (text != null) { 1110 findAction.setText(text); 1111 findAction.findAll(); 1112 } 1113 1114 return true; 1115 } 1116 1117 @Override 1118 public void notifyFindDialogDismissed() { 1119 if (!ThreadUtils.runningOnUiThread()) { 1120 ThreadUtils.postOnUiThread(new Runnable() { 1121 @Override 1122 public void run() { 1123 notifyFindDialogDismissed(); 1124 } 1125 }); 1126 return; 1127 } 1128 clearMatches(); 1129 } 1130 1131 @Override 1132 public void clearMatches() { 1133 if (!ThreadUtils.runningOnUiThread()) { 1134 ThreadUtils.postOnUiThread(new Runnable() { 1135 @Override 1136 public void run() { 1137 clearMatches(); 1138 } 1139 }); 1140 return; 1141 } 1142 mAwContents.clearMatches(); 1143 } 1144 1145 @Override 1146 public void documentHasImages(final Message response) { 1147 if (!ThreadUtils.runningOnUiThread()) { 1148 ThreadUtils.postOnUiThread(new Runnable() { 1149 @Override 1150 public void run() { 1151 documentHasImages(response); 1152 } 1153 }); 1154 return; 1155 } 1156 mAwContents.documentHasImages(response); 1157 } 1158 1159 @Override 1160 public void setWebViewClient(WebViewClient client) { 1161 mContentsClientAdapter.setWebViewClient(client); 1162 } 1163 1164 @Override 1165 public void setDownloadListener(DownloadListener listener) { 1166 mContentsClientAdapter.setDownloadListener(listener); 1167 } 1168 1169 @Override 1170 public void setWebChromeClient(WebChromeClient client) { 1171 mContentsClientAdapter.setWebChromeClient(client); 1172 } 1173 1174 @Override 1175 public void setPictureListener(final WebView.PictureListener listener) { 1176 if (!ThreadUtils.runningOnUiThread()) { 1177 ThreadUtils.postOnUiThread(new Runnable() { 1178 @Override 1179 public void run() { 1180 setPictureListener(listener); 1181 } 1182 }); 1183 return; 1184 } 1185 mContentsClientAdapter.setPictureListener(listener); 1186 mAwContents.enableOnNewPicture(listener != null, 1187 mAppTargetSdkVersion >= Build.VERSION_CODES.JELLY_BEAN_MR2); 1188 } 1189 1190 @Override 1191 public void addJavascriptInterface(final Object obj, final String interfaceName) { 1192 if (!ThreadUtils.runningOnUiThread()) { 1193 ThreadUtils.postOnUiThread(new Runnable() { 1194 @Override 1195 public void run() { 1196 addJavascriptInterface(obj, interfaceName); 1197 } 1198 }); 1199 return; 1200 } 1201 Class<? extends Annotation> requiredAnnotation = null; 1202 if (mAppTargetSdkVersion >= Build.VERSION_CODES.JELLY_BEAN_MR1) { 1203 requiredAnnotation = JavascriptInterface.class; 1204 } 1205 mAwContents.addPossiblyUnsafeJavascriptInterface(obj, interfaceName, requiredAnnotation); 1206 } 1207 1208 @Override 1209 public void removeJavascriptInterface(final String interfaceName) { 1210 if (!ThreadUtils.runningOnUiThread()) { 1211 ThreadUtils.postOnUiThread(new Runnable() { 1212 @Override 1213 public void run() { 1214 removeJavascriptInterface(interfaceName); 1215 } 1216 }); 1217 return; 1218 } 1219 mAwContents.removeJavascriptInterface(interfaceName); 1220 } 1221 1222 @Override 1223 public WebSettings getSettings() { 1224 return mWebSettings; 1225 } 1226 1227 @Override 1228 public void setMapTrackballToArrowKeys(boolean setMap) { 1229 // This is a deprecated API: intentional no-op. 1230 } 1231 1232 @Override 1233 public void flingScroll(final int vx, final int vy) { 1234 if (!ThreadUtils.runningOnUiThread()) { 1235 ThreadUtils.postOnUiThread(new Runnable() { 1236 @Override 1237 public void run() { 1238 flingScroll(vx, vy); 1239 } 1240 }); 1241 return; 1242 } 1243 mAwContents.flingScroll(vx, vy); 1244 } 1245 1246 @Override 1247 public View getZoomControls() { 1248 if (!ThreadUtils.runningOnUiThread()) { 1249 return null; 1250 } 1251 1252 // This was deprecated in 2009 and hidden in JB MR1, so just provide the minimum needed 1253 // to stop very out-dated applications from crashing. 1254 Log.w(TAG, "WebView doesn't support getZoomControls"); 1255 return mAwContents.getSettings().supportZoom() ? new View(mWebView.getContext()) : null; 1256 } 1257 1258 @Override 1259 public boolean canZoomIn() { 1260 if (!ThreadUtils.runningOnUiThread()) { 1261 return false; 1262 } 1263 return mAwContents.canZoomIn(); 1264 } 1265 1266 @Override 1267 public boolean canZoomOut() { 1268 if (!ThreadUtils.runningOnUiThread()) { 1269 return false; 1270 } 1271 return mAwContents.canZoomOut(); 1272 } 1273 1274 @Override 1275 public boolean zoomIn() { 1276 if (!ThreadUtils.runningOnUiThread()) { 1277 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1278 @Override 1279 public Boolean call() { 1280 return zoomIn(); 1281 } 1282 }); 1283 return ret; 1284 } 1285 return mAwContents.zoomIn(); 1286 } 1287 1288 @Override 1289 public boolean zoomOut() { 1290 if (!ThreadUtils.runningOnUiThread()) { 1291 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1292 @Override 1293 public Boolean call() { 1294 return zoomOut(); 1295 } 1296 }); 1297 return ret; 1298 } 1299 return mAwContents.zoomOut(); 1300 } 1301 1302 @Override 1303 public void dumpViewHierarchyWithProperties(BufferedWriter out, int level) { 1304 // Intentional no-op 1305 } 1306 1307 @Override 1308 public View findHierarchyView(String className, int hashCode) { 1309 // Intentional no-op 1310 return null; 1311 } 1312 1313 // WebViewProvider glue methods --------------------------------------------------------------- 1314 1315 @Override 1316 // This needs to be kept thread safe! 1317 public WebViewProvider.ViewDelegate getViewDelegate() { 1318 return this; 1319 } 1320 1321 @Override 1322 // This needs to be kept thread safe! 1323 public WebViewProvider.ScrollDelegate getScrollDelegate() { 1324 return this; 1325 } 1326 1327 1328 // WebViewProvider.ViewDelegate implementation ------------------------------------------------ 1329 1330 // TODO: remove from WebViewProvider and use default implementation from 1331 // ViewGroup. 1332 // @Override 1333 public boolean shouldDelayChildPressedState() { 1334 if (!ThreadUtils.runningOnUiThread()) { 1335 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1336 @Override 1337 public Boolean call() { 1338 return shouldDelayChildPressedState(); 1339 } 1340 }); 1341 return ret; 1342 } 1343 return true; 1344 } 1345 1346// @Override 1347 public AccessibilityNodeProvider getAccessibilityNodeProvider() { 1348 if (!ThreadUtils.runningOnUiThread()) { 1349 AccessibilityNodeProvider ret = runOnUiThreadBlocking( 1350 new Callable<AccessibilityNodeProvider>() { 1351 @Override 1352 public AccessibilityNodeProvider call() { 1353 return getAccessibilityNodeProvider(); 1354 } 1355 }); 1356 return ret; 1357 } 1358 return mAwContents.getAccessibilityNodeProvider(); 1359 } 1360 1361 @Override 1362 public void onInitializeAccessibilityNodeInfo(final AccessibilityNodeInfo info) { 1363 if (!ThreadUtils.runningOnUiThread()) { 1364 runVoidTaskOnUiThreadBlocking(new Runnable() { 1365 @Override 1366 public void run() { 1367 onInitializeAccessibilityNodeInfo(info); 1368 } 1369 }); 1370 return; 1371 } 1372 mAwContents.onInitializeAccessibilityNodeInfo(info); 1373 } 1374 1375 @Override 1376 public void onInitializeAccessibilityEvent(final AccessibilityEvent event) { 1377 if (!ThreadUtils.runningOnUiThread()) { 1378 runVoidTaskOnUiThreadBlocking(new Runnable() { 1379 @Override 1380 public void run() { 1381 onInitializeAccessibilityEvent(event); 1382 } 1383 }); 1384 return; 1385 } 1386 mAwContents.onInitializeAccessibilityEvent(event); 1387 } 1388 1389 @Override 1390 public boolean performAccessibilityAction(final int action, final Bundle arguments) { 1391 if (!ThreadUtils.runningOnUiThread()) { 1392 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1393 @Override 1394 public Boolean call() { 1395 return performAccessibilityAction(action, arguments); 1396 } 1397 }); 1398 return ret; 1399 } 1400 if (mAwContents.supportsAccessibilityAction(action)) { 1401 return mAwContents.performAccessibilityAction(action, arguments); 1402 } 1403 return mWebViewPrivate.super_performAccessibilityAction(action, arguments); 1404 } 1405 1406 @Override 1407 public void setOverScrollMode(final int mode) { 1408 if (!ThreadUtils.runningOnUiThread()) { 1409 ThreadUtils.postOnUiThread(new Runnable() { 1410 @Override 1411 public void run() { 1412 setOverScrollMode(mode); 1413 } 1414 }); 1415 return; 1416 } 1417 // This gets called from the android.view.View c'tor that WebView inherits from. This 1418 // causes the method to be called when mAwContents == null. 1419 // It's safe to ignore these calls however since AwContents will read the current value of 1420 // this setting when it's created. 1421 if (mAwContents != null) { 1422 mAwContents.setOverScrollMode(mode); 1423 } 1424 } 1425 1426 @Override 1427 public void setScrollBarStyle(final int style) { 1428 if (!ThreadUtils.runningOnUiThread()) { 1429 ThreadUtils.postOnUiThread(new Runnable() { 1430 @Override 1431 public void run() { 1432 setScrollBarStyle(style); 1433 } 1434 }); 1435 return; 1436 } 1437 mAwContents.setScrollBarStyle(style); 1438 } 1439 1440 @Override 1441 public void onDrawVerticalScrollBar(final Canvas canvas, final Drawable scrollBar, final int l, 1442 final int t, final int r, final int b) { 1443 if (!ThreadUtils.runningOnUiThread()) { 1444 runVoidTaskOnUiThreadBlocking(new Runnable() { 1445 @Override 1446 public void run() { 1447 onDrawVerticalScrollBar(canvas, scrollBar, l, t, r, b); 1448 } 1449 }); 1450 return; 1451 } 1452 // WebViewClassic was overriding this method to handle rubberband over-scroll. Since 1453 // WebViewChromium doesn't support that the vanilla implementation of this method can be 1454 // used. 1455 mWebViewPrivate.super_onDrawVerticalScrollBar(canvas, scrollBar, l, t, r, b); 1456 } 1457 1458 @Override 1459 public void onOverScrolled(final int scrollX, final int scrollY, final boolean clampedX, 1460 final boolean clampedY) { 1461 if (!ThreadUtils.runningOnUiThread()) { 1462 ThreadUtils.postOnUiThread(new Runnable() { 1463 @Override 1464 public void run() { 1465 onOverScrolled(scrollX, scrollY, clampedX, clampedY); 1466 } 1467 }); 1468 return; 1469 } 1470 mAwContents.onContainerViewOverScrolled(scrollX, scrollY, clampedX, clampedY); 1471 } 1472 1473 @Override 1474 public void onWindowVisibilityChanged(final int visibility) { 1475 if (!ThreadUtils.runningOnUiThread()) { 1476 ThreadUtils.postOnUiThread(new Runnable() { 1477 @Override 1478 public void run() { 1479 onWindowVisibilityChanged(visibility); 1480 } 1481 }); 1482 return; 1483 } 1484 mAwContents.onWindowVisibilityChanged(visibility); 1485 } 1486 1487 @Override 1488 public void onDraw(final Canvas canvas) { 1489 if (!ThreadUtils.runningOnUiThread()) { 1490 runVoidTaskOnUiThreadBlocking(new Runnable() { 1491 @Override 1492 public void run() { 1493 onDraw(canvas); 1494 } 1495 }); 1496 return; 1497 } 1498 mAwContents.onDraw(canvas); 1499 } 1500 1501 @Override 1502 public void setLayoutParams(final ViewGroup.LayoutParams layoutParams) { 1503 if (!ThreadUtils.runningOnUiThread()) { 1504 ThreadUtils.postOnUiThread(new Runnable() { 1505 @Override 1506 public void run() { 1507 setLayoutParams(layoutParams); 1508 } 1509 }); 1510 return; 1511 } 1512 mWebViewPrivate.super_setLayoutParams(layoutParams); 1513 } 1514 1515 @Override 1516 public boolean performLongClick() { 1517 if (!ThreadUtils.runningOnUiThread()) { 1518 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1519 @Override 1520 public Boolean call() { 1521 return performLongClick(); 1522 } 1523 }); 1524 return ret; 1525 } 1526 return mWebViewPrivate.super_performLongClick(); 1527 } 1528 1529 @Override 1530 public void onConfigurationChanged(final Configuration newConfig) { 1531 if (!ThreadUtils.runningOnUiThread()) { 1532 ThreadUtils.postOnUiThread(new Runnable() { 1533 @Override 1534 public void run() { 1535 onConfigurationChanged(newConfig); 1536 } 1537 }); 1538 return; 1539 } 1540 mAwContents.onConfigurationChanged(newConfig); 1541 } 1542 1543 @Override 1544 public InputConnection onCreateInputConnection(final EditorInfo outAttrs) { 1545 if (!ThreadUtils.runningOnUiThread()) { 1546 InputConnection ret = runOnUiThreadBlocking(new Callable<InputConnection>() { 1547 @Override 1548 public InputConnection call() { 1549 return onCreateInputConnection(outAttrs); 1550 } 1551 }); 1552 return ret; 1553 } 1554 return mAwContents.onCreateInputConnection(outAttrs); 1555 } 1556 1557 @Override 1558 public boolean onKeyMultiple(final int keyCode, final int repeatCount, final KeyEvent event) { 1559 if (!ThreadUtils.runningOnUiThread()) { 1560 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1561 @Override 1562 public Boolean call() { 1563 return onKeyMultiple(keyCode, repeatCount, event); 1564 } 1565 }); 1566 return ret; 1567 } 1568 UnimplementedWebViewApi.invoke(); 1569 return false; 1570 } 1571 1572 @Override 1573 public boolean onKeyDown(final int keyCode, final KeyEvent event) { 1574 if (!ThreadUtils.runningOnUiThread()) { 1575 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1576 @Override 1577 public Boolean call() { 1578 return onKeyDown(keyCode, event); 1579 } 1580 }); 1581 return ret; 1582 } 1583 UnimplementedWebViewApi.invoke(); 1584 return false; 1585 } 1586 1587 @Override 1588 public boolean onKeyUp(final int keyCode, final KeyEvent event) { 1589 if (!ThreadUtils.runningOnUiThread()) { 1590 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1591 @Override 1592 public Boolean call() { 1593 return onKeyUp(keyCode, event); 1594 } 1595 }); 1596 return ret; 1597 } 1598 return mAwContents.onKeyUp(keyCode, event); 1599 } 1600 1601 @Override 1602 public void onAttachedToWindow() { 1603 if (!ThreadUtils.runningOnUiThread()) { 1604 ThreadUtils.postOnUiThread(new Runnable() { 1605 @Override 1606 public void run() { 1607 onAttachedToWindow(); 1608 } 1609 }); 1610 return; 1611 } 1612 mAwContents.onAttachedToWindow(); 1613 } 1614 1615 @Override 1616 public void onDetachedFromWindow() { 1617 if (!ThreadUtils.runningOnUiThread()) { 1618 ThreadUtils.postOnUiThread(new Runnable() { 1619 @Override 1620 public void run() { 1621 onDetachedFromWindow(); 1622 } 1623 }); 1624 return; 1625 } 1626 mAwContents.onDetachedFromWindow(); 1627 if (mGLfunctor != null) { 1628 mGLfunctor.detach(); 1629 } 1630 } 1631 1632 @Override 1633 public void onVisibilityChanged(final View changedView, final int visibility) { 1634 if (!ThreadUtils.runningOnUiThread()) { 1635 ThreadUtils.postOnUiThread(new Runnable() { 1636 @Override 1637 public void run() { 1638 onVisibilityChanged(changedView, visibility); 1639 } 1640 }); 1641 return; 1642 } 1643 // The AwContents will find out the container view visibility before the first draw so we 1644 // can safely ignore onVisibilityChanged callbacks that happen before init(). 1645 if (mAwContents != null) { 1646 mAwContents.onVisibilityChanged(changedView, visibility); 1647 } 1648 } 1649 1650 @Override 1651 public void onWindowFocusChanged(final boolean hasWindowFocus) { 1652 if (!ThreadUtils.runningOnUiThread()) { 1653 ThreadUtils.postOnUiThread(new Runnable() { 1654 @Override 1655 public void run() { 1656 onWindowFocusChanged(hasWindowFocus); 1657 } 1658 }); 1659 return; 1660 } 1661 mAwContents.onWindowFocusChanged(hasWindowFocus); 1662 } 1663 1664 @Override 1665 public void onFocusChanged(final boolean focused, final int direction, 1666 final Rect previouslyFocusedRect) { 1667 if (!ThreadUtils.runningOnUiThread()) { 1668 ThreadUtils.postOnUiThread(new Runnable() { 1669 @Override 1670 public void run() { 1671 onFocusChanged(focused, direction, previouslyFocusedRect); 1672 } 1673 }); 1674 return; 1675 } 1676 mAwContents.onFocusChanged(focused, direction, previouslyFocusedRect); 1677 } 1678 1679 @Override 1680 public boolean setFrame(final int left, final int top, final int right, final int bottom) { 1681 if (!ThreadUtils.runningOnUiThread()) { 1682 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1683 @Override 1684 public Boolean call() { 1685 return setFrame(left, top, right, bottom); 1686 } 1687 }); 1688 return ret; 1689 } 1690 return mWebViewPrivate.super_setFrame(left, top, right, bottom); 1691 } 1692 1693 @Override 1694 public void onSizeChanged(final int w, final int h, final int ow, final int oh) { 1695 if (!ThreadUtils.runningOnUiThread()) { 1696 ThreadUtils.postOnUiThread(new Runnable() { 1697 @Override 1698 public void run() { 1699 onSizeChanged(w, h, ow, oh); 1700 } 1701 }); 1702 return; 1703 } 1704 mAwContents.onSizeChanged(w, h, ow, oh); 1705 } 1706 1707 @Override 1708 public void onScrollChanged(int l, int t, int oldl, int oldt) { 1709 } 1710 1711 @Override 1712 public boolean dispatchKeyEvent(final KeyEvent event) { 1713 if (!ThreadUtils.runningOnUiThread()) { 1714 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1715 @Override 1716 public Boolean call() { 1717 return dispatchKeyEvent(event); 1718 } 1719 }); 1720 return ret; 1721 } 1722 return mAwContents.dispatchKeyEvent(event); 1723 } 1724 1725 @Override 1726 public boolean onTouchEvent(final MotionEvent ev) { 1727 if (!ThreadUtils.runningOnUiThread()) { 1728 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1729 @Override 1730 public Boolean call() { 1731 return onTouchEvent(ev); 1732 } 1733 }); 1734 return ret; 1735 } 1736 return mAwContents.onTouchEvent(ev); 1737 } 1738 1739 @Override 1740 public boolean onHoverEvent(final MotionEvent event) { 1741 if (!ThreadUtils.runningOnUiThread()) { 1742 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1743 @Override 1744 public Boolean call() { 1745 return onHoverEvent(event); 1746 } 1747 }); 1748 return ret; 1749 } 1750 return mAwContents.onHoverEvent(event); 1751 } 1752 1753 @Override 1754 public boolean onGenericMotionEvent(final MotionEvent event) { 1755 if (!ThreadUtils.runningOnUiThread()) { 1756 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1757 @Override 1758 public Boolean call() { 1759 return onGenericMotionEvent(event); 1760 } 1761 }); 1762 return ret; 1763 } 1764 return mAwContents.onGenericMotionEvent(event); 1765 } 1766 1767 @Override 1768 public boolean onTrackballEvent(MotionEvent ev) { 1769 // Trackball event not handled, which eventually gets converted to DPAD keyevents 1770 return false; 1771 } 1772 1773 @Override 1774 public boolean requestFocus(final int direction, final Rect previouslyFocusedRect) { 1775 if (!ThreadUtils.runningOnUiThread()) { 1776 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1777 @Override 1778 public Boolean call() { 1779 return requestFocus(direction, previouslyFocusedRect); 1780 } 1781 }); 1782 return ret; 1783 } 1784 mAwContents.requestFocus(); 1785 return mWebViewPrivate.super_requestFocus(direction, previouslyFocusedRect); 1786 } 1787 1788 @Override 1789 public void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) { 1790 if (!ThreadUtils.runningOnUiThread()) { 1791 ThreadUtils.postOnUiThread(new Runnable() { 1792 @Override 1793 public void run() { 1794 onMeasure(widthMeasureSpec, heightMeasureSpec); 1795 } 1796 }); 1797 return; 1798 } 1799 mAwContents.onMeasure(widthMeasureSpec, heightMeasureSpec); 1800 } 1801 1802 @Override 1803 public boolean requestChildRectangleOnScreen(final View child, final Rect rect, 1804 final boolean immediate) { 1805 if (!ThreadUtils.runningOnUiThread()) { 1806 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1807 @Override 1808 public Boolean call() { 1809 return requestChildRectangleOnScreen(child, rect, immediate); 1810 } 1811 }); 1812 return ret; 1813 } 1814 return mAwContents.requestChildRectangleOnScreen(child, rect, immediate); 1815 } 1816 1817 @Override 1818 public void setBackgroundColor(final int color) { 1819 if (!ThreadUtils.runningOnUiThread()) { 1820 ThreadUtils.postOnUiThread(new Runnable() { 1821 @Override 1822 public void run() { 1823 setBackgroundColor(color); 1824 } 1825 }); 1826 return; 1827 } 1828 mAwContents.setBackgroundColor(color); 1829 } 1830 1831 @Override 1832 public void setLayerType(int layerType, Paint paint) { 1833 // Intentional no-op 1834 } 1835 1836 // Remove from superclass 1837 public void preDispatchDraw(Canvas canvas) { 1838 // TODO(leandrogracia): remove this method from WebViewProvider if we think 1839 // we won't need it again. 1840 } 1841 1842 // WebViewProvider.ScrollDelegate implementation ---------------------------------------------- 1843 1844 @Override 1845 public int computeHorizontalScrollRange() { 1846 if (!ThreadUtils.runningOnUiThread()) { 1847 int ret = runOnUiThreadBlocking(new Callable<Integer>() { 1848 @Override 1849 public Integer call() { 1850 return computeHorizontalScrollRange(); 1851 } 1852 }); 1853 return ret; 1854 } 1855 return mAwContents.computeHorizontalScrollRange(); 1856 } 1857 1858 @Override 1859 public int computeHorizontalScrollOffset() { 1860 if (!ThreadUtils.runningOnUiThread()) { 1861 int ret = runOnUiThreadBlocking(new Callable<Integer>() { 1862 @Override 1863 public Integer call() { 1864 return computeHorizontalScrollOffset(); 1865 } 1866 }); 1867 return ret; 1868 } 1869 return mAwContents.computeHorizontalScrollOffset(); 1870 } 1871 1872 @Override 1873 public int computeVerticalScrollRange() { 1874 if (!ThreadUtils.runningOnUiThread()) { 1875 int ret = runOnUiThreadBlocking(new Callable<Integer>() { 1876 @Override 1877 public Integer call() { 1878 return computeVerticalScrollRange(); 1879 } 1880 }); 1881 return ret; 1882 } 1883 return mAwContents.computeVerticalScrollRange(); 1884 } 1885 1886 @Override 1887 public int computeVerticalScrollOffset() { 1888 if (!ThreadUtils.runningOnUiThread()) { 1889 int ret = runOnUiThreadBlocking(new Callable<Integer>() { 1890 @Override 1891 public Integer call() { 1892 return computeVerticalScrollOffset(); 1893 } 1894 }); 1895 return ret; 1896 } 1897 return mAwContents.computeVerticalScrollOffset(); 1898 } 1899 1900 @Override 1901 public int computeVerticalScrollExtent() { 1902 if (!ThreadUtils.runningOnUiThread()) { 1903 int ret = runOnUiThreadBlocking(new Callable<Integer>() { 1904 @Override 1905 public Integer call() { 1906 return computeVerticalScrollExtent(); 1907 } 1908 }); 1909 return ret; 1910 } 1911 return mAwContents.computeVerticalScrollExtent(); 1912 } 1913 1914 @Override 1915 public void computeScroll() { 1916 if (!ThreadUtils.runningOnUiThread()) { 1917 ThreadUtils.postOnUiThread(new Runnable() { 1918 @Override 1919 public void run() { 1920 computeScroll(); 1921 } 1922 }); 1923 return; 1924 } 1925 mAwContents.computeScroll(); 1926 } 1927 1928 // AwContents.InternalAccessDelegate implementation -------------------------------------- 1929 private class InternalAccessAdapter implements AwContents.InternalAccessDelegate { 1930 @Override 1931 public boolean drawChild(Canvas arg0, View arg1, long arg2) { 1932 UnimplementedWebViewApi.invoke(); 1933 return false; 1934 } 1935 1936 @Override 1937 public boolean super_onKeyUp(int arg0, KeyEvent arg1) { 1938 // Intentional no-op 1939 return false; 1940 } 1941 1942 @Override 1943 public boolean super_dispatchKeyEventPreIme(KeyEvent arg0) { 1944 UnimplementedWebViewApi.invoke(); 1945 return false; 1946 } 1947 1948 @Override 1949 public boolean super_dispatchKeyEvent(KeyEvent event) { 1950 return mWebViewPrivate.super_dispatchKeyEvent(event); 1951 } 1952 1953 @Override 1954 public boolean super_onGenericMotionEvent(MotionEvent arg0) { 1955 UnimplementedWebViewApi.invoke(); 1956 return false; 1957 } 1958 1959 @Override 1960 public void super_onConfigurationChanged(Configuration arg0) { 1961 // Intentional no-op 1962 } 1963 1964 @Override 1965 public int super_getScrollBarStyle() { 1966 return mWebViewPrivate.super_getScrollBarStyle(); 1967 } 1968 1969 @Override 1970 public boolean awakenScrollBars() { 1971 mWebViewPrivate.awakenScrollBars(0); 1972 // TODO: modify the WebView.PrivateAccess to provide a return value. 1973 return true; 1974 } 1975 1976 @Override 1977 public boolean super_awakenScrollBars(int arg0, boolean arg1) { 1978 // TODO: need method on WebView.PrivateAccess? 1979 UnimplementedWebViewApi.invoke(); 1980 return false; 1981 } 1982 1983 @Override 1984 public void onScrollChanged(int l, int t, int oldl, int oldt) { 1985 mWebViewPrivate.setScrollXRaw(l); 1986 mWebViewPrivate.setScrollYRaw(t); 1987 mWebViewPrivate.onScrollChanged(l, t, oldl, oldt); 1988 } 1989 1990 @Override 1991 public void overScrollBy(int deltaX, int deltaY, 1992 int scrollX, int scrollY, 1993 int scrollRangeX, int scrollRangeY, 1994 int maxOverScrollX, int maxOverScrollY, 1995 boolean isTouchEvent) { 1996 mWebViewPrivate.overScrollBy(deltaX, deltaY, scrollX, scrollY, 1997 scrollRangeX, scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent); 1998 } 1999 2000 @Override 2001 public void super_scrollTo(int scrollX, int scrollY) { 2002 mWebViewPrivate.super_scrollTo(scrollX, scrollY); 2003 } 2004 2005 @Override 2006 public void setMeasuredDimension(int measuredWidth, int measuredHeight) { 2007 mWebViewPrivate.setMeasuredDimension(measuredWidth, measuredHeight); 2008 } 2009 2010 @Override 2011 public boolean requestDrawGL(Canvas canvas) { 2012 if (mGLfunctor == null) { 2013 mGLfunctor = new DrawGLFunctor(mAwContents.getAwDrawGLViewContext()); 2014 } 2015 return mGLfunctor.requestDrawGL((HardwareCanvas)canvas, mWebView.getViewRootImpl()); 2016 } 2017 } 2018} 2019