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