WebViewChromium.java revision e80eedd97cf65f058960f6d07cdc7c1bc457035f
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 if (!ThreadUtils.runningOnUiThread()) { 420 ThreadUtils.postOnUiThread(new Runnable() { 421 @Override 422 public void run() { 423 stopLoading(); 424 } 425 }); 426 return; 427 } 428 429 mAwContents.stopLoading(); 430 } 431 432 @Override 433 public void reload() { 434 checkThread(); 435 mAwContents.reload(); 436 } 437 438 @Override 439 public boolean canGoBack() { 440 checkThread(); 441 return mAwContents.canGoBack(); 442 } 443 444 @Override 445 public void goBack() { 446 checkThread(); 447 mAwContents.goBack(); 448 } 449 450 @Override 451 public boolean canGoForward() { 452 checkThread(); 453 return mAwContents.canGoForward(); 454 } 455 456 @Override 457 public void goForward() { 458 checkThread(); 459 mAwContents.goForward(); 460 } 461 462 @Override 463 public boolean canGoBackOrForward(int steps) { 464 checkThread(); 465 return mAwContents.canGoBackOrForward(steps); 466 } 467 468 @Override 469 public void goBackOrForward(int steps) { 470 checkThread(); 471 mAwContents.goBackOrForward(steps); 472 } 473 474 @Override 475 public boolean isPrivateBrowsingEnabled() { 476 // Not supported in this WebView implementation. 477 return false; 478 } 479 480 @Override 481 public boolean pageUp(boolean top) { 482 checkThread(); 483 return mAwContents.pageUp(top); 484 } 485 486 @Override 487 public boolean pageDown(boolean bottom) { 488 checkThread(); 489 return mAwContents.pageDown(bottom); 490 } 491 492 @Override 493 public void clearView() { 494 checkThread(); 495 UnimplementedWebViewApi.invoke(); 496 } 497 498 @Override 499 public Picture capturePicture() { 500 checkThread(); 501 return mAwContents.capturePicture(); 502 } 503 504 @Override 505 public void exportToPdf(ParcelFileDescriptor fd, PrintAttributes attributes, 506 ValueCallback<Boolean> resultCallback, CancellationSignal cancellationSignal) 507 throws java.io.IOException { 508 checkThread(); 509 // We convert frameworks attributes to an android_webview specific print attributes 510 // so we do not tie upstreaming android_webview changes to installation of correct 511 // SDK to try bots. 512 if (attributes == null) { 513 throw new IllegalArgumentException("attributes cannot be null"); 514 } 515 if (attributes.getMediaSize() == null) { 516 throw new IllegalArgumentException("attributes must specify a media size"); 517 } 518 if (attributes.getResolution() == null) { 519 throw new IllegalArgumentException("attributes must specify print resolution"); 520 } 521 if (attributes.getMargins() == null) { 522 throw new IllegalArgumentException("attributes must specify margins"); 523 } 524 AwPdfExportAttributes pdfAttributes = new AwPdfExportAttributes(); 525 pdfAttributes.pageWidth = attributes.getMediaSize().getWidthMils(); 526 pdfAttributes.pageHeight = attributes.getMediaSize().getHeightMils(); 527 pdfAttributes.dpi = getPrintDpi(attributes); 528 pdfAttributes.leftMargin = attributes.getMargins().getLeftMils(); 529 pdfAttributes.rightMargin = attributes.getMargins().getRightMils(); 530 pdfAttributes.topMargin = attributes.getMargins().getTopMils(); 531 pdfAttributes.bottomMargin = attributes.getMargins().getBottomMils(); 532 533 mAwContents.getPdfExporter().exportToPdf(fd, pdfAttributes, resultCallback, 534 cancellationSignal); 535 } 536 537 private static int getPrintDpi(PrintAttributes attributes) { 538 // TODO(sgurun) android print attributes support horizontal and 539 // vertical DPI. Chrome has only one DPI. Revisit this. 540 int horizontalDpi = attributes.getResolution().getHorizontalDpi(); 541 int verticalDpi = attributes.getResolution().getVerticalDpi(); 542 if (horizontalDpi != verticalDpi) { 543 Log.w(TAG, "Horizontal and vertical DPIs differ. Using horizontal DPI " + 544 " hDpi=" + horizontalDpi + " vDPI=" + verticalDpi); 545 } 546 return horizontalDpi; 547 } 548 549 @Override 550 public float getScale() { 551 // No checkThread() as it is mostly thread safe (workaround for b/10652991). 552 return mAwContents.getScale(); 553 } 554 555 @Override 556 public void setInitialScale(int scaleInPercent) { 557 checkThread(); 558 mAwContents.getSettings().setInitialPageScale(scaleInPercent); 559 } 560 561 @Override 562 public void invokeZoomPicker() { 563 checkThread(); 564 mAwContents.invokeZoomPicker(); 565 } 566 567 @Override 568 public WebView.HitTestResult getHitTestResult() { 569 checkThread(); 570 AwContents.HitTestData data = mAwContents.getLastHitTestResult(); 571 mHitTestResult.setType(data.hitTestResultType); 572 mHitTestResult.setExtra(data.hitTestResultExtraData); 573 return mHitTestResult; 574 } 575 576 @Override 577 public void requestFocusNodeHref(Message hrefMsg) { 578 checkThread(); 579 mAwContents.requestFocusNodeHref(hrefMsg); 580 } 581 582 @Override 583 public void requestImageRef(Message msg) { 584 checkThread(); 585 mAwContents.requestImageRef(msg); 586 } 587 588 @Override 589 public String getUrl() { 590 checkThread(); 591 String url = mAwContents.getUrl(); 592 if (url == null || url.trim().isEmpty()) return null; 593 return url; 594 } 595 596 @Override 597 public String getOriginalUrl() { 598 checkThread(); 599 String url = mAwContents.getOriginalUrl(); 600 if (url == null || url.trim().isEmpty()) return null; 601 return url; 602 } 603 604 @Override 605 public String getTitle() { 606 checkThread(); 607 return mAwContents.getTitle(); 608 } 609 610 @Override 611 public Bitmap getFavicon() { 612 checkThread(); 613 return mAwContents.getFavicon(); 614 } 615 616 @Override 617 public String getTouchIconUrl() { 618 // Intentional no-op: hidden method on WebView. 619 return null; 620 } 621 622 @Override 623 public int getProgress() { 624 // No checkThread() because the value is cached java side (workaround for b/10533304). 625 return mAwContents.getMostRecentProgress(); 626 } 627 628 @Override 629 public int getContentHeight() { 630 // No checkThread() as it is mostly thread safe (workaround for b/10594869). 631 return mAwContents.getContentHeightCss(); 632 } 633 634 @Override 635 public int getContentWidth() { 636 checkThread(); 637 return mAwContents.getContentWidthCss(); 638 } 639 640 @Override 641 public void pauseTimers() { 642 checkThread(); 643 mAwContents.pauseTimers(); 644 } 645 646 @Override 647 public void resumeTimers() { 648 checkThread(); 649 mAwContents.resumeTimers(); 650 } 651 652 @Override 653 public void onPause() { 654 checkThread(); 655 mAwContents.onPause(); 656 } 657 658 @Override 659 public void onResume() { 660 checkThread(); 661 mAwContents.onResume(); 662 } 663 664 @Override 665 public boolean isPaused() { 666 checkThread(); 667 return mAwContents.isPaused(); 668 } 669 670 @Override 671 public void freeMemory() { 672 checkThread(); 673 // Intentional no-op. Memory is managed automatically by Chromium. 674 } 675 676 @Override 677 public void clearCache(boolean includeDiskFiles) { 678 checkThread(); 679 mAwContents.clearCache(includeDiskFiles); 680 } 681 682 /** 683 * This is a poorly named method, but we keep it for historical reasons. 684 */ 685 @Override 686 public void clearFormData() { 687 checkThread(); 688 mAwContents.hideAutofillPopup(); 689 } 690 691 @Override 692 public void clearHistory() { 693 checkThread(); 694 mAwContents.clearHistory(); 695 } 696 697 @Override 698 public void clearSslPreferences() { 699 checkThread(); 700 mAwContents.clearSslPreferences(); 701 } 702 703 @Override 704 public WebBackForwardList copyBackForwardList() { 705 checkThread(); 706 return new WebBackForwardListChromium( 707 mAwContents.getNavigationHistory()); 708 } 709 710 @Override 711 public void setFindListener(WebView.FindListener listener) { 712 checkThread(); 713 mContentsClientAdapter.setFindListener(listener); 714 } 715 716 @Override 717 public void findNext(boolean forwards) { 718 checkThread(); 719 mAwContents.findNext(forwards); 720 } 721 722 @Override 723 public int findAll(String searchString) { 724 checkThread(); 725 mAwContents.findAllAsync(searchString); 726 return 0; 727 } 728 729 @Override 730 public void findAllAsync(String searchString) { 731 checkThread(); 732 mAwContents.findAllAsync(searchString); 733 } 734 735 @Override 736 public boolean showFindDialog(String text, boolean showIme) { 737 checkThread(); 738 if (mWebView.getParent() == null) { 739 return false; 740 } 741 742 FindActionModeCallback findAction = new FindActionModeCallback(mWebView.getContext()); 743 if (findAction == null) { 744 return false; 745 } 746 747 mWebView.startActionMode(findAction); 748 findAction.setWebView(mWebView); 749 if (showIme) { 750 findAction.showSoftInput(); 751 } 752 753 if (text != null) { 754 findAction.setText(text); 755 findAction.findAll(); 756 } 757 758 return true; 759 } 760 761 @Override 762 public void notifyFindDialogDismissed() { 763 checkThread(); 764 clearMatches(); 765 } 766 767 @Override 768 public void clearMatches() { 769 checkThread(); 770 mAwContents.clearMatches(); 771 } 772 773 @Override 774 public void documentHasImages(Message response) { 775 checkThread(); 776 mAwContents.documentHasImages(response); 777 } 778 779 @Override 780 public void setWebViewClient(WebViewClient client) { 781 checkThread(); 782 mContentsClientAdapter.setWebViewClient(client); 783 } 784 785 @Override 786 public void setDownloadListener(DownloadListener listener) { 787 checkThread(); 788 mContentsClientAdapter.setDownloadListener(listener); 789 } 790 791 @Override 792 public void setWebChromeClient(WebChromeClient client) { 793 checkThread(); 794 mContentsClientAdapter.setWebChromeClient(client); 795 } 796 797 @Override 798 public void setPictureListener(WebView.PictureListener listener) { 799 checkThread(); 800 mContentsClientAdapter.setPictureListener(listener); 801 mAwContents.enableOnNewPicture(listener != null, 802 mAppTargetSdkVersion >= Build.VERSION_CODES.JELLY_BEAN_MR2); 803 } 804 805 @Override 806 public void addJavascriptInterface(Object obj, String interfaceName) { 807 checkThread(); 808 Class<? extends Annotation> requiredAnnotation = null; 809 if (mAppTargetSdkVersion >= Build.VERSION_CODES.JELLY_BEAN_MR1) { 810 requiredAnnotation = JavascriptInterface.class; 811 } 812 mAwContents.addPossiblyUnsafeJavascriptInterface(obj, interfaceName, requiredAnnotation); 813 } 814 815 @Override 816 public void removeJavascriptInterface(String interfaceName) { 817 checkThread(); 818 mAwContents.removeJavascriptInterface(interfaceName); 819 } 820 821 @Override 822 public WebSettings getSettings() { 823 return mWebSettings; 824 } 825 826 @Override 827 public void setMapTrackballToArrowKeys(boolean setMap) { 828 checkThread(); 829 // This is a deprecated API: intentional no-op. 830 } 831 832 @Override 833 public void flingScroll(int vx, int vy) { 834 checkThread(); 835 mAwContents.flingScroll(vx, vy); 836 } 837 838 @Override 839 public View getZoomControls() { 840 checkThread(); 841 // This was deprecated in 2009 and hidden in JB MR1, so just provide the minimum needed 842 // to stop very out-dated applications from crashing. 843 Log.w(TAG, "WebView doesn't support getZoomControls"); 844 return mAwContents.getSettings().supportZoom() ? new View(mWebView.getContext()) : null; 845 } 846 847 @Override 848 public boolean canZoomIn() { 849 checkThread(); 850 return mAwContents.canZoomIn(); 851 } 852 853 @Override 854 public boolean canZoomOut() { 855 checkThread(); 856 return mAwContents.canZoomOut(); 857 } 858 859 @Override 860 public boolean zoomIn() { 861 checkThread(); 862 return mAwContents.zoomIn(); 863 } 864 865 @Override 866 public boolean zoomOut() { 867 checkThread(); 868 return mAwContents.zoomOut(); 869 } 870 871 @Override 872 public void dumpViewHierarchyWithProperties(BufferedWriter out, int level) { 873 UnimplementedWebViewApi.invoke(); 874 } 875 876 @Override 877 public View findHierarchyView(String className, int hashCode) { 878 UnimplementedWebViewApi.invoke(); 879 return null; 880 } 881 882 // WebViewProvider glue methods --------------------------------------------------------------- 883 884 @Override 885 // This needs to be kept thread safe! 886 public WebViewProvider.ViewDelegate getViewDelegate() { 887 return this; 888 } 889 890 @Override 891 public WebViewProvider.ScrollDelegate getScrollDelegate() { 892 checkThread(); 893 return this; 894 } 895 896 897 // WebViewProvider.ViewDelegate implementation ------------------------------------------------ 898 899 // TODO: remove from WebViewProvider and use default implementation from 900 // ViewGroup. 901 // @Override 902 public boolean shouldDelayChildPressedState() { 903 checkThread(); 904 return true; 905 } 906 907// @Override 908 public AccessibilityNodeProvider getAccessibilityNodeProvider() { 909 checkThread(); 910 return mAwContents.getAccessibilityNodeProvider(); 911 } 912 913 @Override 914 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 915 checkThread(); 916 mAwContents.onInitializeAccessibilityNodeInfo(info); 917 } 918 919 @Override 920 public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 921 checkThread(); 922 mAwContents.onInitializeAccessibilityEvent(event); 923 } 924 925 @Override 926 public boolean performAccessibilityAction(int action, Bundle arguments) { 927 checkThread(); 928 if (mAwContents.supportsAccessibilityAction(action)) { 929 return mAwContents.performAccessibilityAction(action, arguments); 930 } 931 return mWebViewPrivate.super_performAccessibilityAction(action, arguments); 932 } 933 934 @Override 935 public void setOverScrollMode(int mode) { 936 checkThread(); 937 // This gets called from the android.view.View c'tor that WebView inherits from. This 938 // causes the method to be called when mAwContents == null. 939 // It's safe to ignore these calls however since AwContents will read the current value of 940 // this setting when it's created. 941 if (mAwContents != null) { 942 mAwContents.setOverScrollMode(mode); 943 } 944 } 945 946 @Override 947 public void setScrollBarStyle(int style) { 948 checkThread(); 949 mAwContents.setScrollBarStyle(style); 950 } 951 952 @Override 953 public void onDrawVerticalScrollBar(Canvas canvas, Drawable scrollBar, 954 int l, int t, int r, int b) { 955 checkThread(); 956 // WebViewClassic was overriding this method to handle rubberband over-scroll. Since 957 // WebViewChromium doesn't support that the vanilla implementation of this method can be 958 // used. 959 mWebViewPrivate.super_onDrawVerticalScrollBar(canvas, scrollBar, l, t, r, b); 960 } 961 962 @Override 963 public void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) { 964 checkThread(); 965 mAwContents.onContainerViewOverScrolled(scrollX, scrollY, clampedX, clampedY); 966 } 967 968 @Override 969 public void onWindowVisibilityChanged(int visibility) { 970 checkThread(); 971 mAwContents.onWindowVisibilityChanged(visibility); 972 } 973 974 @Override 975 public void onDraw(Canvas canvas) { 976 checkThread(); 977 mAwContents.onDraw(canvas); 978 } 979 980 @Override 981 public void setLayoutParams(ViewGroup.LayoutParams layoutParams) { 982 checkThread(); 983 // TODO: This is the minimum implementation for HTMLViewer 984 // bringup. Likely will need to go up to ContentViewCore for 985 // a complete implementation. 986 mWebViewPrivate.super_setLayoutParams(layoutParams); 987 } 988 989 @Override 990 public boolean performLongClick() { 991 checkThread(); 992 return mWebViewPrivate.super_performLongClick(); 993 } 994 995 @Override 996 public void onConfigurationChanged(Configuration newConfig) { 997 checkThread(); 998 mAwContents.onConfigurationChanged(newConfig); 999 } 1000 1001 @Override 1002 public InputConnection onCreateInputConnection(EditorInfo outAttrs) { 1003 checkThread(); 1004 return mAwContents.onCreateInputConnection(outAttrs); 1005 } 1006 1007 @Override 1008 public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) { 1009 checkThread(); 1010 UnimplementedWebViewApi.invoke(); 1011 return false; 1012 } 1013 1014 @Override 1015 public boolean onKeyDown(int keyCode, KeyEvent event) { 1016 checkThread(); 1017 UnimplementedWebViewApi.invoke(); 1018 return false; 1019 } 1020 1021 @Override 1022 public boolean onKeyUp(int keyCode, KeyEvent event) { 1023 checkThread(); 1024 return mAwContents.onKeyUp(keyCode, event); 1025 } 1026 1027 @Override 1028 public void onAttachedToWindow() { 1029 checkThread(); 1030 mAwContents.onAttachedToWindow(); 1031 } 1032 1033 @Override 1034 public void onDetachedFromWindow() { 1035 checkThread(); 1036 mAwContents.onDetachedFromWindow(); 1037 if (mGLfunctor != null) { 1038 mGLfunctor.detach(); 1039 } 1040 } 1041 1042 @Override 1043 public void onVisibilityChanged(View changedView, int visibility) { 1044 checkThread(); 1045 // The AwContents will find out the container view visibility before the first draw so we 1046 // can safely ignore onVisibilityChanged callbacks that happen before init(). 1047 if (mAwContents != null) { 1048 mAwContents.onVisibilityChanged(changedView, visibility); 1049 } 1050 } 1051 1052 @Override 1053 public void onWindowFocusChanged(boolean hasWindowFocus) { 1054 checkThread(); 1055 mAwContents.onWindowFocusChanged(hasWindowFocus); 1056 } 1057 1058 @Override 1059 public void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) { 1060 checkThread(); 1061 mAwContents.onFocusChanged(focused, direction, previouslyFocusedRect); 1062 } 1063 1064 @Override 1065 public boolean setFrame(int left, int top, int right, int bottom) { 1066 // TODO(joth): This is the minimum implementation for initial 1067 // bringup. Likely will need to go up to AwContents for a complete 1068 // implementation, e.g. setting the compositor visible region (to 1069 // avoid painting tiles that are offscreen due to the view's position). 1070 checkThread(); 1071 return mWebViewPrivate.super_setFrame(left, top, right, bottom); 1072 } 1073 1074 @Override 1075 public void onSizeChanged(int w, int h, int ow, int oh) { 1076 checkThread(); 1077 mAwContents.onSizeChanged(w, h, ow, oh); 1078 } 1079 1080 @Override 1081 public void onScrollChanged(int l, int t, int oldl, int oldt) { 1082 checkThread(); 1083 } 1084 1085 @Override 1086 public boolean dispatchKeyEvent(KeyEvent event) { 1087 checkThread(); 1088 return mAwContents.dispatchKeyEvent(event); 1089 } 1090 1091 @Override 1092 public boolean onTouchEvent(MotionEvent ev) { 1093 checkThread(); 1094 return mAwContents.onTouchEvent(ev); 1095 } 1096 1097 @Override 1098 public boolean onHoverEvent(MotionEvent event) { 1099 checkThread(); 1100 return mAwContents.onHoverEvent(event); 1101 } 1102 1103 @Override 1104 public boolean onGenericMotionEvent(MotionEvent event) { 1105 checkThread(); 1106 return mAwContents.onGenericMotionEvent(event); 1107 } 1108 1109 @Override 1110 public boolean onTrackballEvent(MotionEvent ev) { 1111 checkThread(); 1112 // Trackball event not handled, which eventually gets converted to DPAD keyevents 1113 return false; 1114 } 1115 1116 @Override 1117 public boolean requestFocus(int direction, Rect previouslyFocusedRect) { 1118 checkThread(); 1119 mAwContents.requestFocus(); 1120 return mWebViewPrivate.super_requestFocus(direction, previouslyFocusedRect); 1121 } 1122 1123 @Override 1124 public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 1125 checkThread(); 1126 mAwContents.onMeasure(widthMeasureSpec, heightMeasureSpec); 1127 } 1128 1129 @Override 1130 public boolean requestChildRectangleOnScreen(View child, Rect rect, boolean immediate) { 1131 checkThread(); 1132 return mAwContents.requestChildRectangleOnScreen(child, rect, immediate); 1133 } 1134 1135 @Override 1136 public void setBackgroundColor(final int color) { 1137 if (ThreadUtils.runningOnUiThread()) { 1138 mAwContents.setBackgroundColor(color); 1139 } else { 1140 // Disallowed in WebView API for apps targetting a new SDK 1141 assert mAppTargetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2; 1142 ThreadUtils.postOnUiThread(new Runnable() { 1143 @Override 1144 public void run() { 1145 mAwContents.setBackgroundColor(color); 1146 } 1147 }); 1148 } 1149 } 1150 1151 @Override 1152 public void setLayerType(int layerType, Paint paint) { 1153 checkThread(); 1154 UnimplementedWebViewApi.invoke(); 1155 } 1156 1157 @Override 1158 public void preDispatchDraw(Canvas canvas) { 1159 checkThread(); 1160 // TODO(leandrogracia): remove this method from WebViewProvider if we think 1161 // we won't need it again. 1162 } 1163 1164 // WebViewProvider.ScrollDelegate implementation ---------------------------------------------- 1165 1166 @Override 1167 public int computeHorizontalScrollRange() { 1168 checkThread(); 1169 return mAwContents.computeHorizontalScrollRange(); 1170 } 1171 1172 @Override 1173 public int computeHorizontalScrollOffset() { 1174 checkThread(); 1175 return mAwContents.computeHorizontalScrollOffset(); 1176 } 1177 1178 @Override 1179 public int computeVerticalScrollRange() { 1180 checkThread(); 1181 return mAwContents.computeVerticalScrollRange(); 1182 } 1183 1184 @Override 1185 public int computeVerticalScrollOffset() { 1186 checkThread(); 1187 return mAwContents.computeVerticalScrollOffset(); 1188 } 1189 1190 @Override 1191 public int computeVerticalScrollExtent() { 1192 checkThread(); 1193 return mAwContents.computeVerticalScrollExtent(); 1194 } 1195 1196 @Override 1197 public void computeScroll() { 1198 checkThread(); 1199 mAwContents.computeScroll(); 1200 } 1201 1202 // AwContents.InternalAccessDelegate implementation -------------------------------------- 1203 private class InternalAccessAdapter implements AwContents.InternalAccessDelegate { 1204 @Override 1205 public boolean drawChild(Canvas arg0, View arg1, long arg2) { 1206 UnimplementedWebViewApi.invoke(); 1207 return false; 1208 } 1209 1210 @Override 1211 public boolean super_onKeyUp(int arg0, KeyEvent arg1) { 1212 UnimplementedWebViewApi.invoke(); 1213 return false; 1214 } 1215 1216 @Override 1217 public boolean super_dispatchKeyEventPreIme(KeyEvent arg0) { 1218 UnimplementedWebViewApi.invoke(); 1219 return false; 1220 } 1221 1222 @Override 1223 public boolean super_dispatchKeyEvent(KeyEvent event) { 1224 return mWebViewPrivate.super_dispatchKeyEvent(event); 1225 } 1226 1227 @Override 1228 public boolean super_onGenericMotionEvent(MotionEvent arg0) { 1229 UnimplementedWebViewApi.invoke(); 1230 return false; 1231 } 1232 1233 @Override 1234 public void super_onConfigurationChanged(Configuration arg0) { 1235 UnimplementedWebViewApi.invoke(); 1236 } 1237 1238 @Override 1239 public int super_getScrollBarStyle() { 1240 return mWebViewPrivate.super_getScrollBarStyle(); 1241 } 1242 1243 @Override 1244 public boolean awakenScrollBars() { 1245 mWebViewPrivate.awakenScrollBars(0); 1246 // TODO: modify the WebView.PrivateAccess to provide a return value. 1247 return true; 1248 } 1249 1250 @Override 1251 public boolean super_awakenScrollBars(int arg0, boolean arg1) { 1252 // TODO: need method on WebView.PrivateAccess? 1253 UnimplementedWebViewApi.invoke(); 1254 return false; 1255 } 1256 1257 @Override 1258 public void onScrollChanged(int l, int t, int oldl, int oldt) { 1259 mWebViewPrivate.setScrollXRaw(l); 1260 mWebViewPrivate.setScrollYRaw(t); 1261 mWebViewPrivate.onScrollChanged(l, t, oldl, oldt); 1262 } 1263 1264 @Override 1265 public void overScrollBy(int deltaX, int deltaY, 1266 int scrollX, int scrollY, 1267 int scrollRangeX, int scrollRangeY, 1268 int maxOverScrollX, int maxOverScrollY, 1269 boolean isTouchEvent) { 1270 mWebViewPrivate.overScrollBy(deltaX, deltaY, scrollX, scrollY, 1271 scrollRangeX, scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent); 1272 } 1273 1274 @Override 1275 public void super_scrollTo(int scrollX, int scrollY) { 1276 mWebViewPrivate.super_scrollTo(scrollX, scrollY); 1277 } 1278 1279 @Override 1280 public void setMeasuredDimension(int measuredWidth, int measuredHeight) { 1281 mWebViewPrivate.setMeasuredDimension(measuredWidth, measuredHeight); 1282 } 1283 1284 @Override 1285 public boolean requestDrawGL(Canvas canvas) { 1286 if (mGLfunctor == null) { 1287 mGLfunctor = new DrawGLFunctor(mAwContents.getAwDrawGLViewContext()); 1288 } 1289 return mGLfunctor.requestDrawGL((HardwareCanvas)canvas, mWebView.getViewRootImpl()); 1290 } 1291 } 1292} 1293