WebViewChromium.java revision fa62be4cdc2630566ee179843393d4a6f9893966
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.CancellationSignal; 30import android.os.Message; 31import android.os.ParcelFileDescriptor; 32import android.print.PrintAttributes; 33import android.text.TextUtils; 34import android.util.Base64; 35import android.util.Log; 36import android.view.HardwareCanvas; 37import android.view.KeyEvent; 38import android.view.MotionEvent; 39import android.view.View; 40import android.view.ViewGroup; 41import android.view.accessibility.AccessibilityEvent; 42import android.view.accessibility.AccessibilityNodeInfo; 43import android.view.accessibility.AccessibilityNodeProvider; 44import android.view.inputmethod.EditorInfo; 45import android.view.inputmethod.InputConnection; 46import android.webkit.DownloadListener; 47import android.webkit.FindActionModeCallback; 48import android.webkit.JavascriptInterface; 49import android.webkit.ValueCallback; 50import android.webkit.WebBackForwardList; 51import android.webkit.WebChromeClient; 52import android.webkit.WebSettings; 53import android.webkit.WebView; 54import android.webkit.WebViewClient; 55import android.webkit.WebViewProvider; 56import android.widget.TextView; 57 58import org.chromium.android_webview.AwBrowserContext; 59import org.chromium.android_webview.AwContents; 60import org.chromium.android_webview.AwLayoutSizer; 61import org.chromium.android_webview.AwPdfExportAttributes; 62import org.chromium.base.ThreadUtils; 63import org.chromium.content.browser.LoadUrlParams; 64import org.chromium.net.NetworkChangeNotifier; 65 66import java.io.BufferedWriter; 67import java.io.File; 68import java.lang.annotation.Annotation; 69import java.util.HashMap; 70import java.util.Map; 71 72/** 73 * This class is the delegate to which WebViewProxy forwards all API calls. 74 * 75 * Most of the actual functionality is implemented by AwContents (or ContentViewCore within 76 * it). This class also contains WebView-specific APIs that require the creation of other 77 * adapters (otherwise org.chromium.content would depend on the webview.chromium package) 78 * and a small set of no-op deprecated APIs. 79 */ 80class WebViewChromium implements WebViewProvider, 81 WebViewProvider.ScrollDelegate, WebViewProvider.ViewDelegate { 82 83 private static final String TAG = WebViewChromium.class.getSimpleName(); 84 85 // The WebView that this WebViewChromium is the provider for. 86 WebView mWebView; 87 // Lets us access protected View-derived methods on the WebView instance we're backing. 88 WebView.PrivateAccess mWebViewPrivate; 89 // The client adapter class. 90 private WebViewContentsClientAdapter mContentsClientAdapter; 91 92 // Variables for functionality provided by this adapter --------------------------------------- 93 // WebSettings adapter, lazily initialized in the getter 94 private WebSettings mWebSettings; 95 // The WebView wrapper for ContentViewCore and required browser compontents. 96 private AwContents mAwContents; 97 // Non-null if this webview is using the GL accelerated draw path. 98 private DrawGLFunctor mGLfunctor; 99 100 private AwBrowserContext mBrowserContext; 101 102 private final WebView.HitTestResult mHitTestResult; 103 104 private final int mAppTargetSdkVersion; 105 106 public WebViewChromium(WebView webView, WebView.PrivateAccess webViewPrivate, 107 AwBrowserContext browserContext) { 108 checkThread(); 109 mWebView = webView; 110 mWebViewPrivate = webViewPrivate; 111 mHitTestResult = new WebView.HitTestResult(); 112 mBrowserContext = browserContext; 113 mAppTargetSdkVersion = mWebView.getContext().getApplicationInfo().targetSdkVersion; 114 } 115 116 static void completeWindowCreation(WebView parent, WebView child) { 117 AwContents parentContents = ((WebViewChromium) parent.getWebViewProvider()).mAwContents; 118 AwContents childContents = 119 child == null ? null : ((WebViewChromium) child.getWebViewProvider()).mAwContents; 120 parentContents.supplyContentsForPopup(childContents); 121 } 122 123 // WebViewProvider methods -------------------------------------------------------------------- 124 125 @Override 126 public void init(Map<String, Object> javaScriptInterfaces, boolean privateBrowsing) { 127 // BUG=6790250 |javaScriptInterfaces| was only ever used by the obsolete DumpRenderTree 128 // so is ignored. TODO: remove it from WebViewProvider. 129 final boolean isAccessFromFileURLsGrantedByDefault = 130 mAppTargetSdkVersion < Build.VERSION_CODES.JELLY_BEAN; 131 final boolean areLegacyQuirksEnabled = 132 mAppTargetSdkVersion < Build.VERSION_CODES.KITKAT; 133 mContentsClientAdapter = new WebViewContentsClientAdapter(mWebView); 134 mAwContents = new AwContents(mBrowserContext, mWebView, new InternalAccessAdapter(), 135 mContentsClientAdapter, isAccessFromFileURLsGrantedByDefault, 136 new AwLayoutSizer(), areLegacyQuirksEnabled); 137 mWebSettings = new ContentSettingsAdapter(mAwContents.getSettings()); 138 139 if (privateBrowsing) { 140 final String msg = "Private browsing is not supported in WebView."; 141 if (mAppTargetSdkVersion >= Build.VERSION_CODES.KITKAT) { 142 throw new IllegalArgumentException(msg); 143 } else { 144 Log.w(TAG, msg); 145 // Intentionally irreversibly disable the webview instance, so that private 146 // user data cannot leak through misuse of a non-privateBrowing WebView instance. 147 // Can't just null out mAwContents as we never null-check it before use. 148 mAwContents.destroy(); 149 TextView warningLabel = new TextView(mWebView.getContext()); 150 warningLabel.setText(mWebView.getContext().getString( 151 com.android.internal.R.string.webviewchromium_private_browsing_warning)); 152 mWebView.addView(warningLabel); 153 } 154 } 155 156 } 157 158 private RuntimeException createThreadException() { 159 return new IllegalStateException("Calling View methods on another thread than the UI " + 160 "thread. PLEASE FILE A BUG! go/klp-webview-bug"); 161 } 162 163 // Intentionally not static, as no need to check thread on static methods 164 private void checkThread() { 165 if (!ThreadUtils.runningOnUiThread()) { 166 final RuntimeException threadViolation = createThreadException(); 167 ThreadUtils.postOnUiThread(new Runnable() { 168 @Override 169 public void run() { 170 throw threadViolation; 171 } 172 }); 173 throw createThreadException(); 174 } 175 } 176 177 @Override 178 public void setHorizontalScrollbarOverlay(boolean overlay) { 179 checkThread(); 180 mAwContents.setHorizontalScrollbarOverlay(overlay); 181 } 182 183 @Override 184 public void setVerticalScrollbarOverlay(boolean overlay) { 185 checkThread(); 186 mAwContents.setVerticalScrollbarOverlay(overlay); 187 } 188 189 @Override 190 public boolean overlayHorizontalScrollbar() { 191 checkThread(); 192 return mAwContents.overlayHorizontalScrollbar(); 193 } 194 195 @Override 196 public boolean overlayVerticalScrollbar() { 197 checkThread(); 198 return mAwContents.overlayVerticalScrollbar(); 199 } 200 201 @Override 202 public int getVisibleTitleHeight() { 203 // This is deprecated in WebView and should always return 0. 204 return 0; 205 } 206 207 @Override 208 public SslCertificate getCertificate() { 209 checkThread(); 210 return mAwContents.getCertificate(); 211 } 212 213 @Override 214 public void setCertificate(SslCertificate certificate) { 215 checkThread(); 216 UnimplementedWebViewApi.invoke(); 217 } 218 219 @Override 220 public void savePassword(String host, String username, String password) { 221 // This is a deprecated API: intentional no-op. 222 } 223 224 @Override 225 public void setHttpAuthUsernamePassword(String host, String realm, String username, 226 String password) { 227 checkThread(); 228 mAwContents.setHttpAuthUsernamePassword(host, realm, username, password); 229 } 230 231 @Override 232 public String[] getHttpAuthUsernamePassword(String host, String realm) { 233 checkThread(); 234 return mAwContents.getHttpAuthUsernamePassword(host, realm); 235 } 236 237 @Override 238 public void destroy() { 239 if (!ThreadUtils.runningOnUiThread()) { 240 ThreadUtils.postOnUiThread(new Runnable() { 241 @Override 242 public void run() { 243 destroy(); 244 } 245 }); 246 return; 247 } 248 249 mAwContents.destroy(); 250 if (mGLfunctor != null) { 251 mGLfunctor.destroy(); 252 mGLfunctor = null; 253 } 254 } 255 256 @Override 257 public void setNetworkAvailable(boolean networkUp) { 258 checkThread(); 259 // Note that this purely toggles the JS navigator.online property. 260 // It does not in affect chromium or network stack state in any way. 261 mAwContents.setNetworkAvailable(networkUp); 262 } 263 264 @Override 265 public WebBackForwardList saveState(Bundle outState) { 266 checkThread(); 267 if (outState == null) return null; 268 if (!mAwContents.saveState(outState)) return null; 269 return copyBackForwardList(); 270 } 271 272 @Override 273 public boolean savePicture(Bundle b, File dest) { 274 // Intentional no-op: hidden method on WebView. 275 return false; 276 } 277 278 @Override 279 public boolean restorePicture(Bundle b, File src) { 280 // Intentional no-op: hidden method on WebView. 281 return false; 282 } 283 284 @Override 285 public WebBackForwardList restoreState(Bundle inState) { 286 checkThread(); 287 if (inState == null) return null; 288 if (!mAwContents.restoreState(inState)) return null; 289 return copyBackForwardList(); 290 } 291 292 @Override 293 public void loadUrl(String url, Map<String, String> additionalHttpHeaders) { 294 // TODO: We may actually want to do some sanity checks here (like filter about://chrome). 295 296 // For backwards compatibility, apps targeting less than K will have JS URLs evaluated 297 // directly and any result of the evaluation will not replace the current page content. 298 // Matching Chrome behavior more closely; apps targetting >= K that load a JS URL will 299 // have the result of that URL replace the content of the current page. 300 final String JAVASCRIPT_SCHEME = "javascript:"; 301 if (mAppTargetSdkVersion < Build.VERSION_CODES.KITKAT && 302 url.startsWith(JAVASCRIPT_SCHEME)) { 303 mAwContents.evaluateJavaScriptEvenIfNotYetNavigated( 304 url.substring(JAVASCRIPT_SCHEME.length())); 305 return; 306 } 307 308 LoadUrlParams params = new LoadUrlParams(url); 309 if (additionalHttpHeaders != null) params.setExtraHeaders(additionalHttpHeaders); 310 loadUrlOnUiThread(params); 311 } 312 313 @Override 314 public void loadUrl(String url) { 315 loadUrl(url, null); 316 } 317 318 @Override 319 public void postUrl(String url, byte[] postData) { 320 LoadUrlParams params = LoadUrlParams.createLoadHttpPostParams(url, postData); 321 Map<String,String> headers = new HashMap<String,String>(); 322 headers.put("Content-Type", "application/x-www-form-urlencoded"); 323 params.setExtraHeaders(headers); 324 loadUrlOnUiThread(params); 325 } 326 327 private static String fixupMimeType(String mimeType) { 328 return TextUtils.isEmpty(mimeType) ? "text/html" : mimeType; 329 } 330 331 private static String fixupData(String data) { 332 return TextUtils.isEmpty(data) ? "" : data; 333 } 334 335 private static String fixupBase(String url) { 336 return TextUtils.isEmpty(url) ? "about:blank" : url; 337 } 338 339 private static String fixupHistory(String url) { 340 return TextUtils.isEmpty(url) ? "about:blank" : url; 341 } 342 343 private static boolean isBase64Encoded(String encoding) { 344 return "base64".equals(encoding); 345 } 346 347 @Override 348 public void loadData(String data, String mimeType, String encoding) { 349 loadUrlOnUiThread(LoadUrlParams.createLoadDataParams( 350 fixupData(data), fixupMimeType(mimeType), isBase64Encoded(encoding))); 351 } 352 353 @Override 354 public void loadDataWithBaseURL(String baseUrl, String data, String mimeType, String encoding, 355 String historyUrl) { 356 data = fixupData(data); 357 mimeType = fixupMimeType(mimeType); 358 LoadUrlParams loadUrlParams; 359 baseUrl = fixupBase(baseUrl); 360 historyUrl = fixupHistory(historyUrl); 361 362 if (baseUrl.startsWith("data:")) { 363 // For backwards compatibility with WebViewClassic, we use the value of |encoding| 364 // as the charset, as long as it's not "base64". 365 boolean isBase64 = isBase64Encoded(encoding); 366 loadUrlParams = LoadUrlParams.createLoadDataParamsWithBaseUrl( 367 data, mimeType, isBase64, baseUrl, historyUrl, isBase64 ? null : encoding); 368 } else { 369 // When loading data with a non-data: base URL, the classic WebView would effectively 370 // "dump" that string of data into the WebView without going through regular URL 371 // loading steps such as decoding URL-encoded entities. We achieve this same behavior by 372 // base64 encoding the data that is passed here and then loading that as a data: URL. 373 try { 374 loadUrlParams = LoadUrlParams.createLoadDataParamsWithBaseUrl( 375 Base64.encodeToString(data.getBytes("utf-8"), Base64.DEFAULT), mimeType, 376 true, baseUrl, historyUrl, "utf-8"); 377 } catch (java.io.UnsupportedEncodingException e) { 378 Log.wtf(TAG, "Unable to load data string " + data, e); 379 return; 380 } 381 } 382 loadUrlOnUiThread(loadUrlParams); 383 } 384 385 private void loadUrlOnUiThread(final LoadUrlParams loadUrlParams) { 386 if (ThreadUtils.runningOnUiThread()) { 387 mAwContents.loadUrl(loadUrlParams); 388 } else { 389 // Disallowed in WebView API for apps targetting a new SDK 390 assert mAppTargetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2; 391 ThreadUtils.postOnUiThread(new Runnable() { 392 @Override 393 public void run() { 394 mAwContents.loadUrl(loadUrlParams); 395 } 396 }); 397 } 398 } 399 400 public void evaluateJavaScript(String script, ValueCallback<String> resultCallback) { 401 checkThread(); 402 mAwContents.evaluateJavaScript(script, resultCallback); 403 } 404 405 @Override 406 public void saveWebArchive(String filename) { 407 checkThread(); 408 saveWebArchive(filename, false, null); 409 } 410 411 @Override 412 public void saveWebArchive(String basename, boolean autoname, ValueCallback<String> callback) { 413 checkThread(); 414 mAwContents.saveWebArchive(basename, autoname, callback); 415 } 416 417 @Override 418 public void stopLoading() { 419 checkThread(); 420 mAwContents.stopLoading(); 421 } 422 423 @Override 424 public void reload() { 425 checkThread(); 426 mAwContents.reload(); 427 } 428 429 @Override 430 public boolean canGoBack() { 431 checkThread(); 432 return mAwContents.canGoBack(); 433 } 434 435 @Override 436 public void goBack() { 437 checkThread(); 438 mAwContents.goBack(); 439 } 440 441 @Override 442 public boolean canGoForward() { 443 checkThread(); 444 return mAwContents.canGoForward(); 445 } 446 447 @Override 448 public void goForward() { 449 checkThread(); 450 mAwContents.goForward(); 451 } 452 453 @Override 454 public boolean canGoBackOrForward(int steps) { 455 checkThread(); 456 return mAwContents.canGoBackOrForward(steps); 457 } 458 459 @Override 460 public void goBackOrForward(int steps) { 461 checkThread(); 462 mAwContents.goBackOrForward(steps); 463 } 464 465 @Override 466 public boolean isPrivateBrowsingEnabled() { 467 // Not supported in this WebView implementation. 468 return false; 469 } 470 471 @Override 472 public boolean pageUp(boolean top) { 473 checkThread(); 474 return mAwContents.pageUp(top); 475 } 476 477 @Override 478 public boolean pageDown(boolean bottom) { 479 checkThread(); 480 return mAwContents.pageDown(bottom); 481 } 482 483 @Override 484 public void clearView() { 485 checkThread(); 486 UnimplementedWebViewApi.invoke(); 487 } 488 489 @Override 490 public Picture capturePicture() { 491 checkThread(); 492 return mAwContents.capturePicture(); 493 } 494 495 @Override 496 public void exportToPdf(ParcelFileDescriptor fd, PrintAttributes attributes, 497 ValueCallback<Boolean> resultCallback, CancellationSignal cancellationSignal) 498 throws java.io.IOException { 499 checkThread(); 500 // We convert frameworks attributes to an android_webview specific print attributes 501 // so we do not tie upstreaming android_webview changes to installation of correct 502 // SDK to try bots. 503 if (attributes == null) { 504 throw new IllegalArgumentException("attributes cannot be null"); 505 } 506 if (attributes.getMediaSize() == null) { 507 throw new IllegalArgumentException("attributes must specify a media size"); 508 } 509 if (attributes.getResolution() == null) { 510 throw new IllegalArgumentException("attributes must specify print resolution"); 511 } 512 if (attributes.getMargins() == null) { 513 throw new IllegalArgumentException("attributes must specify margins"); 514 } 515 AwPdfExportAttributes pdfAttributes = new AwPdfExportAttributes(); 516 pdfAttributes.pageWidth = attributes.getMediaSize().getWidthMils(); 517 pdfAttributes.pageHeight = attributes.getMediaSize().getHeightMils(); 518 pdfAttributes.dpi = getPrintDpi(attributes); 519 pdfAttributes.leftMargin = attributes.getMargins().getLeftMils(); 520 pdfAttributes.rightMargin = attributes.getMargins().getRightMils(); 521 pdfAttributes.topMargin = attributes.getMargins().getTopMils(); 522 pdfAttributes.bottomMargin = attributes.getMargins().getBottomMils(); 523 524 mAwContents.getPdfExporter().exportToPdf(fd, pdfAttributes, resultCallback, 525 cancellationSignal); 526 } 527 528 private static int getPrintDpi(PrintAttributes attributes) { 529 // TODO(sgurun) android print attributes support horizontal and 530 // vertical DPI. Chrome has only one DPI. Revisit this. 531 int horizontalDpi = attributes.getResolution().getHorizontalDpi(); 532 int verticalDpi = attributes.getResolution().getVerticalDpi(); 533 if (horizontalDpi != verticalDpi) { 534 Log.w(TAG, "Horizontal and vertical DPIs differ. Using horizontal DPI " + 535 " hDpi=" + horizontalDpi + " vDPI=" + verticalDpi); 536 } 537 return horizontalDpi; 538 } 539 540 @Override 541 public float getScale() { 542 // No checkThread() as it is mostly thread safe (workaround for b/10652991). 543 return mAwContents.getScale(); 544 } 545 546 @Override 547 public void setInitialScale(int scaleInPercent) { 548 checkThread(); 549 mAwContents.getSettings().setInitialPageScale(scaleInPercent); 550 } 551 552 @Override 553 public void invokeZoomPicker() { 554 checkThread(); 555 mAwContents.invokeZoomPicker(); 556 } 557 558 @Override 559 public WebView.HitTestResult getHitTestResult() { 560 checkThread(); 561 AwContents.HitTestData data = mAwContents.getLastHitTestResult(); 562 mHitTestResult.setType(data.hitTestResultType); 563 mHitTestResult.setExtra(data.hitTestResultExtraData); 564 return mHitTestResult; 565 } 566 567 @Override 568 public void requestFocusNodeHref(Message hrefMsg) { 569 checkThread(); 570 mAwContents.requestFocusNodeHref(hrefMsg); 571 } 572 573 @Override 574 public void requestImageRef(Message msg) { 575 checkThread(); 576 mAwContents.requestImageRef(msg); 577 } 578 579 @Override 580 public String getUrl() { 581 checkThread(); 582 String url = mAwContents.getUrl(); 583 if (url == null || url.trim().isEmpty()) return null; 584 return url; 585 } 586 587 @Override 588 public String getOriginalUrl() { 589 checkThread(); 590 String url = mAwContents.getOriginalUrl(); 591 if (url == null || url.trim().isEmpty()) return null; 592 return url; 593 } 594 595 @Override 596 public String getTitle() { 597 checkThread(); 598 return mAwContents.getTitle(); 599 } 600 601 @Override 602 public Bitmap getFavicon() { 603 checkThread(); 604 return mAwContents.getFavicon(); 605 } 606 607 @Override 608 public String getTouchIconUrl() { 609 // Intentional no-op: hidden method on WebView. 610 return null; 611 } 612 613 @Override 614 public int getProgress() { 615 // No checkThread() because the value is cached java side (workaround for b/10533304). 616 return mAwContents.getMostRecentProgress(); 617 } 618 619 @Override 620 public int getContentHeight() { 621 // No checkThread() as it is mostly thread safe (workaround for b/10594869). 622 return mAwContents.getContentHeightCss(); 623 } 624 625 @Override 626 public int getContentWidth() { 627 checkThread(); 628 return mAwContents.getContentWidthCss(); 629 } 630 631 @Override 632 public void pauseTimers() { 633 checkThread(); 634 mAwContents.pauseTimers(); 635 } 636 637 @Override 638 public void resumeTimers() { 639 checkThread(); 640 mAwContents.resumeTimers(); 641 } 642 643 @Override 644 public void onPause() { 645 checkThread(); 646 mAwContents.onPause(); 647 } 648 649 @Override 650 public void onResume() { 651 checkThread(); 652 mAwContents.onResume(); 653 } 654 655 @Override 656 public boolean isPaused() { 657 checkThread(); 658 return mAwContents.isPaused(); 659 } 660 661 @Override 662 public void freeMemory() { 663 checkThread(); 664 // Intentional no-op. Memory is managed automatically by Chromium. 665 } 666 667 @Override 668 public void clearCache(boolean includeDiskFiles) { 669 checkThread(); 670 mAwContents.clearCache(includeDiskFiles); 671 } 672 673 /** 674 * This is a poorly named method, but we keep it for historical reasons. 675 */ 676 @Override 677 public void clearFormData() { 678 checkThread(); 679 mAwContents.hideAutofillPopup(); 680 } 681 682 @Override 683 public void clearHistory() { 684 checkThread(); 685 mAwContents.clearHistory(); 686 } 687 688 @Override 689 public void clearSslPreferences() { 690 checkThread(); 691 mAwContents.clearSslPreferences(); 692 } 693 694 @Override 695 public WebBackForwardList copyBackForwardList() { 696 checkThread(); 697 return new WebBackForwardListChromium( 698 mAwContents.getNavigationHistory()); 699 } 700 701 @Override 702 public void setFindListener(WebView.FindListener listener) { 703 checkThread(); 704 mContentsClientAdapter.setFindListener(listener); 705 } 706 707 @Override 708 public void findNext(boolean forwards) { 709 checkThread(); 710 mAwContents.findNext(forwards); 711 } 712 713 @Override 714 public int findAll(String searchString) { 715 checkThread(); 716 mAwContents.findAllAsync(searchString); 717 return 0; 718 } 719 720 @Override 721 public void findAllAsync(String searchString) { 722 checkThread(); 723 mAwContents.findAllAsync(searchString); 724 } 725 726 @Override 727 public boolean showFindDialog(String text, boolean showIme) { 728 checkThread(); 729 if (mWebView.getParent() == null) { 730 return false; 731 } 732 733 FindActionModeCallback findAction = new FindActionModeCallback(mWebView.getContext()); 734 if (findAction == null) { 735 return false; 736 } 737 738 mWebView.startActionMode(findAction); 739 findAction.setWebView(mWebView); 740 if (showIme) { 741 findAction.showSoftInput(); 742 } 743 744 if (text != null) { 745 findAction.setText(text); 746 findAction.findAll(); 747 } 748 749 return true; 750 } 751 752 @Override 753 public void notifyFindDialogDismissed() { 754 checkThread(); 755 clearMatches(); 756 } 757 758 @Override 759 public void clearMatches() { 760 checkThread(); 761 mAwContents.clearMatches(); 762 } 763 764 @Override 765 public void documentHasImages(Message response) { 766 checkThread(); 767 mAwContents.documentHasImages(response); 768 } 769 770 @Override 771 public void setWebViewClient(WebViewClient client) { 772 checkThread(); 773 mContentsClientAdapter.setWebViewClient(client); 774 } 775 776 @Override 777 public void setDownloadListener(DownloadListener listener) { 778 checkThread(); 779 mContentsClientAdapter.setDownloadListener(listener); 780 } 781 782 @Override 783 public void setWebChromeClient(WebChromeClient client) { 784 checkThread(); 785 mContentsClientAdapter.setWebChromeClient(client); 786 } 787 788 @Override 789 public void setPictureListener(WebView.PictureListener listener) { 790 checkThread(); 791 mContentsClientAdapter.setPictureListener(listener); 792 mAwContents.enableOnNewPicture(listener != null, 793 mAppTargetSdkVersion >= Build.VERSION_CODES.JELLY_BEAN_MR2); 794 } 795 796 @Override 797 public void addJavascriptInterface(Object obj, String interfaceName) { 798 checkThread(); 799 Class<? extends Annotation> requiredAnnotation = null; 800 if (mAppTargetSdkVersion >= Build.VERSION_CODES.JELLY_BEAN_MR1) { 801 requiredAnnotation = JavascriptInterface.class; 802 } 803 mAwContents.addPossiblyUnsafeJavascriptInterface(obj, interfaceName, requiredAnnotation); 804 } 805 806 @Override 807 public void removeJavascriptInterface(String interfaceName) { 808 checkThread(); 809 mAwContents.removeJavascriptInterface(interfaceName); 810 } 811 812 @Override 813 public WebSettings getSettings() { 814 return mWebSettings; 815 } 816 817 @Override 818 public void setMapTrackballToArrowKeys(boolean setMap) { 819 checkThread(); 820 // This is a deprecated API: intentional no-op. 821 } 822 823 @Override 824 public void flingScroll(int vx, int vy) { 825 checkThread(); 826 mAwContents.flingScroll(vx, vy); 827 } 828 829 @Override 830 public View getZoomControls() { 831 checkThread(); 832 // This was deprecated in 2009 and hidden in JB MR1, so just provide the minimum needed 833 // to stop very out-dated applications from crashing. 834 Log.w(TAG, "WebView doesn't support getZoomControls"); 835 return mAwContents.getSettings().supportZoom() ? new View(mWebView.getContext()) : null; 836 } 837 838 @Override 839 public boolean canZoomIn() { 840 checkThread(); 841 return mAwContents.canZoomIn(); 842 } 843 844 @Override 845 public boolean canZoomOut() { 846 checkThread(); 847 return mAwContents.canZoomOut(); 848 } 849 850 @Override 851 public boolean zoomIn() { 852 checkThread(); 853 return mAwContents.zoomIn(); 854 } 855 856 @Override 857 public boolean zoomOut() { 858 checkThread(); 859 return mAwContents.zoomOut(); 860 } 861 862 @Override 863 public void dumpViewHierarchyWithProperties(BufferedWriter out, int level) { 864 UnimplementedWebViewApi.invoke(); 865 } 866 867 @Override 868 public View findHierarchyView(String className, int hashCode) { 869 UnimplementedWebViewApi.invoke(); 870 return null; 871 } 872 873 // WebViewProvider glue methods --------------------------------------------------------------- 874 875 @Override 876 // This needs to be kept thread safe! 877 public WebViewProvider.ViewDelegate getViewDelegate() { 878 return this; 879 } 880 881 @Override 882 public WebViewProvider.ScrollDelegate getScrollDelegate() { 883 checkThread(); 884 return this; 885 } 886 887 888 // WebViewProvider.ViewDelegate implementation ------------------------------------------------ 889 890 // TODO: remove from WebViewProvider and use default implementation from 891 // ViewGroup. 892 // @Override 893 public boolean shouldDelayChildPressedState() { 894 checkThread(); 895 return true; 896 } 897 898// @Override 899 public AccessibilityNodeProvider getAccessibilityNodeProvider() { 900 checkThread(); 901 return mAwContents.getAccessibilityNodeProvider(); 902 } 903 904 @Override 905 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 906 checkThread(); 907 mAwContents.onInitializeAccessibilityNodeInfo(info); 908 } 909 910 @Override 911 public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 912 checkThread(); 913 mAwContents.onInitializeAccessibilityEvent(event); 914 } 915 916 @Override 917 public boolean performAccessibilityAction(int action, Bundle arguments) { 918 checkThread(); 919 if (mAwContents.supportsAccessibilityAction(action)) { 920 return mAwContents.performAccessibilityAction(action, arguments); 921 } 922 return mWebViewPrivate.super_performAccessibilityAction(action, arguments); 923 } 924 925 @Override 926 public void setOverScrollMode(int mode) { 927 checkThread(); 928 // This gets called from the android.view.View c'tor that WebView inherits from. This 929 // causes the method to be called when mAwContents == null. 930 // It's safe to ignore these calls however since AwContents will read the current value of 931 // this setting when it's created. 932 if (mAwContents != null) { 933 mAwContents.setOverScrollMode(mode); 934 } 935 } 936 937 @Override 938 public void setScrollBarStyle(int style) { 939 checkThread(); 940 mAwContents.setScrollBarStyle(style); 941 } 942 943 @Override 944 public void onDrawVerticalScrollBar(Canvas canvas, Drawable scrollBar, 945 int l, int t, int r, int b) { 946 checkThread(); 947 // WebViewClassic was overriding this method to handle rubberband over-scroll. Since 948 // WebViewChromium doesn't support that the vanilla implementation of this method can be 949 // used. 950 mWebViewPrivate.super_onDrawVerticalScrollBar(canvas, scrollBar, l, t, r, b); 951 } 952 953 @Override 954 public void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) { 955 checkThread(); 956 mAwContents.onContainerViewOverScrolled(scrollX, scrollY, clampedX, clampedY); 957 } 958 959 @Override 960 public void onWindowVisibilityChanged(int visibility) { 961 checkThread(); 962 mAwContents.onWindowVisibilityChanged(visibility); 963 } 964 965 @Override 966 public void onDraw(Canvas canvas) { 967 checkThread(); 968 mAwContents.onDraw(canvas); 969 } 970 971 @Override 972 public void setLayoutParams(ViewGroup.LayoutParams layoutParams) { 973 checkThread(); 974 // TODO: This is the minimum implementation for HTMLViewer 975 // bringup. Likely will need to go up to ContentViewCore for 976 // a complete implementation. 977 mWebViewPrivate.super_setLayoutParams(layoutParams); 978 } 979 980 @Override 981 public boolean performLongClick() { 982 checkThread(); 983 return mWebViewPrivate.super_performLongClick(); 984 } 985 986 @Override 987 public void onConfigurationChanged(Configuration newConfig) { 988 checkThread(); 989 mAwContents.onConfigurationChanged(newConfig); 990 } 991 992 @Override 993 public InputConnection onCreateInputConnection(EditorInfo outAttrs) { 994 checkThread(); 995 return mAwContents.onCreateInputConnection(outAttrs); 996 } 997 998 @Override 999 public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) { 1000 checkThread(); 1001 UnimplementedWebViewApi.invoke(); 1002 return false; 1003 } 1004 1005 @Override 1006 public boolean onKeyDown(int keyCode, KeyEvent event) { 1007 checkThread(); 1008 UnimplementedWebViewApi.invoke(); 1009 return false; 1010 } 1011 1012 @Override 1013 public boolean onKeyUp(int keyCode, KeyEvent event) { 1014 checkThread(); 1015 return mAwContents.onKeyUp(keyCode, event); 1016 } 1017 1018 @Override 1019 public void onAttachedToWindow() { 1020 checkThread(); 1021 mAwContents.onAttachedToWindow(); 1022 } 1023 1024 @Override 1025 public void onDetachedFromWindow() { 1026 checkThread(); 1027 mAwContents.onDetachedFromWindow(); 1028 if (mGLfunctor != null) { 1029 mGLfunctor.detach(); 1030 } 1031 } 1032 1033 @Override 1034 public void onVisibilityChanged(View changedView, int visibility) { 1035 checkThread(); 1036 // The AwContents will find out the container view visibility before the first draw so we 1037 // can safely ignore onVisibilityChanged callbacks that happen before init(). 1038 if (mAwContents != null) { 1039 mAwContents.onVisibilityChanged(changedView, visibility); 1040 } 1041 } 1042 1043 @Override 1044 public void onWindowFocusChanged(boolean hasWindowFocus) { 1045 checkThread(); 1046 mAwContents.onWindowFocusChanged(hasWindowFocus); 1047 } 1048 1049 @Override 1050 public void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) { 1051 checkThread(); 1052 mAwContents.onFocusChanged(focused, direction, previouslyFocusedRect); 1053 } 1054 1055 @Override 1056 public boolean setFrame(int left, int top, int right, int bottom) { 1057 // TODO(joth): This is the minimum implementation for initial 1058 // bringup. Likely will need to go up to AwContents for a complete 1059 // implementation, e.g. setting the compositor visible region (to 1060 // avoid painting tiles that are offscreen due to the view's position). 1061 checkThread(); 1062 return mWebViewPrivate.super_setFrame(left, top, right, bottom); 1063 } 1064 1065 @Override 1066 public void onSizeChanged(int w, int h, int ow, int oh) { 1067 checkThread(); 1068 mAwContents.onSizeChanged(w, h, ow, oh); 1069 } 1070 1071 @Override 1072 public void onScrollChanged(int l, int t, int oldl, int oldt) { 1073 checkThread(); 1074 } 1075 1076 @Override 1077 public boolean dispatchKeyEvent(KeyEvent event) { 1078 checkThread(); 1079 return mAwContents.dispatchKeyEvent(event); 1080 } 1081 1082 @Override 1083 public boolean onTouchEvent(MotionEvent ev) { 1084 checkThread(); 1085 return mAwContents.onTouchEvent(ev); 1086 } 1087 1088 @Override 1089 public boolean onHoverEvent(MotionEvent event) { 1090 checkThread(); 1091 return mAwContents.onHoverEvent(event); 1092 } 1093 1094 @Override 1095 public boolean onGenericMotionEvent(MotionEvent event) { 1096 checkThread(); 1097 return mAwContents.onGenericMotionEvent(event); 1098 } 1099 1100 @Override 1101 public boolean onTrackballEvent(MotionEvent ev) { 1102 checkThread(); 1103 // Trackball event not handled, which eventually gets converted to DPAD keyevents 1104 return false; 1105 } 1106 1107 @Override 1108 public boolean requestFocus(int direction, Rect previouslyFocusedRect) { 1109 checkThread(); 1110 mAwContents.requestFocus(); 1111 return mWebViewPrivate.super_requestFocus(direction, previouslyFocusedRect); 1112 } 1113 1114 @Override 1115 public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 1116 checkThread(); 1117 mAwContents.onMeasure(widthMeasureSpec, heightMeasureSpec); 1118 } 1119 1120 @Override 1121 public boolean requestChildRectangleOnScreen(View child, Rect rect, boolean immediate) { 1122 checkThread(); 1123 UnimplementedWebViewApi.invoke(); 1124 return false; 1125 } 1126 1127 @Override 1128 public void setBackgroundColor(final int color) { 1129 if (ThreadUtils.runningOnUiThread()) { 1130 mAwContents.setBackgroundColor(color); 1131 } else { 1132 // Disallowed in WebView API for apps targetting a new SDK 1133 assert mAppTargetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2; 1134 ThreadUtils.postOnUiThread(new Runnable() { 1135 @Override 1136 public void run() { 1137 mAwContents.setBackgroundColor(color); 1138 } 1139 }); 1140 } 1141 } 1142 1143 @Override 1144 public void setLayerType(int layerType, Paint paint) { 1145 checkThread(); 1146 UnimplementedWebViewApi.invoke(); 1147 } 1148 1149 @Override 1150 public void preDispatchDraw(Canvas canvas) { 1151 checkThread(); 1152 // TODO(leandrogracia): remove this method from WebViewProvider if we think 1153 // we won't need it again. 1154 } 1155 1156 // WebViewProvider.ScrollDelegate implementation ---------------------------------------------- 1157 1158 @Override 1159 public int computeHorizontalScrollRange() { 1160 checkThread(); 1161 return mAwContents.computeHorizontalScrollRange(); 1162 } 1163 1164 @Override 1165 public int computeHorizontalScrollOffset() { 1166 checkThread(); 1167 return mAwContents.computeHorizontalScrollOffset(); 1168 } 1169 1170 @Override 1171 public int computeVerticalScrollRange() { 1172 checkThread(); 1173 return mAwContents.computeVerticalScrollRange(); 1174 } 1175 1176 @Override 1177 public int computeVerticalScrollOffset() { 1178 checkThread(); 1179 return mAwContents.computeVerticalScrollOffset(); 1180 } 1181 1182 @Override 1183 public int computeVerticalScrollExtent() { 1184 checkThread(); 1185 return mAwContents.computeVerticalScrollExtent(); 1186 } 1187 1188 @Override 1189 public void computeScroll() { 1190 checkThread(); 1191 mAwContents.computeScroll(); 1192 } 1193 1194 // AwContents.InternalAccessDelegate implementation -------------------------------------- 1195 private class InternalAccessAdapter implements AwContents.InternalAccessDelegate { 1196 @Override 1197 public boolean drawChild(Canvas arg0, View arg1, long arg2) { 1198 UnimplementedWebViewApi.invoke(); 1199 return false; 1200 } 1201 1202 @Override 1203 public boolean super_onKeyUp(int arg0, KeyEvent arg1) { 1204 UnimplementedWebViewApi.invoke(); 1205 return false; 1206 } 1207 1208 @Override 1209 public boolean super_dispatchKeyEventPreIme(KeyEvent arg0) { 1210 UnimplementedWebViewApi.invoke(); 1211 return false; 1212 } 1213 1214 @Override 1215 public boolean super_dispatchKeyEvent(KeyEvent event) { 1216 return mWebViewPrivate.super_dispatchKeyEvent(event); 1217 } 1218 1219 @Override 1220 public boolean super_onGenericMotionEvent(MotionEvent arg0) { 1221 UnimplementedWebViewApi.invoke(); 1222 return false; 1223 } 1224 1225 @Override 1226 public void super_onConfigurationChanged(Configuration arg0) { 1227 UnimplementedWebViewApi.invoke(); 1228 } 1229 1230 @Override 1231 public int super_getScrollBarStyle() { 1232 return mWebViewPrivate.super_getScrollBarStyle(); 1233 } 1234 1235 @Override 1236 public boolean awakenScrollBars() { 1237 mWebViewPrivate.awakenScrollBars(0); 1238 // TODO: modify the WebView.PrivateAccess to provide a return value. 1239 return true; 1240 } 1241 1242 @Override 1243 public boolean super_awakenScrollBars(int arg0, boolean arg1) { 1244 // TODO: need method on WebView.PrivateAccess? 1245 UnimplementedWebViewApi.invoke(); 1246 return false; 1247 } 1248 1249 @Override 1250 public void onScrollChanged(int l, int t, int oldl, int oldt) { 1251 mWebViewPrivate.setScrollXRaw(l); 1252 mWebViewPrivate.setScrollYRaw(t); 1253 mWebViewPrivate.onScrollChanged(l, t, oldl, oldt); 1254 } 1255 1256 @Override 1257 public void overScrollBy(int deltaX, int deltaY, 1258 int scrollX, int scrollY, 1259 int scrollRangeX, int scrollRangeY, 1260 int maxOverScrollX, int maxOverScrollY, 1261 boolean isTouchEvent) { 1262 mWebViewPrivate.overScrollBy(deltaX, deltaY, scrollX, scrollY, 1263 scrollRangeX, scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent); 1264 } 1265 1266 @Override 1267 public void super_scrollTo(int scrollX, int scrollY) { 1268 mWebViewPrivate.super_scrollTo(scrollX, scrollY); 1269 } 1270 1271 @Override 1272 public void setMeasuredDimension(int measuredWidth, int measuredHeight) { 1273 mWebViewPrivate.setMeasuredDimension(measuredWidth, measuredHeight); 1274 } 1275 1276 @Override 1277 public boolean requestDrawGL(Canvas canvas) { 1278 if (mGLfunctor == null) { 1279 mGLfunctor = new DrawGLFunctor(mAwContents.getAwDrawGLViewContext()); 1280 } 1281 return mGLfunctor.requestDrawGL((HardwareCanvas)canvas, mWebView.getViewRootImpl()); 1282 } 1283 } 1284} 1285