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