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