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