WebViewChromium.java revision 125973639f92ac1ac6080808ddf5b06f131d3c95
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.Looper; 30import android.os.Message; 31import android.print.PrintDocumentAdapter; 32import android.text.TextUtils; 33import android.util.Base64; 34import android.util.Log; 35import android.view.HardwareCanvas; 36import android.view.KeyEvent; 37import android.view.MotionEvent; 38import android.view.View; 39import android.view.View.MeasureSpec; 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.AwSettings; 62import org.chromium.android_webview.AwPrintDocumentAdapter; 63import org.chromium.base.ThreadUtils; 64import org.chromium.content.browser.LoadUrlParams; 65import org.chromium.net.NetworkChangeNotifier; 66 67import java.io.BufferedWriter; 68import java.io.File; 69import java.lang.annotation.Annotation; 70import java.util.concurrent.Callable; 71import java.util.concurrent.ConcurrentLinkedQueue; 72import java.util.concurrent.FutureTask; 73import java.util.concurrent.TimeUnit; 74import java.util.HashMap; 75import java.util.Map; 76import java.util.Queue; 77 78/** 79 * This class is the delegate to which WebViewProxy forwards all API calls. 80 * 81 * Most of the actual functionality is implemented by AwContents (or ContentViewCore within 82 * it). This class also contains WebView-specific APIs that require the creation of other 83 * adapters (otherwise org.chromium.content would depend on the webview.chromium package) 84 * and a small set of no-op deprecated APIs. 85 */ 86class WebViewChromium implements WebViewProvider, 87 WebViewProvider.ScrollDelegate, WebViewProvider.ViewDelegate { 88 89 private class WebViewChromiumRunQueue { 90 public WebViewChromiumRunQueue() { 91 mQueue = new ConcurrentLinkedQueue<Runnable>(); 92 } 93 94 public void addTask(Runnable task) { 95 mQueue.add(task); 96 if (mFactory.hasStarted()) { 97 ThreadUtils.runOnUiThread(new Runnable() { 98 @Override 99 public void run() { 100 drainQueue(); 101 } 102 }); 103 } 104 } 105 106 public void drainQueue() { 107 if (mQueue == null || mQueue.isEmpty()) { 108 return; 109 } 110 111 Runnable task = mQueue.poll(); 112 while(task != null) { 113 task.run(); 114 task = mQueue.poll(); 115 } 116 } 117 118 private Queue<Runnable> mQueue; 119 } 120 121 private WebViewChromiumRunQueue mRunQueue; 122 123 private static final String TAG = WebViewChromium.class.getSimpleName(); 124 125 // The WebView that this WebViewChromium is the provider for. 126 WebView mWebView; 127 // Lets us access protected View-derived methods on the WebView instance we're backing. 128 WebView.PrivateAccess mWebViewPrivate; 129 // The client adapter class. 130 private WebViewContentsClientAdapter mContentsClientAdapter; 131 132 // Variables for functionality provided by this adapter --------------------------------------- 133 private ContentSettingsAdapter mWebSettings; 134 // The WebView wrapper for ContentViewCore and required browser compontents. 135 private AwContents mAwContents; 136 // Non-null if this webview is using the GL accelerated draw path. 137 private DrawGLFunctor mGLfunctor; 138 139 private final WebView.HitTestResult mHitTestResult; 140 141 private final int mAppTargetSdkVersion; 142 143 private WebViewChromiumFactoryProvider mFactory; 144 145 // This does not touch any global / non-threadsafe state, but note that 146 // init is ofter called right after and is NOT threadsafe. 147 public WebViewChromium(WebViewChromiumFactoryProvider factory, WebView webView, 148 WebView.PrivateAccess webViewPrivate) { 149 mWebView = webView; 150 mWebViewPrivate = webViewPrivate; 151 mHitTestResult = new WebView.HitTestResult(); 152 mAppTargetSdkVersion = mWebView.getContext().getApplicationInfo().targetSdkVersion; 153 mFactory = factory; 154 mRunQueue = new WebViewChromiumRunQueue(); 155 } 156 157 static void completeWindowCreation(WebView parent, WebView child) { 158 AwContents parentContents = ((WebViewChromium) parent.getWebViewProvider()).mAwContents; 159 AwContents childContents = 160 child == null ? null : ((WebViewChromium) child.getWebViewProvider()).mAwContents; 161 parentContents.supplyContentsForPopup(childContents); 162 } 163 164 private <T> T runBlockingFuture(FutureTask<T> task) { 165 if (!mFactory.hasStarted()) throw new RuntimeException("Must be started before we block!"); 166 if (ThreadUtils.runningOnUiThread()) { 167 throw new IllegalStateException("This method should only be called off the UI thread"); 168 } 169 mRunQueue.addTask(task); 170 try { 171 return task.get(4, TimeUnit.SECONDS); 172 } catch (java.util.concurrent.TimeoutException e) { 173 throw new RuntimeException("Probable deadlock detected due to WebView API being called " 174 + "on incorrect thread while the UI thread is blocked.", e); 175 } catch (Exception e) { 176 throw new RuntimeException(e); 177 } 178 } 179 180 // We have a 4 second timeout to try to detect deadlocks to detect and aid in debuggin 181 // deadlocks. 182 // Do not call this method while on the UI thread! 183 private void runVoidTaskOnUiThreadBlocking(Runnable r) { 184 FutureTask<Void> task = new FutureTask<Void>(r, null); 185 runBlockingFuture(task); 186 } 187 188 private <T> T runOnUiThreadBlocking(Callable<T> c) { 189 return runBlockingFuture(new FutureTask<T>(c)); 190 } 191 192 // WebViewProvider methods -------------------------------------------------------------------- 193 194 @Override 195 // BUG=6790250 |javaScriptInterfaces| was only ever used by the obsolete DumpRenderTree 196 // so is ignored. TODO: remove it from WebViewProvider. 197 public void init(final Map<String, Object> javaScriptInterfaces, 198 final boolean privateBrowsing) { 199 if (privateBrowsing) { 200 mFactory.startYourEngines(true); 201 final String msg = "Private browsing is not supported in WebView."; 202 if (mAppTargetSdkVersion >= Build.VERSION_CODES.KITKAT) { 203 throw new IllegalArgumentException(msg); 204 } else { 205 Log.w(TAG, msg); 206 TextView warningLabel = new TextView(mWebView.getContext()); 207 warningLabel.setText(mWebView.getContext().getString( 208 com.android.internal.R.string.webviewchromium_private_browsing_warning)); 209 mWebView.addView(warningLabel); 210 } 211 } 212 213 // We will defer real initialization until we know which thread to do it on, unless: 214 // - we are on the main thread already (common case), 215 // - the app is targeting >= JB MR2, in which case checkThread enforces that all usage 216 // comes from a single thread. (Note in JB MR2 this exception was in WebView.java). 217 if (mAppTargetSdkVersion >= Build.VERSION_CODES.JELLY_BEAN_MR2) { 218 mFactory.startYourEngines(false); 219 checkThread(); 220 } else if (!mFactory.hasStarted()) { 221 if (Looper.myLooper() == Looper.getMainLooper()) { 222 mFactory.startYourEngines(true); 223 } 224 } 225 226 final boolean isAccessFromFileURLsGrantedByDefault = 227 mAppTargetSdkVersion < Build.VERSION_CODES.JELLY_BEAN; 228 final boolean areLegacyQuirksEnabled = 229 mAppTargetSdkVersion < Build.VERSION_CODES.KITKAT; 230 231 mContentsClientAdapter = new WebViewContentsClientAdapter(mWebView); 232 mWebSettings = new ContentSettingsAdapter(new AwSettings( 233 mWebView.getContext(), isAccessFromFileURLsGrantedByDefault, 234 areLegacyQuirksEnabled)); 235 236 mRunQueue.addTask(new Runnable() { 237 @Override 238 public void run() { 239 initForReal(); 240 if (privateBrowsing) { 241 // Intentionally irreversibly disable the webview instance, so that private 242 // user data cannot leak through misuse of a non-privateBrowing WebView 243 // instance. Can't just null out mAwContents as we never null-check it 244 // before use. 245 destroy(); 246 } 247 } 248 }); 249 } 250 251 private void initForReal() { 252 mAwContents = new AwContents(mFactory.getBrowserContext(), mWebView, 253 new InternalAccessAdapter(), mContentsClientAdapter, mWebSettings.getAwSettings()); 254 255 if (mAppTargetSdkVersion >= Build.VERSION_CODES.KITKAT) { 256 // On KK and above, favicons are automatically downloaded as the method 257 // old apps use to enable that behavior is deprecated. 258 AwContents.setShouldDownloadFavicons(); 259 } 260 261 if (mAppTargetSdkVersion <= Build.VERSION_CODES.KITKAT) { 262 // On KK and older versions, JavaScript objects injected via addJavascriptInterface 263 // were not inspectable. 264 mAwContents.disableJavascriptInterfacesInspection(); 265 } 266 } 267 268 void startYourEngine() { 269 mRunQueue.drainQueue(); 270 } 271 272 private RuntimeException createThreadException() { 273 return new IllegalStateException( 274 "Calling View methods on another thread than the UI thread."); 275 } 276 277 private boolean checkNeedsPost() { 278 boolean needsPost = !mFactory.hasStarted() || !ThreadUtils.runningOnUiThread(); 279 if (!needsPost && mAwContents == null) { 280 throw new IllegalStateException( 281 "AwContents must be created if we are not posting!"); 282 } 283 return needsPost; 284 } 285 286 // Intentionally not static, as no need to check thread on static methods 287 private void checkThread() { 288 if (!ThreadUtils.runningOnUiThread()) { 289 final RuntimeException threadViolation = createThreadException(); 290 ThreadUtils.postOnUiThread(new Runnable() { 291 @Override 292 public void run() { 293 throw threadViolation; 294 } 295 }); 296 throw createThreadException(); 297 } 298 } 299 300 @Override 301 public void setHorizontalScrollbarOverlay(final boolean overlay) { 302 if (checkNeedsPost()) { 303 mRunQueue.addTask(new Runnable() { 304 @Override 305 public void run() { 306 setHorizontalScrollbarOverlay(overlay); 307 } 308 }); 309 return; 310 } 311 mAwContents.setHorizontalScrollbarOverlay(overlay); 312 } 313 314 @Override 315 public void setVerticalScrollbarOverlay(final boolean overlay) { 316 if (checkNeedsPost()) { 317 mRunQueue.addTask(new Runnable() { 318 @Override 319 public void run() { 320 setVerticalScrollbarOverlay(overlay); 321 } 322 }); 323 return; 324 } 325 mAwContents.setVerticalScrollbarOverlay(overlay); 326 } 327 328 @Override 329 public boolean overlayHorizontalScrollbar() { 330 mFactory.startYourEngines(false); 331 if (checkNeedsPost()) { 332 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 333 @Override 334 public Boolean call() { 335 return overlayHorizontalScrollbar(); 336 } 337 }); 338 return ret; 339 } 340 return mAwContents.overlayHorizontalScrollbar(); 341 } 342 343 @Override 344 public boolean overlayVerticalScrollbar() { 345 mFactory.startYourEngines(false); 346 if (checkNeedsPost()) { 347 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 348 @Override 349 public Boolean call() { 350 return overlayVerticalScrollbar(); 351 } 352 }); 353 return ret; 354 } 355 return mAwContents.overlayVerticalScrollbar(); 356 } 357 358 @Override 359 public int getVisibleTitleHeight() { 360 // This is deprecated in WebView and should always return 0. 361 return 0; 362 } 363 364 @Override 365 public SslCertificate getCertificate() { 366 mFactory.startYourEngines(true); 367 if (checkNeedsPost()) { 368 SslCertificate ret = runOnUiThreadBlocking(new Callable<SslCertificate>() { 369 @Override 370 public SslCertificate call() { 371 return getCertificate(); 372 } 373 }); 374 return ret; 375 } 376 return mAwContents.getCertificate(); 377 } 378 379 @Override 380 public void setCertificate(SslCertificate certificate) { 381 // intentional no-op 382 } 383 384 @Override 385 public void savePassword(String host, String username, String password) { 386 // This is a deprecated API: intentional no-op. 387 } 388 389 @Override 390 public void setHttpAuthUsernamePassword(final String host, final String realm, 391 final String username, final String password) { 392 if (checkNeedsPost()) { 393 mRunQueue.addTask(new Runnable() { 394 @Override 395 public void run() { 396 setHttpAuthUsernamePassword(host, realm, username, password); 397 } 398 }); 399 return; 400 } 401 mAwContents.setHttpAuthUsernamePassword(host, realm, username, password); 402 } 403 404 @Override 405 public String[] getHttpAuthUsernamePassword(final String host, final String realm) { 406 mFactory.startYourEngines(true); 407 if (checkNeedsPost()) { 408 String[] ret = runOnUiThreadBlocking(new Callable<String[]>() { 409 @Override 410 public String[] call() { 411 return getHttpAuthUsernamePassword(host, realm); 412 } 413 }); 414 return ret; 415 } 416 return mAwContents.getHttpAuthUsernamePassword(host, realm); 417 } 418 419 @Override 420 public void destroy() { 421 if (checkNeedsPost()) { 422 mRunQueue.addTask(new Runnable() { 423 @Override 424 public void run() { 425 destroy(); 426 } 427 }); 428 return; 429 } 430 431 mAwContents.destroy(); 432 if (mGLfunctor != null) { 433 mGLfunctor.destroy(); 434 mGLfunctor = null; 435 } 436 } 437 438 @Override 439 public void setNetworkAvailable(final boolean networkUp) { 440 // Note that this purely toggles the JS navigator.online property. 441 // It does not in affect chromium or network stack state in any way. 442 if (checkNeedsPost()) { 443 mRunQueue.addTask(new Runnable() { 444 @Override 445 public void run() { 446 setNetworkAvailable(networkUp); 447 } 448 }); 449 return; 450 } 451 mAwContents.setNetworkAvailable(networkUp); 452 } 453 454 @Override 455 public WebBackForwardList saveState(final Bundle outState) { 456 mFactory.startYourEngines(true); 457 if (checkNeedsPost()) { 458 WebBackForwardList ret = runOnUiThreadBlocking(new Callable<WebBackForwardList>() { 459 @Override 460 public WebBackForwardList call() { 461 return saveState(outState); 462 } 463 }); 464 return ret; 465 } 466 if (outState == null) return null; 467 if (!mAwContents.saveState(outState)) return null; 468 return copyBackForwardList(); 469 } 470 471 @Override 472 public boolean savePicture(Bundle b, File dest) { 473 // Intentional no-op: hidden method on WebView. 474 return false; 475 } 476 477 @Override 478 public boolean restorePicture(Bundle b, File src) { 479 // Intentional no-op: hidden method on WebView. 480 return false; 481 } 482 483 @Override 484 public WebBackForwardList restoreState(final Bundle inState) { 485 mFactory.startYourEngines(true); 486 if (checkNeedsPost()) { 487 WebBackForwardList ret = runOnUiThreadBlocking(new Callable<WebBackForwardList>() { 488 @Override 489 public WebBackForwardList call() { 490 return restoreState(inState); 491 } 492 }); 493 return ret; 494 } 495 if (inState == null) return null; 496 if (!mAwContents.restoreState(inState)) return null; 497 return copyBackForwardList(); 498 } 499 500 @Override 501 public void loadUrl(final String url, Map<String, String> additionalHttpHeaders) { 502 // TODO: We may actually want to do some sanity checks here (like filter about://chrome). 503 504 // For backwards compatibility, apps targeting less than K will have JS URLs evaluated 505 // directly and any result of the evaluation will not replace the current page content. 506 // Matching Chrome behavior more closely; apps targetting >= K that load a JS URL will 507 // have the result of that URL replace the content of the current page. 508 final String JAVASCRIPT_SCHEME = "javascript:"; 509 if (mAppTargetSdkVersion < Build.VERSION_CODES.KITKAT && 510 url != null && url.startsWith(JAVASCRIPT_SCHEME)) { 511 mFactory.startYourEngines(true); 512 if (checkNeedsPost()) { 513 mRunQueue.addTask(new Runnable() { 514 @Override 515 public void run() { 516 mAwContents.evaluateJavaScriptEvenIfNotYetNavigated( 517 url.substring(JAVASCRIPT_SCHEME.length())); 518 } 519 }); 520 } else { 521 mAwContents.evaluateJavaScriptEvenIfNotYetNavigated( 522 url.substring(JAVASCRIPT_SCHEME.length())); 523 } 524 return; 525 } 526 527 LoadUrlParams params = new LoadUrlParams(url); 528 if (additionalHttpHeaders != null) params.setExtraHeaders(additionalHttpHeaders); 529 loadUrlOnUiThread(params); 530 } 531 532 @Override 533 public void loadUrl(String url) { 534 // Early out to match old WebView implementation 535 if (url == null) { 536 return; 537 } 538 loadUrl(url, null); 539 } 540 541 @Override 542 public void postUrl(String url, byte[] postData) { 543 LoadUrlParams params = LoadUrlParams.createLoadHttpPostParams(url, postData); 544 Map<String,String> headers = new HashMap<String,String>(); 545 headers.put("Content-Type", "application/x-www-form-urlencoded"); 546 params.setExtraHeaders(headers); 547 loadUrlOnUiThread(params); 548 } 549 550 private static String fixupMimeType(String mimeType) { 551 return TextUtils.isEmpty(mimeType) ? "text/html" : mimeType; 552 } 553 554 private static String fixupData(String data) { 555 return TextUtils.isEmpty(data) ? "" : data; 556 } 557 558 private static String fixupBase(String url) { 559 return TextUtils.isEmpty(url) ? "about:blank" : url; 560 } 561 562 private static String fixupHistory(String url) { 563 return TextUtils.isEmpty(url) ? "about:blank" : url; 564 } 565 566 private static boolean isBase64Encoded(String encoding) { 567 return "base64".equals(encoding); 568 } 569 570 @Override 571 public void loadData(String data, String mimeType, String encoding) { 572 loadUrlOnUiThread(LoadUrlParams.createLoadDataParams( 573 fixupData(data), fixupMimeType(mimeType), isBase64Encoded(encoding))); 574 } 575 576 @Override 577 public void loadDataWithBaseURL(String baseUrl, String data, String mimeType, String encoding, 578 String historyUrl) { 579 data = fixupData(data); 580 mimeType = fixupMimeType(mimeType); 581 LoadUrlParams loadUrlParams; 582 baseUrl = fixupBase(baseUrl); 583 historyUrl = fixupHistory(historyUrl); 584 585 if (baseUrl.startsWith("data:")) { 586 // For backwards compatibility with WebViewClassic, we use the value of |encoding| 587 // as the charset, as long as it's not "base64". 588 boolean isBase64 = isBase64Encoded(encoding); 589 loadUrlParams = LoadUrlParams.createLoadDataParamsWithBaseUrl( 590 data, mimeType, isBase64, baseUrl, historyUrl, isBase64 ? null : encoding); 591 } else { 592 // When loading data with a non-data: base URL, the classic WebView would effectively 593 // "dump" that string of data into the WebView without going through regular URL 594 // loading steps such as decoding URL-encoded entities. We achieve this same behavior by 595 // base64 encoding the data that is passed here and then loading that as a data: URL. 596 try { 597 loadUrlParams = LoadUrlParams.createLoadDataParamsWithBaseUrl( 598 Base64.encodeToString(data.getBytes("utf-8"), Base64.DEFAULT), mimeType, 599 true, baseUrl, historyUrl, "utf-8"); 600 } catch (java.io.UnsupportedEncodingException e) { 601 Log.wtf(TAG, "Unable to load data string " + data, e); 602 return; 603 } 604 } 605 loadUrlOnUiThread(loadUrlParams); 606 } 607 608 private void loadUrlOnUiThread(final LoadUrlParams loadUrlParams) { 609 // This is the last point that we can delay starting the Chromium backend up 610 // and if the app has not caused us to bind the Chromium UI thread to a background thread 611 // we now bind Chromium's notion of the UI thread to the app main thread. 612 mFactory.startYourEngines(true); 613 if (checkNeedsPost()) { 614 // Disallowed in WebView API for apps targetting a new SDK 615 assert mAppTargetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2; 616 mRunQueue.addTask(new Runnable() { 617 @Override 618 public void run() { 619 mAwContents.loadUrl(loadUrlParams); 620 } 621 }); 622 return; 623 } 624 mAwContents.loadUrl(loadUrlParams); 625 } 626 627 public void evaluateJavaScript(String script, ValueCallback<String> resultCallback) { 628 checkThread(); 629 mAwContents.evaluateJavaScript(script, resultCallback); 630 } 631 632 @Override 633 public void saveWebArchive(String filename) { 634 saveWebArchive(filename, false, null); 635 } 636 637 @Override 638 public void saveWebArchive(final String basename, final boolean autoname, 639 final ValueCallback<String> callback) { 640 if (checkNeedsPost()) { 641 mRunQueue.addTask(new Runnable() { 642 @Override 643 public void run() { 644 saveWebArchive(basename, autoname, callback); 645 } 646 }); 647 return; 648 } 649 mAwContents.saveWebArchive(basename, autoname, callback); 650 } 651 652 @Override 653 public void stopLoading() { 654 if (checkNeedsPost()) { 655 mRunQueue.addTask(new Runnable() { 656 @Override 657 public void run() { 658 stopLoading(); 659 } 660 }); 661 return; 662 } 663 664 mAwContents.stopLoading(); 665 } 666 667 @Override 668 public void reload() { 669 if (checkNeedsPost()) { 670 mRunQueue.addTask(new Runnable() { 671 @Override 672 public void run() { 673 reload(); 674 } 675 }); 676 return; 677 } 678 mAwContents.reload(); 679 } 680 681 @Override 682 public boolean canGoBack() { 683 mFactory.startYourEngines(true); 684 if (checkNeedsPost()) { 685 Boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 686 @Override 687 public Boolean call() { 688 return canGoBack(); 689 } 690 }); 691 return ret; 692 } 693 return mAwContents.canGoBack(); 694 } 695 696 @Override 697 public void goBack() { 698 if (checkNeedsPost()) { 699 mRunQueue.addTask(new Runnable() { 700 @Override 701 public void run() { 702 goBack(); 703 } 704 }); 705 return; 706 } 707 mAwContents.goBack(); 708 } 709 710 @Override 711 public boolean canGoForward() { 712 mFactory.startYourEngines(true); 713 if (checkNeedsPost()) { 714 Boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 715 @Override 716 public Boolean call() { 717 return canGoForward(); 718 } 719 }); 720 return ret; 721 } 722 return mAwContents.canGoForward(); 723 } 724 725 @Override 726 public void goForward() { 727 if (checkNeedsPost()) { 728 mRunQueue.addTask(new Runnable() { 729 @Override 730 public void run() { 731 goForward(); 732 } 733 }); 734 return; 735 } 736 mAwContents.goForward(); 737 } 738 739 @Override 740 public boolean canGoBackOrForward(final int steps) { 741 mFactory.startYourEngines(true); 742 if (checkNeedsPost()) { 743 Boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 744 @Override 745 public Boolean call() { 746 return canGoBackOrForward(steps); 747 } 748 }); 749 return ret; 750 } 751 return mAwContents.canGoBackOrForward(steps); 752 } 753 754 @Override 755 public void goBackOrForward(final int steps) { 756 if (checkNeedsPost()) { 757 mRunQueue.addTask(new Runnable() { 758 @Override 759 public void run() { 760 goBackOrForward(steps); 761 } 762 }); 763 return; 764 } 765 mAwContents.goBackOrForward(steps); 766 } 767 768 @Override 769 public boolean isPrivateBrowsingEnabled() { 770 // Not supported in this WebView implementation. 771 return false; 772 } 773 774 @Override 775 public boolean pageUp(final boolean top) { 776 mFactory.startYourEngines(true); 777 if (checkNeedsPost()) { 778 Boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 779 @Override 780 public Boolean call() { 781 return pageUp(top); 782 } 783 }); 784 return ret; 785 } 786 return mAwContents.pageUp(top); 787 } 788 789 @Override 790 public boolean pageDown(final boolean bottom) { 791 mFactory.startYourEngines(true); 792 if (checkNeedsPost()) { 793 Boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 794 @Override 795 public Boolean call() { 796 return pageDown(bottom); 797 } 798 }); 799 return ret; 800 } 801 return mAwContents.pageDown(bottom); 802 } 803 804 @Override 805 public void clearView() { 806 if (checkNeedsPost()) { 807 mRunQueue.addTask(new Runnable() { 808 @Override 809 public void run() { 810 clearView(); 811 } 812 }); 813 return; 814 } 815 mAwContents.clearView(); 816 } 817 818 @Override 819 public Picture capturePicture() { 820 mFactory.startYourEngines(true); 821 if (checkNeedsPost()) { 822 Picture ret = runOnUiThreadBlocking(new Callable<Picture>() { 823 @Override 824 public Picture call() { 825 return capturePicture(); 826 } 827 }); 828 return ret; 829 } 830 return mAwContents.capturePicture(); 831 } 832 833 @Override 834 public float getScale() { 835 // No checkThread() as it is mostly thread safe (workaround for b/10652991). 836 mFactory.startYourEngines(true); 837 return mAwContents.getScale(); 838 } 839 840 @Override 841 public void setInitialScale(final int scaleInPercent) { 842 // No checkThread() as it is thread safe 843 mWebSettings.getAwSettings().setInitialPageScale(scaleInPercent); 844 } 845 846 @Override 847 public void invokeZoomPicker() { 848 if (checkNeedsPost()) { 849 mRunQueue.addTask(new Runnable() { 850 @Override 851 public void run() { 852 invokeZoomPicker(); 853 } 854 }); 855 return; 856 } 857 mAwContents.invokeZoomPicker(); 858 } 859 860 @Override 861 public WebView.HitTestResult getHitTestResult() { 862 mFactory.startYourEngines(true); 863 if (checkNeedsPost()) { 864 WebView.HitTestResult ret = runOnUiThreadBlocking( 865 new Callable<WebView.HitTestResult>() { 866 @Override 867 public WebView.HitTestResult call() { 868 return getHitTestResult(); 869 } 870 }); 871 return ret; 872 } 873 AwContents.HitTestData data = mAwContents.getLastHitTestResult(); 874 mHitTestResult.setType(data.hitTestResultType); 875 mHitTestResult.setExtra(data.hitTestResultExtraData); 876 return mHitTestResult; 877 } 878 879 @Override 880 public void requestFocusNodeHref(final Message hrefMsg) { 881 if (checkNeedsPost()) { 882 mRunQueue.addTask(new Runnable() { 883 @Override 884 public void run() { 885 requestFocusNodeHref(hrefMsg); 886 } 887 }); 888 return; 889 } 890 mAwContents.requestFocusNodeHref(hrefMsg); 891 } 892 893 @Override 894 public void requestImageRef(final Message msg) { 895 if (checkNeedsPost()) { 896 mRunQueue.addTask(new Runnable() { 897 @Override 898 public void run() { 899 requestImageRef(msg); 900 } 901 }); 902 return; 903 } 904 mAwContents.requestImageRef(msg); 905 } 906 907 @Override 908 public String getUrl() { 909 mFactory.startYourEngines(true); 910 if (checkNeedsPost()) { 911 String ret = runOnUiThreadBlocking(new Callable<String>() { 912 @Override 913 public String call() { 914 return getUrl(); 915 } 916 }); 917 return ret; 918 } 919 String url = mAwContents.getUrl(); 920 if (url == null || url.trim().isEmpty()) return null; 921 return url; 922 } 923 924 @Override 925 public String getOriginalUrl() { 926 mFactory.startYourEngines(true); 927 if (checkNeedsPost()) { 928 String ret = runOnUiThreadBlocking(new Callable<String>() { 929 @Override 930 public String call() { 931 return getOriginalUrl(); 932 } 933 }); 934 return ret; 935 } 936 String url = mAwContents.getOriginalUrl(); 937 if (url == null || url.trim().isEmpty()) return null; 938 return url; 939 } 940 941 @Override 942 public String getTitle() { 943 mFactory.startYourEngines(true); 944 if (checkNeedsPost()) { 945 String ret = runOnUiThreadBlocking(new Callable<String>() { 946 @Override 947 public String call() { 948 return getTitle(); 949 } 950 }); 951 return ret; 952 } 953 return mAwContents.getTitle(); 954 } 955 956 @Override 957 public Bitmap getFavicon() { 958 mFactory.startYourEngines(true); 959 if (checkNeedsPost()) { 960 Bitmap ret = runOnUiThreadBlocking(new Callable<Bitmap>() { 961 @Override 962 public Bitmap call() { 963 return getFavicon(); 964 } 965 }); 966 return ret; 967 } 968 return mAwContents.getFavicon(); 969 } 970 971 @Override 972 public String getTouchIconUrl() { 973 // Intentional no-op: hidden method on WebView. 974 return null; 975 } 976 977 @Override 978 public int getProgress() { 979 if (mAwContents == null) return 100; 980 // No checkThread() because the value is cached java side (workaround for b/10533304). 981 return mAwContents.getMostRecentProgress(); 982 } 983 984 @Override 985 public int getContentHeight() { 986 if (mAwContents == null) return 0; 987 // No checkThread() as it is mostly thread safe (workaround for b/10594869). 988 return mAwContents.getContentHeightCss(); 989 } 990 991 @Override 992 public int getContentWidth() { 993 if (mAwContents == null) return 0; 994 // No checkThread() as it is mostly thread safe (workaround for b/10594869). 995 return mAwContents.getContentWidthCss(); 996 } 997 998 @Override 999 public void pauseTimers() { 1000 if (checkNeedsPost()) { 1001 mRunQueue.addTask(new Runnable() { 1002 @Override 1003 public void run() { 1004 pauseTimers(); 1005 } 1006 }); 1007 return; 1008 } 1009 mAwContents.pauseTimers(); 1010 } 1011 1012 @Override 1013 public void resumeTimers() { 1014 if (checkNeedsPost()) { 1015 mRunQueue.addTask(new Runnable() { 1016 @Override 1017 public void run() { 1018 resumeTimers(); 1019 } 1020 }); 1021 return; 1022 } 1023 mAwContents.resumeTimers(); 1024 } 1025 1026 @Override 1027 public void onPause() { 1028 if (checkNeedsPost()) { 1029 mRunQueue.addTask(new Runnable() { 1030 @Override 1031 public void run() { 1032 onPause(); 1033 } 1034 }); 1035 return; 1036 } 1037 mAwContents.onPause(); 1038 } 1039 1040 @Override 1041 public void onResume() { 1042 if (checkNeedsPost()) { 1043 mRunQueue.addTask(new Runnable() { 1044 @Override 1045 public void run() { 1046 onResume(); 1047 } 1048 }); 1049 return; 1050 } 1051 mAwContents.onResume(); 1052 } 1053 1054 @Override 1055 public boolean isPaused() { 1056 mFactory.startYourEngines(true); 1057 if (checkNeedsPost()) { 1058 Boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1059 @Override 1060 public Boolean call() { 1061 return isPaused(); 1062 } 1063 }); 1064 return ret; 1065 } 1066 return mAwContents.isPaused(); 1067 } 1068 1069 @Override 1070 public void freeMemory() { 1071 // Intentional no-op. Memory is managed automatically by Chromium. 1072 } 1073 1074 @Override 1075 public void clearCache(final boolean includeDiskFiles) { 1076 if (checkNeedsPost()) { 1077 mRunQueue.addTask(new Runnable() { 1078 @Override 1079 public void run() { 1080 clearCache(includeDiskFiles); 1081 } 1082 }); 1083 return; 1084 } 1085 mAwContents.clearCache(includeDiskFiles); 1086 } 1087 1088 /** 1089 * This is a poorly named method, but we keep it for historical reasons. 1090 */ 1091 @Override 1092 public void clearFormData() { 1093 if (checkNeedsPost()) { 1094 mRunQueue.addTask(new Runnable() { 1095 @Override 1096 public void run() { 1097 clearFormData(); 1098 } 1099 }); 1100 return; 1101 } 1102 mAwContents.hideAutofillPopup(); 1103 } 1104 1105 @Override 1106 public void clearHistory() { 1107 if (checkNeedsPost()) { 1108 mRunQueue.addTask(new Runnable() { 1109 @Override 1110 public void run() { 1111 clearHistory(); 1112 } 1113 }); 1114 return; 1115 } 1116 mAwContents.clearHistory(); 1117 } 1118 1119 @Override 1120 public void clearSslPreferences() { 1121 if (checkNeedsPost()) { 1122 mRunQueue.addTask(new Runnable() { 1123 @Override 1124 public void run() { 1125 clearSslPreferences(); 1126 } 1127 }); 1128 return; 1129 } 1130 mAwContents.clearSslPreferences(); 1131 } 1132 1133 @Override 1134 public WebBackForwardList copyBackForwardList() { 1135 mFactory.startYourEngines(true); 1136 if (checkNeedsPost()) { 1137 WebBackForwardList ret = runOnUiThreadBlocking(new Callable<WebBackForwardList>() { 1138 @Override 1139 public WebBackForwardList call() { 1140 return copyBackForwardList(); 1141 } 1142 }); 1143 return ret; 1144 } 1145 return new WebBackForwardListChromium( 1146 mAwContents.getNavigationHistory()); 1147 } 1148 1149 @Override 1150 public void setFindListener(WebView.FindListener listener) { 1151 mContentsClientAdapter.setFindListener(listener); 1152 } 1153 1154 @Override 1155 public void findNext(final boolean forwards) { 1156 if (checkNeedsPost()) { 1157 mRunQueue.addTask(new Runnable() { 1158 @Override 1159 public void run() { 1160 findNext(forwards); 1161 } 1162 }); 1163 return; 1164 } 1165 mAwContents.findNext(forwards); 1166 } 1167 1168 @Override 1169 public int findAll(final String searchString) { 1170 findAllAsync(searchString); 1171 return 0; 1172 } 1173 1174 @Override 1175 public void findAllAsync(final String searchString) { 1176 if (checkNeedsPost()) { 1177 mRunQueue.addTask(new Runnable() { 1178 @Override 1179 public void run() { 1180 findAllAsync(searchString); 1181 } 1182 }); 1183 return; 1184 } 1185 mAwContents.findAllAsync(searchString); 1186 } 1187 1188 @Override 1189 public boolean showFindDialog(final String text, final boolean showIme) { 1190 mFactory.startYourEngines(false); 1191 if (checkNeedsPost()) { 1192 return false; 1193 } 1194 if (mWebView.getParent() == null) { 1195 return false; 1196 } 1197 1198 FindActionModeCallback findAction = new FindActionModeCallback(mWebView.getContext()); 1199 if (findAction == null) { 1200 return false; 1201 } 1202 1203 mWebView.startActionMode(findAction); 1204 findAction.setWebView(mWebView); 1205 if (showIme) { 1206 findAction.showSoftInput(); 1207 } 1208 1209 if (text != null) { 1210 findAction.setText(text); 1211 findAction.findAll(); 1212 } 1213 1214 return true; 1215 } 1216 1217 @Override 1218 public void notifyFindDialogDismissed() { 1219 if (checkNeedsPost()) { 1220 mRunQueue.addTask(new Runnable() { 1221 @Override 1222 public void run() { 1223 notifyFindDialogDismissed(); 1224 } 1225 }); 1226 return; 1227 } 1228 clearMatches(); 1229 } 1230 1231 @Override 1232 public void clearMatches() { 1233 if (checkNeedsPost()) { 1234 mRunQueue.addTask(new Runnable() { 1235 @Override 1236 public void run() { 1237 clearMatches(); 1238 } 1239 }); 1240 return; 1241 } 1242 mAwContents.clearMatches(); 1243 } 1244 1245 @Override 1246 public void documentHasImages(final Message response) { 1247 if (checkNeedsPost()) { 1248 mRunQueue.addTask(new Runnable() { 1249 @Override 1250 public void run() { 1251 documentHasImages(response); 1252 } 1253 }); 1254 return; 1255 } 1256 mAwContents.documentHasImages(response); 1257 } 1258 1259 @Override 1260 public void setWebViewClient(WebViewClient client) { 1261 mContentsClientAdapter.setWebViewClient(client); 1262 } 1263 1264 @Override 1265 public void setDownloadListener(DownloadListener listener) { 1266 mContentsClientAdapter.setDownloadListener(listener); 1267 } 1268 1269 @Override 1270 public void setWebChromeClient(WebChromeClient client) { 1271 mContentsClientAdapter.setWebChromeClient(client); 1272 } 1273 1274 @Override 1275 public void setPictureListener(final WebView.PictureListener listener) { 1276 if (checkNeedsPost()) { 1277 mRunQueue.addTask(new Runnable() { 1278 @Override 1279 public void run() { 1280 setPictureListener(listener); 1281 } 1282 }); 1283 return; 1284 } 1285 mContentsClientAdapter.setPictureListener(listener); 1286 mAwContents.enableOnNewPicture(listener != null, 1287 mAppTargetSdkVersion >= Build.VERSION_CODES.JELLY_BEAN_MR2); 1288 } 1289 1290 @Override 1291 public void addJavascriptInterface(final Object obj, final String interfaceName) { 1292 if (checkNeedsPost()) { 1293 mRunQueue.addTask(new Runnable() { 1294 @Override 1295 public void run() { 1296 addJavascriptInterface(obj, interfaceName); 1297 } 1298 }); 1299 return; 1300 } 1301 Class<? extends Annotation> requiredAnnotation = null; 1302 if (mAppTargetSdkVersion >= Build.VERSION_CODES.JELLY_BEAN_MR1) { 1303 requiredAnnotation = JavascriptInterface.class; 1304 } 1305 mAwContents.addPossiblyUnsafeJavascriptInterface(obj, interfaceName, requiredAnnotation); 1306 } 1307 1308 @Override 1309 public void removeJavascriptInterface(final String interfaceName) { 1310 if (checkNeedsPost()) { 1311 mRunQueue.addTask(new Runnable() { 1312 @Override 1313 public void run() { 1314 removeJavascriptInterface(interfaceName); 1315 } 1316 }); 1317 return; 1318 } 1319 mAwContents.removeJavascriptInterface(interfaceName); 1320 } 1321 1322 @Override 1323 public WebSettings getSettings() { 1324 return mWebSettings; 1325 } 1326 1327 @Override 1328 public void setMapTrackballToArrowKeys(boolean setMap) { 1329 // This is a deprecated API: intentional no-op. 1330 } 1331 1332 @Override 1333 public void flingScroll(final int vx, final int vy) { 1334 if (checkNeedsPost()) { 1335 mRunQueue.addTask(new Runnable() { 1336 @Override 1337 public void run() { 1338 flingScroll(vx, vy); 1339 } 1340 }); 1341 return; 1342 } 1343 mAwContents.flingScroll(vx, vy); 1344 } 1345 1346 @Override 1347 public View getZoomControls() { 1348 mFactory.startYourEngines(false); 1349 if (checkNeedsPost()) { 1350 return null; 1351 } 1352 1353 // This was deprecated in 2009 and hidden in JB MR1, so just provide the minimum needed 1354 // to stop very out-dated applications from crashing. 1355 Log.w(TAG, "WebView doesn't support getZoomControls"); 1356 return mAwContents.getSettings().supportZoom() ? new View(mWebView.getContext()) : null; 1357 } 1358 1359 @Override 1360 public boolean canZoomIn() { 1361 if (checkNeedsPost()) { 1362 return false; 1363 } 1364 return mAwContents.canZoomIn(); 1365 } 1366 1367 @Override 1368 public boolean canZoomOut() { 1369 if (checkNeedsPost()) { 1370 return false; 1371 } 1372 return mAwContents.canZoomOut(); 1373 } 1374 1375 @Override 1376 public boolean zoomIn() { 1377 mFactory.startYourEngines(true); 1378 if (checkNeedsPost()) { 1379 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1380 @Override 1381 public Boolean call() { 1382 return zoomIn(); 1383 } 1384 }); 1385 return ret; 1386 } 1387 return mAwContents.zoomIn(); 1388 } 1389 1390 @Override 1391 public boolean zoomOut() { 1392 mFactory.startYourEngines(true); 1393 if (checkNeedsPost()) { 1394 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1395 @Override 1396 public Boolean call() { 1397 return zoomOut(); 1398 } 1399 }); 1400 return ret; 1401 } 1402 return mAwContents.zoomOut(); 1403 } 1404 1405 @Override 1406 public void dumpViewHierarchyWithProperties(BufferedWriter out, int level) { 1407 // Intentional no-op 1408 } 1409 1410 @Override 1411 public View findHierarchyView(String className, int hashCode) { 1412 // Intentional no-op 1413 return null; 1414 } 1415 1416 // WebViewProvider glue methods --------------------------------------------------------------- 1417 1418 @Override 1419 // This needs to be kept thread safe! 1420 public WebViewProvider.ViewDelegate getViewDelegate() { 1421 return this; 1422 } 1423 1424 @Override 1425 // This needs to be kept thread safe! 1426 public WebViewProvider.ScrollDelegate getScrollDelegate() { 1427 return this; 1428 } 1429 1430 1431 // WebViewProvider.ViewDelegate implementation ------------------------------------------------ 1432 1433 // TODO: remove from WebViewProvider and use default implementation from 1434 // ViewGroup. 1435 // @Override 1436 public boolean shouldDelayChildPressedState() { 1437 mFactory.startYourEngines(false); 1438 if (checkNeedsPost()) { 1439 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1440 @Override 1441 public Boolean call() { 1442 return shouldDelayChildPressedState(); 1443 } 1444 }); 1445 return ret; 1446 } 1447 return true; 1448 } 1449 1450// @Override 1451 public AccessibilityNodeProvider getAccessibilityNodeProvider() { 1452 mFactory.startYourEngines(false); 1453 if (checkNeedsPost()) { 1454 AccessibilityNodeProvider ret = runOnUiThreadBlocking( 1455 new Callable<AccessibilityNodeProvider>() { 1456 @Override 1457 public AccessibilityNodeProvider call() { 1458 return getAccessibilityNodeProvider(); 1459 } 1460 }); 1461 return ret; 1462 } 1463 return mAwContents.getAccessibilityNodeProvider(); 1464 } 1465 1466 @Override 1467 public void onInitializeAccessibilityNodeInfo(final AccessibilityNodeInfo info) { 1468 mFactory.startYourEngines(false); 1469 if (checkNeedsPost()) { 1470 runVoidTaskOnUiThreadBlocking(new Runnable() { 1471 @Override 1472 public void run() { 1473 onInitializeAccessibilityNodeInfo(info); 1474 } 1475 }); 1476 return; 1477 } 1478 mAwContents.onInitializeAccessibilityNodeInfo(info); 1479 } 1480 1481 @Override 1482 public void onInitializeAccessibilityEvent(final AccessibilityEvent event) { 1483 mFactory.startYourEngines(false); 1484 if (checkNeedsPost()) { 1485 runVoidTaskOnUiThreadBlocking(new Runnable() { 1486 @Override 1487 public void run() { 1488 onInitializeAccessibilityEvent(event); 1489 } 1490 }); 1491 return; 1492 } 1493 mAwContents.onInitializeAccessibilityEvent(event); 1494 } 1495 1496 @Override 1497 public boolean performAccessibilityAction(final int action, final Bundle arguments) { 1498 mFactory.startYourEngines(false); 1499 if (checkNeedsPost()) { 1500 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1501 @Override 1502 public Boolean call() { 1503 return performAccessibilityAction(action, arguments); 1504 } 1505 }); 1506 return ret; 1507 } 1508 if (mAwContents.supportsAccessibilityAction(action)) { 1509 return mAwContents.performAccessibilityAction(action, arguments); 1510 } 1511 return mWebViewPrivate.super_performAccessibilityAction(action, arguments); 1512 } 1513 1514 @Override 1515 public void setOverScrollMode(final int mode) { 1516 // This gets called from the android.view.View c'tor that WebView inherits from. This 1517 // causes the method to be called when mAwContents == null. 1518 // It's safe to ignore these calls however since AwContents will read the current value of 1519 // this setting when it's created. 1520 if (mAwContents == null) return; 1521 1522 if (checkNeedsPost()) { 1523 mRunQueue.addTask(new Runnable() { 1524 @Override 1525 public void run() { 1526 setOverScrollMode(mode); 1527 } 1528 }); 1529 return; 1530 } 1531 mAwContents.setOverScrollMode(mode); 1532 } 1533 1534 @Override 1535 public void setScrollBarStyle(final int style) { 1536 if (checkNeedsPost()) { 1537 mRunQueue.addTask(new Runnable() { 1538 @Override 1539 public void run() { 1540 setScrollBarStyle(style); 1541 } 1542 }); 1543 return; 1544 } 1545 mAwContents.setScrollBarStyle(style); 1546 } 1547 1548 @Override 1549 public void onDrawVerticalScrollBar(final Canvas canvas, final Drawable scrollBar, final int l, 1550 final int t, final int r, final int b) { 1551 // WebViewClassic was overriding this method to handle rubberband over-scroll. Since 1552 // WebViewChromium doesn't support that the vanilla implementation of this method can be 1553 // used. 1554 mWebViewPrivate.super_onDrawVerticalScrollBar(canvas, scrollBar, l, t, r, b); 1555 } 1556 1557 @Override 1558 public void onOverScrolled(final int scrollX, final int scrollY, final boolean clampedX, 1559 final boolean clampedY) { 1560 if (checkNeedsPost()) { 1561 mRunQueue.addTask(new Runnable() { 1562 @Override 1563 public void run() { 1564 onOverScrolled(scrollX, scrollY, clampedX, clampedY); 1565 } 1566 }); 1567 return; 1568 } 1569 mAwContents.onContainerViewOverScrolled(scrollX, scrollY, clampedX, clampedY); 1570 } 1571 1572 @Override 1573 public void onWindowVisibilityChanged(final int visibility) { 1574 if (checkNeedsPost()) { 1575 mRunQueue.addTask(new Runnable() { 1576 @Override 1577 public void run() { 1578 onWindowVisibilityChanged(visibility); 1579 } 1580 }); 1581 return; 1582 } 1583 mAwContents.onWindowVisibilityChanged(visibility); 1584 } 1585 1586 @Override 1587 public void onDraw(final Canvas canvas) { 1588 mFactory.startYourEngines(true); 1589 if (checkNeedsPost()) { 1590 runVoidTaskOnUiThreadBlocking(new Runnable() { 1591 @Override 1592 public void run() { 1593 onDraw(canvas); 1594 } 1595 }); 1596 return; 1597 } 1598 mAwContents.onDraw(canvas); 1599 } 1600 1601 @Override 1602 public void setLayoutParams(final ViewGroup.LayoutParams layoutParams) { 1603 // This API is our strongest signal from the View system that this 1604 // WebView is going to be bound to a View hierarchy and so at this 1605 // point we must bind Chromium's UI thread to the current thread. 1606 mFactory.startYourEngines(false); 1607 checkThread(); 1608 mWebViewPrivate.super_setLayoutParams(layoutParams); 1609 } 1610 1611 @Override 1612 public boolean performLongClick() { 1613 // Return false unless the WebView is attached to a View with a parent 1614 return mWebView.getParent() != null ? mWebViewPrivate.super_performLongClick() : false; 1615 } 1616 1617 @Override 1618 public void onConfigurationChanged(final Configuration newConfig) { 1619 if (checkNeedsPost()) { 1620 mRunQueue.addTask(new Runnable() { 1621 @Override 1622 public void run() { 1623 onConfigurationChanged(newConfig); 1624 } 1625 }); 1626 return; 1627 } 1628 mAwContents.onConfigurationChanged(newConfig); 1629 } 1630 1631 @Override 1632 public InputConnection onCreateInputConnection(final EditorInfo outAttrs) { 1633 mFactory.startYourEngines(false); 1634 if (checkNeedsPost()) { 1635 return null; 1636 } 1637 return mAwContents.onCreateInputConnection(outAttrs); 1638 } 1639 1640 @Override 1641 public boolean onKeyMultiple(final int keyCode, final int repeatCount, final KeyEvent event) { 1642 mFactory.startYourEngines(false); 1643 if (checkNeedsPost()) { 1644 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1645 @Override 1646 public Boolean call() { 1647 return onKeyMultiple(keyCode, repeatCount, event); 1648 } 1649 }); 1650 return ret; 1651 } 1652 UnimplementedWebViewApi.invoke(); 1653 return false; 1654 } 1655 1656 @Override 1657 public boolean onKeyDown(final int keyCode, final KeyEvent event) { 1658 mFactory.startYourEngines(false); 1659 if (checkNeedsPost()) { 1660 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1661 @Override 1662 public Boolean call() { 1663 return onKeyDown(keyCode, event); 1664 } 1665 }); 1666 return ret; 1667 } 1668 UnimplementedWebViewApi.invoke(); 1669 return false; 1670 } 1671 1672 @Override 1673 public boolean onKeyUp(final int keyCode, final KeyEvent event) { 1674 mFactory.startYourEngines(false); 1675 if (checkNeedsPost()) { 1676 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1677 @Override 1678 public Boolean call() { 1679 return onKeyUp(keyCode, event); 1680 } 1681 }); 1682 return ret; 1683 } 1684 return mAwContents.onKeyUp(keyCode, event); 1685 } 1686 1687 @Override 1688 public void onAttachedToWindow() { 1689 // This API is our strongest signal from the View system that this 1690 // WebView is going to be bound to a View hierarchy and so at this 1691 // point we must bind Chromium's UI thread to the current thread. 1692 mFactory.startYourEngines(false); 1693 checkThread(); 1694 mAwContents.onAttachedToWindow(); 1695 } 1696 1697 @Override 1698 public void onDetachedFromWindow() { 1699 if (checkNeedsPost()) { 1700 mRunQueue.addTask(new Runnable() { 1701 @Override 1702 public void run() { 1703 onDetachedFromWindow(); 1704 } 1705 }); 1706 return; 1707 } 1708 1709 mAwContents.onDetachedFromWindow(); 1710 if (mGLfunctor != null) { 1711 mGLfunctor.detach(); 1712 } 1713 } 1714 1715 @Override 1716 public void onVisibilityChanged(final View changedView, final int visibility) { 1717 // The AwContents will find out the container view visibility before the first draw so we 1718 // can safely ignore onVisibilityChanged callbacks that happen before init(). 1719 if (mAwContents == null) return; 1720 1721 if (checkNeedsPost()) { 1722 mRunQueue.addTask(new Runnable() { 1723 @Override 1724 public void run() { 1725 onVisibilityChanged(changedView, visibility); 1726 } 1727 }); 1728 return; 1729 } 1730 mAwContents.onVisibilityChanged(changedView, visibility); 1731 } 1732 1733 @Override 1734 public void onWindowFocusChanged(final boolean hasWindowFocus) { 1735 if (checkNeedsPost()) { 1736 mRunQueue.addTask(new Runnable() { 1737 @Override 1738 public void run() { 1739 onWindowFocusChanged(hasWindowFocus); 1740 } 1741 }); 1742 return; 1743 } 1744 mAwContents.onWindowFocusChanged(hasWindowFocus); 1745 } 1746 1747 @Override 1748 public void onFocusChanged(final boolean focused, final int direction, 1749 final Rect previouslyFocusedRect) { 1750 if (checkNeedsPost()) { 1751 mRunQueue.addTask(new Runnable() { 1752 @Override 1753 public void run() { 1754 onFocusChanged(focused, direction, previouslyFocusedRect); 1755 } 1756 }); 1757 return; 1758 } 1759 mAwContents.onFocusChanged(focused, direction, previouslyFocusedRect); 1760 } 1761 1762 @Override 1763 public boolean setFrame(final int left, final int top, final int right, final int bottom) { 1764 return mWebViewPrivate.super_setFrame(left, top, right, bottom); 1765 } 1766 1767 @Override 1768 public void onSizeChanged(final int w, final int h, final int ow, final int oh) { 1769 if (checkNeedsPost()) { 1770 mRunQueue.addTask(new Runnable() { 1771 @Override 1772 public void run() { 1773 onSizeChanged(w, h, ow, oh); 1774 } 1775 }); 1776 return; 1777 } 1778 mAwContents.onSizeChanged(w, h, ow, oh); 1779 } 1780 1781 @Override 1782 public void onScrollChanged(int l, int t, int oldl, int oldt) { 1783 } 1784 1785 @Override 1786 public boolean dispatchKeyEvent(final KeyEvent event) { 1787 mFactory.startYourEngines(false); 1788 if (checkNeedsPost()) { 1789 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1790 @Override 1791 public Boolean call() { 1792 return dispatchKeyEvent(event); 1793 } 1794 }); 1795 return ret; 1796 } 1797 return mAwContents.dispatchKeyEvent(event); 1798 } 1799 1800 @Override 1801 public boolean onTouchEvent(final MotionEvent ev) { 1802 mFactory.startYourEngines(false); 1803 if (checkNeedsPost()) { 1804 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1805 @Override 1806 public Boolean call() { 1807 return onTouchEvent(ev); 1808 } 1809 }); 1810 return ret; 1811 } 1812 return mAwContents.onTouchEvent(ev); 1813 } 1814 1815 @Override 1816 public boolean onHoverEvent(final MotionEvent event) { 1817 mFactory.startYourEngines(false); 1818 if (checkNeedsPost()) { 1819 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1820 @Override 1821 public Boolean call() { 1822 return onHoverEvent(event); 1823 } 1824 }); 1825 return ret; 1826 } 1827 return mAwContents.onHoverEvent(event); 1828 } 1829 1830 @Override 1831 public boolean onGenericMotionEvent(final MotionEvent event) { 1832 mFactory.startYourEngines(false); 1833 if (checkNeedsPost()) { 1834 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1835 @Override 1836 public Boolean call() { 1837 return onGenericMotionEvent(event); 1838 } 1839 }); 1840 return ret; 1841 } 1842 return mAwContents.onGenericMotionEvent(event); 1843 } 1844 1845 @Override 1846 public boolean onTrackballEvent(MotionEvent ev) { 1847 // Trackball event not handled, which eventually gets converted to DPAD keyevents 1848 return false; 1849 } 1850 1851 @Override 1852 public boolean requestFocus(final int direction, final Rect previouslyFocusedRect) { 1853 mFactory.startYourEngines(false); 1854 if (checkNeedsPost()) { 1855 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1856 @Override 1857 public Boolean call() { 1858 return requestFocus(direction, previouslyFocusedRect); 1859 } 1860 }); 1861 return ret; 1862 } 1863 mAwContents.requestFocus(); 1864 return mWebViewPrivate.super_requestFocus(direction, previouslyFocusedRect); 1865 } 1866 1867 @Override 1868 public void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) { 1869 mFactory.startYourEngines(false); 1870 if (checkNeedsPost()) { 1871 runVoidTaskOnUiThreadBlocking(new Runnable() { 1872 @Override 1873 public void run() { 1874 onMeasure(widthMeasureSpec, heightMeasureSpec); 1875 } 1876 }); 1877 return; 1878 } 1879 mAwContents.onMeasure(widthMeasureSpec, heightMeasureSpec); 1880 } 1881 1882 @Override 1883 public boolean requestChildRectangleOnScreen(final View child, final Rect rect, 1884 final boolean immediate) { 1885 mFactory.startYourEngines(false); 1886 if (checkNeedsPost()) { 1887 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1888 @Override 1889 public Boolean call() { 1890 return requestChildRectangleOnScreen(child, rect, immediate); 1891 } 1892 }); 1893 return ret; 1894 } 1895 return mAwContents.requestChildRectangleOnScreen(child, rect, immediate); 1896 } 1897 1898 @Override 1899 public void setBackgroundColor(final int color) { 1900 mFactory.startYourEngines(false); 1901 if (checkNeedsPost()) { 1902 ThreadUtils.postOnUiThread(new Runnable() { 1903 @Override 1904 public void run() { 1905 setBackgroundColor(color); 1906 } 1907 }); 1908 return; 1909 } 1910 mAwContents.setBackgroundColor(color); 1911 } 1912 1913 @Override 1914 public void setLayerType(final int layerType, final Paint paint) { 1915 mFactory.startYourEngines(false); 1916 if (checkNeedsPost()) { 1917 ThreadUtils.postOnUiThread(new Runnable() { 1918 @Override 1919 public void run() { 1920 setLayerType(layerType, paint); 1921 } 1922 }); 1923 return; 1924 } 1925 mAwContents.setLayerType(layerType, paint); 1926 } 1927 1928 // Remove from superclass 1929 public void preDispatchDraw(Canvas canvas) { 1930 // TODO(leandrogracia): remove this method from WebViewProvider if we think 1931 // we won't need it again. 1932 } 1933 1934 // WebViewProvider.ScrollDelegate implementation ---------------------------------------------- 1935 1936 @Override 1937 public int computeHorizontalScrollRange() { 1938 mFactory.startYourEngines(false); 1939 if (checkNeedsPost()) { 1940 int ret = runOnUiThreadBlocking(new Callable<Integer>() { 1941 @Override 1942 public Integer call() { 1943 return computeHorizontalScrollRange(); 1944 } 1945 }); 1946 return ret; 1947 } 1948 return mAwContents.computeHorizontalScrollRange(); 1949 } 1950 1951 @Override 1952 public int computeHorizontalScrollOffset() { 1953 mFactory.startYourEngines(false); 1954 if (checkNeedsPost()) { 1955 int ret = runOnUiThreadBlocking(new Callable<Integer>() { 1956 @Override 1957 public Integer call() { 1958 return computeHorizontalScrollOffset(); 1959 } 1960 }); 1961 return ret; 1962 } 1963 return mAwContents.computeHorizontalScrollOffset(); 1964 } 1965 1966 @Override 1967 public int computeVerticalScrollRange() { 1968 mFactory.startYourEngines(false); 1969 if (checkNeedsPost()) { 1970 int ret = runOnUiThreadBlocking(new Callable<Integer>() { 1971 @Override 1972 public Integer call() { 1973 return computeVerticalScrollRange(); 1974 } 1975 }); 1976 return ret; 1977 } 1978 return mAwContents.computeVerticalScrollRange(); 1979 } 1980 1981 @Override 1982 public int computeVerticalScrollOffset() { 1983 mFactory.startYourEngines(false); 1984 if (checkNeedsPost()) { 1985 int ret = runOnUiThreadBlocking(new Callable<Integer>() { 1986 @Override 1987 public Integer call() { 1988 return computeVerticalScrollOffset(); 1989 } 1990 }); 1991 return ret; 1992 } 1993 return mAwContents.computeVerticalScrollOffset(); 1994 } 1995 1996 @Override 1997 public int computeVerticalScrollExtent() { 1998 mFactory.startYourEngines(false); 1999 if (checkNeedsPost()) { 2000 int ret = runOnUiThreadBlocking(new Callable<Integer>() { 2001 @Override 2002 public Integer call() { 2003 return computeVerticalScrollExtent(); 2004 } 2005 }); 2006 return ret; 2007 } 2008 return mAwContents.computeVerticalScrollExtent(); 2009 } 2010 2011 @Override 2012 public void computeScroll() { 2013 mFactory.startYourEngines(false); 2014 if (checkNeedsPost()) { 2015 runVoidTaskOnUiThreadBlocking(new Runnable() { 2016 @Override 2017 public void run() { 2018 computeScroll(); 2019 } 2020 }); 2021 return; 2022 } 2023 mAwContents.computeScroll(); 2024 } 2025 2026 @Override 2027 public PrintDocumentAdapter createPrintDocumentAdapter() { 2028 checkThread(); 2029 return new AwPrintDocumentAdapter(mAwContents.getPdfExporter()); 2030 } 2031 2032 // AwContents.InternalAccessDelegate implementation -------------------------------------- 2033 private class InternalAccessAdapter implements AwContents.InternalAccessDelegate { 2034 @Override 2035 public boolean drawChild(Canvas arg0, View arg1, long arg2) { 2036 UnimplementedWebViewApi.invoke(); 2037 return false; 2038 } 2039 2040 @Override 2041 public boolean super_onKeyUp(int arg0, KeyEvent arg1) { 2042 // Intentional no-op 2043 return false; 2044 } 2045 2046 @Override 2047 public boolean super_dispatchKeyEventPreIme(KeyEvent arg0) { 2048 UnimplementedWebViewApi.invoke(); 2049 return false; 2050 } 2051 2052 @Override 2053 public boolean super_dispatchKeyEvent(KeyEvent event) { 2054 return mWebViewPrivate.super_dispatchKeyEvent(event); 2055 } 2056 2057 @Override 2058 public boolean super_onGenericMotionEvent(MotionEvent arg0) { 2059 return mWebViewPrivate.super_onGenericMotionEvent(arg0); 2060 } 2061 2062 @Override 2063 public void super_onConfigurationChanged(Configuration arg0) { 2064 // Intentional no-op 2065 } 2066 2067 @Override 2068 public int super_getScrollBarStyle() { 2069 return mWebViewPrivate.super_getScrollBarStyle(); 2070 } 2071 2072 @Override 2073 public boolean awakenScrollBars() { 2074 mWebViewPrivate.awakenScrollBars(0); 2075 // TODO: modify the WebView.PrivateAccess to provide a return value. 2076 return true; 2077 } 2078 2079 @Override 2080 public boolean super_awakenScrollBars(int arg0, boolean arg1) { 2081 // TODO: need method on WebView.PrivateAccess? 2082 UnimplementedWebViewApi.invoke(); 2083 return false; 2084 } 2085 2086 @Override 2087 public void onScrollChanged(int l, int t, int oldl, int oldt) { 2088 // Intentional no-op. 2089 // Chromium calls this directly to trigger accessibility events. That isn't needed 2090 // for WebView since super_scrollTo invokes onScrollChanged for us. 2091 } 2092 2093 @Override 2094 public void overScrollBy(int deltaX, int deltaY, 2095 int scrollX, int scrollY, 2096 int scrollRangeX, int scrollRangeY, 2097 int maxOverScrollX, int maxOverScrollY, 2098 boolean isTouchEvent) { 2099 mWebViewPrivate.overScrollBy(deltaX, deltaY, scrollX, scrollY, 2100 scrollRangeX, scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent); 2101 } 2102 2103 @Override 2104 public void super_scrollTo(int scrollX, int scrollY) { 2105 mWebViewPrivate.super_scrollTo(scrollX, scrollY); 2106 } 2107 2108 @Override 2109 public void setMeasuredDimension(int measuredWidth, int measuredHeight) { 2110 mWebViewPrivate.setMeasuredDimension(measuredWidth, measuredHeight); 2111 } 2112 2113 @Override 2114 public boolean requestDrawGL(Canvas canvas) { 2115 if (mGLfunctor == null) { 2116 mGLfunctor = new DrawGLFunctor(mAwContents.getAwDrawGLViewContext()); 2117 } 2118 return mGLfunctor.requestDrawGL((HardwareCanvas)canvas, mWebView.getViewRootImpl()); 2119 } 2120 2121 // @Override 2122 public boolean executeHardwareAction(Runnable action) { 2123 return mWebView.executeHardwareAction(action); 2124 } 2125 } 2126} 2127