1 // Copyright 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 package org.chromium.android_webview; 6 7 import android.annotation.SuppressLint; 8 import android.app.Activity; 9 import android.content.ComponentCallbacks2; 10 import android.content.Context; 11 import android.content.res.Configuration; 12 import android.graphics.Bitmap; 13 import android.graphics.Canvas; 14 import android.graphics.Color; 15 import android.graphics.Paint; 16 import android.graphics.Picture; 17 import android.graphics.Rect; 18 import android.net.Uri; 19 import android.net.http.SslCertificate; 20 import android.os.AsyncTask; 21 import android.os.Build; 22 import android.os.Bundle; 23 import android.os.Handler; 24 import android.os.Message; 25 import android.text.TextUtils; 26 import android.util.Log; 27 import android.util.Pair; 28 import android.view.KeyEvent; 29 import android.view.MotionEvent; 30 import android.view.View; 31 import android.view.ViewGroup; 32 import android.view.accessibility.AccessibilityEvent; 33 import android.view.accessibility.AccessibilityNodeInfo; 34 import android.view.accessibility.AccessibilityNodeProvider; 35 import android.view.inputmethod.EditorInfo; 36 import android.view.inputmethod.InputConnection; 37 import android.webkit.GeolocationPermissions; 38 import android.webkit.ValueCallback; 39 import android.widget.OverScroller; 40 41 import org.chromium.android_webview.permission.AwPermissionRequest; 42 import org.chromium.base.CalledByNative; 43 import org.chromium.base.JNINamespace; 44 import org.chromium.base.ThreadUtils; 45 import org.chromium.base.VisibleForTesting; 46 import org.chromium.components.navigation_interception.InterceptNavigationDelegate; 47 import org.chromium.components.navigation_interception.NavigationParams; 48 import org.chromium.content.browser.ContentSettings; 49 import org.chromium.content.browser.ContentViewClient; 50 import org.chromium.content.browser.ContentViewCore; 51 import org.chromium.content.browser.ContentViewStatics; 52 import org.chromium.content.browser.SmartClipProvider; 53 import org.chromium.content.browser.WebContentsObserverAndroid; 54 import org.chromium.content.common.CleanupReference; 55 import org.chromium.content_public.browser.GestureStateListener; 56 import org.chromium.content_public.browser.JavaScriptCallback; 57 import org.chromium.content_public.browser.LoadUrlParams; 58 import org.chromium.content_public.browser.NavigationController; 59 import org.chromium.content_public.browser.NavigationHistory; 60 import org.chromium.content_public.browser.WebContents; 61 import org.chromium.content_public.common.Referrer; 62 import org.chromium.ui.base.ActivityWindowAndroid; 63 import org.chromium.ui.base.PageTransitionTypes; 64 import org.chromium.ui.base.WindowAndroid; 65 import org.chromium.ui.gfx.DeviceDisplayInfo; 66 67 import java.io.File; 68 import java.lang.annotation.Annotation; 69 import java.net.MalformedURLException; 70 import java.net.URL; 71 import java.util.HashMap; 72 import java.util.Locale; 73 import java.util.Map; 74 import java.util.concurrent.Callable; 75 76 /** 77 * Exposes the native AwContents class, and together these classes wrap the ContentViewCore 78 * and Browser components that are required to implement Android WebView API. This is the 79 * primary entry point for the WebViewProvider implementation; it holds a 1:1 object 80 * relationship with application WebView instances. 81 * (We define this class independent of the hidden WebViewProvider interfaces, to allow 82 * continuous build & test in the open source SDK-based tree). 83 */ 84 @JNINamespace("android_webview") 85 public class AwContents implements SmartClipProvider { 86 private static final String TAG = "AwContents"; 87 88 private static final String WEB_ARCHIVE_EXTENSION = ".mht"; 89 90 // Used to avoid enabling zooming in / out if resulting zooming will 91 // produce little visible difference. 92 private static final float ZOOM_CONTROLS_EPSILON = 0.007f; 93 94 /** 95 * WebKit hit test related data strcutre. These are used to implement 96 * getHitTestResult, requestFocusNodeHref, requestImageRef methods in WebView. 97 * All values should be updated together. The native counterpart is 98 * AwHitTestData. 99 */ 100 public static class HitTestData { 101 // Used in getHitTestResult. 102 public int hitTestResultType; 103 public String hitTestResultExtraData; 104 105 // Used in requestFocusNodeHref (all three) and requestImageRef (only imgSrc). 106 public String href; 107 public String anchorText; 108 public String imgSrc; 109 } 110 111 /** 112 * Interface that consumers of {@link AwContents} must implement to allow the proper 113 * dispatching of view methods through the containing view. 114 */ 115 public interface InternalAccessDelegate extends ContentViewCore.InternalAccessDelegate { 116 117 /** 118 * @see View#overScrollBy(int, int, int, int, int, int, int, int, boolean); 119 */ 120 void overScrollBy(int deltaX, int deltaY, 121 int scrollX, int scrollY, 122 int scrollRangeX, int scrollRangeY, 123 int maxOverScrollX, int maxOverScrollY, 124 boolean isTouchEvent); 125 126 /** 127 * @see View#scrollTo(int, int) 128 */ 129 void super_scrollTo(int scrollX, int scrollY); 130 131 /** 132 * @see View#setMeasuredDimension(int, int) 133 */ 134 void setMeasuredDimension(int measuredWidth, int measuredHeight); 135 136 /** 137 * @see View#getScrollBarStyle() 138 */ 139 int super_getScrollBarStyle(); 140 } 141 142 /** 143 * Interface that consumers of {@link AwContents} must implement to support 144 * native GL rendering. 145 */ 146 public interface NativeGLDelegate { 147 /** 148 * Requests a callback on the native DrawGL method (see getAwDrawGLFunction) 149 * if called from within onDraw, |canvas| will be non-null and hardware accelerated. 150 * Otherwise, |canvas| will be null, and the container view itself will be hardware 151 * accelerated. If |waitForCompletion| is true, this method will not return until 152 * functor has returned. 153 * Should avoid setting |waitForCompletion| when |canvas| is not null. 154 * |containerView| is the view where the AwContents should be drawn. 155 * 156 * @return false indicates the GL draw request was not accepted, and the caller 157 * should fallback to the SW path. 158 */ 159 boolean requestDrawGL(Canvas canvas, boolean waitForCompletion, View containerView); 160 161 /** 162 * Detaches the GLFunctor from the view tree. 163 */ 164 void detachGLFunctor(); 165 } 166 167 /** 168 * Class to facilitate dependency injection. Subclasses by test code to provide mock versions of 169 * certain AwContents dependencies. 170 */ 171 public static class DependencyFactory { 172 public AwLayoutSizer createLayoutSizer() { 173 return new AwLayoutSizer(); 174 } 175 176 public AwScrollOffsetManager createScrollOffsetManager( 177 AwScrollOffsetManager.Delegate delegate, OverScroller overScroller) { 178 return new AwScrollOffsetManager(delegate, overScroller); 179 } 180 } 181 182 private long mNativeAwContents; 183 private final AwBrowserContext mBrowserContext; 184 private ViewGroup mContainerView; 185 private final AwLayoutChangeListener mLayoutChangeListener; 186 private final Context mContext; 187 private ContentViewCore mContentViewCore; 188 private WindowAndroid mWindowAndroid; 189 private WebContents mWebContents; 190 private NavigationController mNavigationController; 191 private final AwContentsClient mContentsClient; 192 private final AwContentViewClient mContentViewClient; 193 private WebContentsObserverAndroid mWebContentsObserver; 194 private final AwContentsClientBridge mContentsClientBridge; 195 private final AwWebContentsDelegateAdapter mWebContentsDelegate; 196 private final AwContentsIoThreadClient mIoThreadClient; 197 private final InterceptNavigationDelegateImpl mInterceptNavigationDelegate; 198 private InternalAccessDelegate mInternalAccessAdapter; 199 private final NativeGLDelegate mNativeGLDelegate; 200 private final AwLayoutSizer mLayoutSizer; 201 private final AwZoomControls mZoomControls; 202 private final AwScrollOffsetManager mScrollOffsetManager; 203 private OverScrollGlow mOverScrollGlow; 204 // This can be accessed on any thread after construction. See AwContentsIoThreadClient. 205 private final AwSettings mSettings; 206 private final ScrollAccessibilityHelper mScrollAccessibilityHelper; 207 208 private boolean mIsPaused; 209 private boolean mIsViewVisible; 210 private boolean mIsWindowVisible; 211 private boolean mIsAttachedToWindow; 212 private Bitmap mFavicon; 213 private boolean mHasRequestedVisitedHistoryFromClient; 214 // TODO(boliu): This should be in a global context, not per webview. 215 private final double mDIPScale; 216 217 // The base background color, i.e. not accounting for any CSS body from the current page. 218 private int mBaseBackgroundColor = Color.WHITE; 219 220 // Must call nativeUpdateLastHitTestData first to update this before use. 221 private final HitTestData mPossiblyStaleHitTestData = new HitTestData(); 222 223 private final DefaultVideoPosterRequestHandler mDefaultVideoPosterRequestHandler; 224 225 // Bound method for suppling Picture instances to the AwContentsClient. Will be null if the 226 // picture listener API has not yet been enabled, or if it is using invalidation-only mode. 227 private Callable<Picture> mPictureListenerContentProvider; 228 229 private boolean mContainerViewFocused; 230 private boolean mWindowFocused; 231 232 // These come from the compositor and are updated synchronously (in contrast to the values in 233 // ContentViewCore, which are updated at end of every frame). 234 private float mPageScaleFactor = 1.0f; 235 private float mMinPageScaleFactor = 1.0f; 236 private float mMaxPageScaleFactor = 1.0f; 237 private float mContentWidthDip; 238 private float mContentHeightDip; 239 240 private AwAutofillClient mAwAutofillClient; 241 242 private AwPdfExporter mAwPdfExporter; 243 244 private AwViewMethods mAwViewMethods; 245 private final FullScreenTransitionsState mFullScreenTransitionsState; 246 247 // This flag indicates that ShouldOverrideUrlNavigation should be posted 248 // through the resourcethrottle. This is only used for popup windows. 249 private boolean mDeferredShouldOverrideUrlLoadingIsPendingForPopup; 250 251 // The framework may temporarily detach our container view, for example during layout if 252 // we are a child of a ListView. This may cause many toggles of View focus, which we suppress 253 // when in this state. 254 private boolean mTemporarilyDetached; 255 256 // True when this AwContents has been destroyed. 257 // Do not use directly, call isDestroyed() instead. 258 private boolean mIsDestroyed = false; 259 260 private static final class DestroyRunnable implements Runnable { 261 private final long mNativeAwContents; 262 private DestroyRunnable(long nativeAwContents) { 263 mNativeAwContents = nativeAwContents; 264 } 265 @Override 266 public void run() { 267 nativeDestroy(mNativeAwContents); 268 } 269 } 270 271 /** 272 * A class that stores the state needed to enter and exit fullscreen. 273 */ 274 private static class FullScreenTransitionsState { 275 private final ViewGroup mInitialContainerView; 276 private final InternalAccessDelegate mInitialInternalAccessAdapter; 277 private final AwViewMethods mInitialAwViewMethods; 278 private FullScreenView mFullScreenView; 279 280 private FullScreenTransitionsState(ViewGroup initialContainerView, 281 InternalAccessDelegate initialInternalAccessAdapter, 282 AwViewMethods initialAwViewMethods) { 283 mInitialContainerView = initialContainerView; 284 mInitialInternalAccessAdapter = initialInternalAccessAdapter; 285 mInitialAwViewMethods = initialAwViewMethods; 286 } 287 288 private void enterFullScreen(FullScreenView fullScreenView) { 289 mFullScreenView = fullScreenView; 290 } 291 292 private void exitFullScreen() { 293 mFullScreenView = null; 294 } 295 296 private boolean isFullScreen() { 297 return mFullScreenView != null; 298 } 299 300 private ViewGroup getInitialContainerView() { 301 return mInitialContainerView; 302 } 303 304 private InternalAccessDelegate getInitialInternalAccessDelegate() { 305 return mInitialInternalAccessAdapter; 306 } 307 308 private AwViewMethods getInitialAwViewMethods() { 309 return mInitialAwViewMethods; 310 } 311 312 private FullScreenView getFullScreenView() { 313 return mFullScreenView; 314 } 315 } 316 317 // Reference to the active mNativeAwContents pointer while it is active use 318 // (ie before it is destroyed). 319 private CleanupReference mCleanupReference; 320 321 //-------------------------------------------------------------------------------------------- 322 private class IoThreadClientImpl extends AwContentsIoThreadClient { 323 // All methods are called on the IO thread. 324 325 @Override 326 public int getCacheMode() { 327 return mSettings.getCacheMode(); 328 } 329 330 @Override 331 public AwWebResourceResponse shouldInterceptRequest( 332 AwContentsClient.ShouldInterceptRequestParams params) { 333 String url = params.url; 334 AwWebResourceResponse awWebResourceResponse; 335 // Return the response directly if the url is default video poster url. 336 awWebResourceResponse = mDefaultVideoPosterRequestHandler.shouldInterceptRequest(url); 337 if (awWebResourceResponse != null) return awWebResourceResponse; 338 339 awWebResourceResponse = mContentsClient.shouldInterceptRequest(params); 340 341 if (awWebResourceResponse == null) { 342 mContentsClient.getCallbackHelper().postOnLoadResource(url); 343 } 344 345 if (params.isMainFrame && awWebResourceResponse != null && 346 awWebResourceResponse.getData() == null) { 347 // In this case the intercepted URLRequest job will simulate an empty response 348 // which doesn't trigger the onReceivedError callback. For WebViewClassic 349 // compatibility we synthesize that callback. http://crbug.com/180950 350 mContentsClient.getCallbackHelper().postOnReceivedError( 351 ErrorCodeConversionHelper.ERROR_UNKNOWN, 352 null /* filled in by the glue layer */, url); 353 } 354 return awWebResourceResponse; 355 } 356 357 @Override 358 public boolean shouldBlockContentUrls() { 359 return !mSettings.getAllowContentAccess(); 360 } 361 362 @Override 363 public boolean shouldBlockFileUrls() { 364 return !mSettings.getAllowFileAccess(); 365 } 366 367 @Override 368 public boolean shouldBlockNetworkLoads() { 369 return mSettings.getBlockNetworkLoads(); 370 } 371 372 @Override 373 public boolean shouldAcceptThirdPartyCookies() { 374 return mSettings.getAcceptThirdPartyCookies(); 375 } 376 377 @Override 378 public void onDownloadStart(String url, String userAgent, 379 String contentDisposition, String mimeType, long contentLength) { 380 mContentsClient.getCallbackHelper().postOnDownloadStart(url, userAgent, 381 contentDisposition, mimeType, contentLength); 382 } 383 384 @Override 385 public void newLoginRequest(String realm, String account, String args) { 386 mContentsClient.getCallbackHelper().postOnReceivedLoginRequest(realm, account, args); 387 } 388 } 389 390 //-------------------------------------------------------------------------------------------- 391 // When the navigation is for a newly created WebView (i.e. a popup), intercept the navigation 392 // here for implementing shouldOverrideUrlLoading. This is to send the shouldOverrideUrlLoading 393 // callback to the correct WebViewClient that is associated with the WebView. 394 // Otherwise, use this delegate only to post onPageStarted messages. 395 // 396 // We are not using WebContentsObserver.didStartLoading because of stale URLs, out of order 397 // onPageStarted's and double onPageStarted's. 398 // 399 private class InterceptNavigationDelegateImpl implements InterceptNavigationDelegate { 400 @Override 401 public boolean shouldIgnoreNavigation(NavigationParams navigationParams) { 402 final String url = navigationParams.url; 403 boolean ignoreNavigation = false; 404 if (mDeferredShouldOverrideUrlLoadingIsPendingForPopup) { 405 mDeferredShouldOverrideUrlLoadingIsPendingForPopup = false; 406 // If this is used for all navigations in future, cases for application initiated 407 // load, redirect and backforward should also be filtered out. 408 if (!navigationParams.isPost) { 409 ignoreNavigation = mContentsClient.shouldOverrideUrlLoading(url); 410 } 411 } 412 // The shouldOverrideUrlLoading call might have resulted in posting messages to the 413 // UI thread. Using sendMessage here (instead of calling onPageStarted directly) 414 // will allow those to run in order. 415 if (!ignoreNavigation) { 416 mContentsClient.getCallbackHelper().postOnPageStarted(url); 417 } 418 return ignoreNavigation; 419 } 420 } 421 422 //-------------------------------------------------------------------------------------------- 423 private class AwLayoutSizerDelegate implements AwLayoutSizer.Delegate { 424 @Override 425 public void requestLayout() { 426 mContainerView.requestLayout(); 427 } 428 429 @Override 430 public void setMeasuredDimension(int measuredWidth, int measuredHeight) { 431 mInternalAccessAdapter.setMeasuredDimension(measuredWidth, measuredHeight); 432 } 433 434 @Override 435 public boolean isLayoutParamsHeightWrapContent() { 436 return mContainerView.getLayoutParams() != null && 437 mContainerView.getLayoutParams().height == ViewGroup.LayoutParams.WRAP_CONTENT; 438 } 439 440 @Override 441 public void setForceZeroLayoutHeight(boolean forceZeroHeight) { 442 getSettings().setForceZeroLayoutHeight(forceZeroHeight); 443 } 444 } 445 446 //-------------------------------------------------------------------------------------------- 447 private class AwScrollOffsetManagerDelegate implements AwScrollOffsetManager.Delegate { 448 @Override 449 public void overScrollContainerViewBy(int deltaX, int deltaY, int scrollX, int scrollY, 450 int scrollRangeX, int scrollRangeY, boolean isTouchEvent) { 451 mInternalAccessAdapter.overScrollBy(deltaX, deltaY, scrollX, scrollY, 452 scrollRangeX, scrollRangeY, 0, 0, isTouchEvent); 453 } 454 455 @Override 456 public void scrollContainerViewTo(int x, int y) { 457 mInternalAccessAdapter.super_scrollTo(x, y); 458 } 459 460 @Override 461 public void scrollNativeTo(int x, int y) { 462 if (!isDestroyed()) nativeScrollTo(mNativeAwContents, x, y); 463 } 464 465 @Override 466 public int getContainerViewScrollX() { 467 return mContainerView.getScrollX(); 468 } 469 470 @Override 471 public int getContainerViewScrollY() { 472 return mContainerView.getScrollY(); 473 } 474 475 @Override 476 public void invalidate() { 477 mContainerView.invalidate(); 478 } 479 } 480 481 //-------------------------------------------------------------------------------------------- 482 private class AwGestureStateListener extends GestureStateListener { 483 @Override 484 public void onPinchStarted() { 485 // While it's possible to re-layout the view during a pinch gesture, the effect is very 486 // janky (especially that the page scale update notification comes from the renderer 487 // main thread, not from the impl thread, so it's usually out of sync with what's on 488 // screen). It's also quite expensive to do a re-layout, so we simply postpone 489 // re-layout for the duration of the gesture. This is compatible with what 490 // WebViewClassic does. 491 mLayoutSizer.freezeLayoutRequests(); 492 } 493 494 @Override 495 public void onPinchEnded() { 496 mLayoutSizer.unfreezeLayoutRequests(); 497 } 498 499 @Override 500 public void onFlingCancelGesture() { 501 mScrollOffsetManager.onFlingCancelGesture(); 502 } 503 504 @Override 505 public void onUnhandledFlingStartEvent(int velocityX, int velocityY) { 506 mScrollOffsetManager.onUnhandledFlingStartEvent(velocityX, velocityY); 507 } 508 509 @Override 510 public void onScrollUpdateGestureConsumed() { 511 mScrollAccessibilityHelper.postViewScrolledAccessibilityEventCallback(); 512 } 513 } 514 515 //-------------------------------------------------------------------------------------------- 516 private class AwComponentCallbacks implements ComponentCallbacks2 { 517 @Override 518 public void onTrimMemory(final int level) { 519 if (isDestroyed()) return; 520 boolean visibleRectEmpty = getGlobalVisibleRect().isEmpty(); 521 final boolean visible = mIsViewVisible && mIsWindowVisible && !visibleRectEmpty; 522 nativeTrimMemory(mNativeAwContents, level, visible); 523 } 524 525 @Override 526 public void onLowMemory() {} 527 528 @Override 529 public void onConfigurationChanged(Configuration configuration) {} 530 }; 531 532 //-------------------------------------------------------------------------------------------- 533 private class AwLayoutChangeListener implements View.OnLayoutChangeListener { 534 @Override 535 public void onLayoutChange(View v, int left, int top, int right, int bottom, 536 int oldLeft, int oldTop, int oldRight, int oldBottom) { 537 assert v == mContainerView; 538 mLayoutSizer.onLayoutChange(); 539 } 540 } 541 542 /** 543 * @param browserContext the browsing context to associate this view contents with. 544 * @param containerView the view-hierarchy item this object will be bound to. 545 * @param context the context to use, usually containerView.getContext(). 546 * @param internalAccessAdapter to access private methods on containerView. 547 * @param nativeGLDelegate to access the GL functor provided by the WebView. 548 * @param contentsClient will receive API callbacks from this WebView Contents. 549 * @param awSettings AwSettings instance used to configure the AwContents. 550 * 551 * This constructor uses the default view sizing policy. 552 */ 553 public AwContents(AwBrowserContext browserContext, ViewGroup containerView, Context context, 554 InternalAccessDelegate internalAccessAdapter, NativeGLDelegate nativeGLDelegate, 555 AwContentsClient contentsClient, AwSettings awSettings) { 556 this(browserContext, containerView, context, internalAccessAdapter, nativeGLDelegate, 557 contentsClient, awSettings, new DependencyFactory()); 558 } 559 560 /** 561 * @param dependencyFactory an instance of the DependencyFactory used to provide instances of 562 * classes that this class depends on. 563 * 564 * This version of the constructor is used in test code to inject test versions of the above 565 * documented classes. 566 */ 567 public AwContents(AwBrowserContext browserContext, ViewGroup containerView, Context context, 568 InternalAccessDelegate internalAccessAdapter, NativeGLDelegate nativeGLDelegate, 569 AwContentsClient contentsClient, AwSettings settings, 570 DependencyFactory dependencyFactory) { 571 mBrowserContext = browserContext; 572 mContainerView = containerView; 573 mContext = context; 574 mInternalAccessAdapter = internalAccessAdapter; 575 mNativeGLDelegate = nativeGLDelegate; 576 mContentsClient = contentsClient; 577 mAwViewMethods = new AwViewMethodsImpl(); 578 mFullScreenTransitionsState = new FullScreenTransitionsState( 579 mContainerView, mInternalAccessAdapter, mAwViewMethods); 580 mContentViewClient = new AwContentViewClient(contentsClient, settings, this, mContext); 581 mLayoutSizer = dependencyFactory.createLayoutSizer(); 582 mSettings = settings; 583 mDIPScale = DeviceDisplayInfo.create(mContext).getDIPScale(); 584 mLayoutSizer.setDelegate(new AwLayoutSizerDelegate()); 585 mLayoutSizer.setDIPScale(mDIPScale); 586 mWebContentsDelegate = new AwWebContentsDelegateAdapter( 587 contentsClient, mContainerView, mContext); 588 mContentsClientBridge = new AwContentsClientBridge(contentsClient, 589 mBrowserContext.getKeyStore(), AwContentsStatics.getClientCertLookupTable()); 590 mZoomControls = new AwZoomControls(this); 591 mIoThreadClient = new IoThreadClientImpl(); 592 mInterceptNavigationDelegate = new InterceptNavigationDelegateImpl(); 593 594 AwSettings.ZoomSupportChangeListener zoomListener = 595 new AwSettings.ZoomSupportChangeListener() { 596 @Override 597 public void onGestureZoomSupportChanged( 598 boolean supportsDoubleTapZoom, boolean supportsMultiTouchZoom) { 599 if (isDestroyed()) return; 600 mContentViewCore.updateDoubleTapSupport(supportsDoubleTapZoom); 601 mContentViewCore.updateMultiTouchZoomSupport(supportsMultiTouchZoom); 602 } 603 604 }; 605 mSettings.setZoomListener(zoomListener); 606 mDefaultVideoPosterRequestHandler = new DefaultVideoPosterRequestHandler(mContentsClient); 607 mSettings.setDefaultVideoPosterURL( 608 mDefaultVideoPosterRequestHandler.getDefaultVideoPosterURL()); 609 mSettings.setDIPScale(mDIPScale); 610 mScrollOffsetManager = dependencyFactory.createScrollOffsetManager( 611 new AwScrollOffsetManagerDelegate(), new OverScroller(mContext)); 612 mScrollAccessibilityHelper = new ScrollAccessibilityHelper(mContainerView); 613 614 setOverScrollMode(mContainerView.getOverScrollMode()); 615 setScrollBarStyle(mInternalAccessAdapter.super_getScrollBarStyle()); 616 mLayoutChangeListener = new AwLayoutChangeListener(); 617 mContainerView.addOnLayoutChangeListener(mLayoutChangeListener); 618 619 setNewAwContents(nativeInit(mBrowserContext)); 620 621 onContainerViewChanged(); 622 } 623 624 private static ContentViewCore createAndInitializeContentViewCore(ViewGroup containerView, 625 Context context, InternalAccessDelegate internalDispatcher, long nativeWebContents, 626 GestureStateListener gestureStateListener, 627 ContentViewClient contentViewClient, 628 ContentViewCore.ZoomControlsDelegate zoomControlsDelegate, 629 WindowAndroid windowAndroid) { 630 ContentViewCore contentViewCore = new ContentViewCore(context); 631 contentViewCore.initialize(containerView, internalDispatcher, nativeWebContents, 632 windowAndroid); 633 contentViewCore.addGestureStateListener(gestureStateListener); 634 contentViewCore.setContentViewClient(contentViewClient); 635 contentViewCore.setZoomControlsDelegate(zoomControlsDelegate); 636 return contentViewCore; 637 } 638 639 boolean isFullScreen() { 640 return mFullScreenTransitionsState.isFullScreen(); 641 } 642 643 /** 644 * Transitions this {@link AwContents} to fullscreen mode and returns the 645 * {@link View} where the contents will be drawn while in fullscreen, or null 646 * if this AwContents has already been destroyed. 647 */ 648 View enterFullScreen() { 649 assert !isFullScreen(); 650 if (isDestroyed()) return null; 651 652 // Detach to tear down the GL functor if this is still associated with the old 653 // container view. It will be recreated during the next call to onDraw attached to 654 // the new container view. 655 onDetachedFromWindow(); 656 657 // In fullscreen mode FullScreenView owns the AwViewMethodsImpl and AwContents 658 // a NullAwViewMethods. 659 FullScreenView fullScreenView = new FullScreenView(mContext, mAwViewMethods); 660 mFullScreenTransitionsState.enterFullScreen(fullScreenView); 661 mAwViewMethods = new NullAwViewMethods(this, mInternalAccessAdapter, mContainerView); 662 mContainerView.removeOnLayoutChangeListener(mLayoutChangeListener); 663 fullScreenView.addOnLayoutChangeListener(mLayoutChangeListener); 664 665 // Associate this AwContents with the FullScreenView. 666 setInternalAccessAdapter(fullScreenView.getInternalAccessAdapter()); 667 setContainerView(fullScreenView); 668 669 return fullScreenView; 670 } 671 672 /** 673 * Returns this {@link AwContents} to embedded mode, where the {@link AwContents} are drawn 674 * in the WebView. 675 */ 676 void exitFullScreen() { 677 if (!isFullScreen() || isDestroyed()) 678 // exitFullScreen() can be called without a prior call to enterFullScreen() if a 679 // "misbehave" app overrides onShowCustomView but does not add the custom view to 680 // the window. Exiting avoids a crash. 681 return; 682 683 // Detach to tear down the GL functor if this is still associated with the old 684 // container view. It will be recreated during the next call to onDraw attached to 685 // the new container view. 686 // NOTE: we cannot use mAwViewMethods here because its type is NullAwViewMethods. 687 AwViewMethods awViewMethodsImpl = mFullScreenTransitionsState.getInitialAwViewMethods(); 688 awViewMethodsImpl.onDetachedFromWindow(); 689 690 // Swap the view delegates. In embedded mode the FullScreenView owns a 691 // NullAwViewMethods and AwContents the AwViewMethodsImpl. 692 FullScreenView fullscreenView = mFullScreenTransitionsState.getFullScreenView(); 693 fullscreenView.setAwViewMethods(new NullAwViewMethods( 694 this, fullscreenView.getInternalAccessAdapter(), fullscreenView)); 695 mAwViewMethods = awViewMethodsImpl; 696 ViewGroup initialContainerView = mFullScreenTransitionsState.getInitialContainerView(); 697 initialContainerView.addOnLayoutChangeListener(mLayoutChangeListener); 698 fullscreenView.removeOnLayoutChangeListener(mLayoutChangeListener); 699 700 // Re-associate this AwContents with the WebView. 701 setInternalAccessAdapter(mFullScreenTransitionsState.getInitialInternalAccessDelegate()); 702 setContainerView(initialContainerView); 703 704 mFullScreenTransitionsState.exitFullScreen(); 705 } 706 707 private void setInternalAccessAdapter(InternalAccessDelegate internalAccessAdapter) { 708 mInternalAccessAdapter = internalAccessAdapter; 709 mContentViewCore.setContainerViewInternals(mInternalAccessAdapter); 710 } 711 712 private void setContainerView(ViewGroup newContainerView) { 713 mContainerView = newContainerView; 714 mContentViewCore.setContainerView(mContainerView); 715 if (mAwPdfExporter != null) { 716 mAwPdfExporter.setContainerView(mContainerView); 717 } 718 mWebContentsDelegate.setContainerView(mContainerView); 719 720 onContainerViewChanged(); 721 } 722 723 /** 724 * Reconciles the state of this AwContents object with the state of the new container view. 725 */ 726 private void onContainerViewChanged() { 727 // NOTE: mAwViewMethods is used by the old container view, the WebView, so it might refer 728 // to a NullAwViewMethods when in fullscreen. To ensure that the state is reconciled with 729 // the new container view correctly, we bypass mAwViewMethods and use the real 730 // implementation directly. 731 AwViewMethods awViewMethodsImpl = mFullScreenTransitionsState.getInitialAwViewMethods(); 732 awViewMethodsImpl.onVisibilityChanged(mContainerView, mContainerView.getVisibility()); 733 awViewMethodsImpl.onWindowVisibilityChanged(mContainerView.getWindowVisibility()); 734 735 // We should stop running WebView tests in JellyBean devices, see crbug/161864. 736 // Until then we skip calling isAttachedToWindow() as it has only been introduced in K. 737 if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.KITKAT 738 || mContainerView.isAttachedToWindow()) { 739 awViewMethodsImpl.onAttachedToWindow(); 740 } else { 741 awViewMethodsImpl.onDetachedFromWindow(); 742 } 743 awViewMethodsImpl.onSizeChanged( 744 mContainerView.getWidth(), mContainerView.getHeight(), 0, 0); 745 awViewMethodsImpl.onWindowFocusChanged(mContainerView.hasWindowFocus()); 746 awViewMethodsImpl.onFocusChanged(mContainerView.hasFocus(), 0, null); 747 mContainerView.requestLayout(); 748 } 749 750 /* Common initialization routine for adopting a native AwContents instance into this 751 * java instance. 752 * 753 * TAKE CARE! This method can get called multiple times per java instance. Code accordingly. 754 * ^^^^^^^^^ See the native class declaration for more details on relative object lifetimes. 755 */ 756 private void setNewAwContents(long newAwContentsPtr) { 757 if (mNativeAwContents != 0) { 758 destroyNatives(); 759 mContentViewCore = null; 760 mWebContents = null; 761 mNavigationController = null; 762 } 763 764 assert mNativeAwContents == 0 && mCleanupReference == null && mContentViewCore == null; 765 766 mNativeAwContents = newAwContentsPtr; 767 // TODO(joth): when the native and java counterparts of AwBrowserContext are hooked up to 768 // each other, we should update |mBrowserContext| according to the newly received native 769 // WebContent's browser context. 770 771 // The native side object has been bound to this java instance, so now is the time to 772 // bind all the native->java relationships. 773 mCleanupReference = new CleanupReference(this, new DestroyRunnable(mNativeAwContents)); 774 775 long nativeWebContents = nativeGetWebContents(mNativeAwContents); 776 777 mWindowAndroid = mContext instanceof Activity ? 778 new ActivityWindowAndroid((Activity) mContext) : 779 new WindowAndroid(mContext.getApplicationContext()); 780 mContentViewCore = createAndInitializeContentViewCore( 781 mContainerView, mContext, mInternalAccessAdapter, nativeWebContents, 782 new AwGestureStateListener(), mContentViewClient, mZoomControls, mWindowAndroid); 783 nativeSetJavaPeers(mNativeAwContents, this, mWebContentsDelegate, mContentsClientBridge, 784 mIoThreadClient, mInterceptNavigationDelegate); 785 mWebContents = mContentViewCore.getWebContents(); 786 mNavigationController = mWebContents.getNavigationController(); 787 installWebContentsObserver(); 788 mSettings.setWebContents(nativeWebContents); 789 nativeSetDipScale(mNativeAwContents, (float) mDIPScale); 790 mContentViewCore.onShow(); 791 } 792 793 private void installWebContentsObserver() { 794 if (mWebContentsObserver != null) { 795 mWebContentsObserver.detachFromWebContents(); 796 } 797 mWebContentsObserver = new AwWebContentsObserver(mWebContents, mContentsClient); 798 } 799 800 /** 801 * Called on the "source" AwContents that is opening the popup window to 802 * provide the AwContents to host the pop up content. 803 */ 804 public void supplyContentsForPopup(AwContents newContents) { 805 long popupNativeAwContents = nativeReleasePopupAwContents(mNativeAwContents); 806 if (popupNativeAwContents == 0) { 807 Log.w(TAG, "Popup WebView bind failed: no pending content."); 808 if (newContents != null) newContents.destroy(); 809 return; 810 } 811 if (newContents == null) { 812 nativeDestroy(popupNativeAwContents); 813 return; 814 } 815 816 newContents.receivePopupContents(popupNativeAwContents); 817 } 818 819 // Recap: supplyContentsForPopup() is called on the parent window's content, this method is 820 // called on the popup window's content. 821 private void receivePopupContents(long popupNativeAwContents) { 822 mDeferredShouldOverrideUrlLoadingIsPendingForPopup = true; 823 // Save existing view state. 824 final boolean wasAttached = mIsAttachedToWindow; 825 final boolean wasViewVisible = mIsViewVisible; 826 final boolean wasWindowVisible = mIsWindowVisible; 827 final boolean wasPaused = mIsPaused; 828 final boolean wasFocused = mContainerViewFocused; 829 final boolean wasWindowFocused = mWindowFocused; 830 831 // Properly clean up existing mContentViewCore and mNativeAwContents. 832 if (wasFocused) onFocusChanged(false, 0, null); 833 if (wasWindowFocused) onWindowFocusChanged(false); 834 if (wasViewVisible) setViewVisibilityInternal(false); 835 if (wasWindowVisible) setWindowVisibilityInternal(false); 836 if (wasAttached) onDetachedFromWindow(); 837 if (!wasPaused) onPause(); 838 839 // Save injected JavaScript interfaces. 840 Map<String, Pair<Object, Class>> javascriptInterfaces = 841 new HashMap<String, Pair<Object, Class>>(); 842 if (mContentViewCore != null) { 843 javascriptInterfaces.putAll(mContentViewCore.getJavascriptInterfaces()); 844 } 845 846 setNewAwContents(popupNativeAwContents); 847 848 // Finally refresh all view state for mContentViewCore and mNativeAwContents. 849 if (!wasPaused) onResume(); 850 if (wasAttached) { 851 onAttachedToWindow(); 852 postInvalidateOnAnimation(); 853 } 854 onSizeChanged(mContainerView.getWidth(), mContainerView.getHeight(), 0, 0); 855 if (wasWindowVisible) setWindowVisibilityInternal(true); 856 if (wasViewVisible) setViewVisibilityInternal(true); 857 if (wasWindowFocused) onWindowFocusChanged(wasWindowFocused); 858 if (wasFocused) onFocusChanged(true, 0, null); 859 860 // Restore injected JavaScript interfaces. 861 for (Map.Entry<String, Pair<Object, Class>> entry : javascriptInterfaces.entrySet()) { 862 @SuppressWarnings("unchecked") 863 Class<? extends Annotation> requiredAnnotation = entry.getValue().second; 864 mContentViewCore.addPossiblyUnsafeJavascriptInterface( 865 entry.getValue().first, 866 entry.getKey(), 867 requiredAnnotation); 868 } 869 } 870 871 /** 872 * Destroys this object and deletes its native counterpart. 873 */ 874 public void destroy() { 875 mIsDestroyed = true; 876 destroyNatives(); 877 } 878 879 /** 880 * Deletes the native counterpart of this object. 881 */ 882 private void destroyNatives() { 883 if (mCleanupReference != null) { 884 assert mNativeAwContents != 0; 885 // If we are attached, we have to call native detach to clean up 886 // hardware resources. 887 if (mIsAttachedToWindow) { 888 nativeOnDetachedFromWindow(mNativeAwContents); 889 } 890 891 mWebContentsObserver.detachFromWebContents(); 892 mWebContentsObserver = null; 893 mContentViewCore.destroy(); 894 mContentViewCore = null; 895 mNativeAwContents = 0; 896 mWebContents = null; 897 mNavigationController = null; 898 899 mCleanupReference.cleanupNow(); 900 mCleanupReference = null; 901 } 902 903 assert mContentViewCore == null; 904 assert mWebContents == null; 905 assert mNavigationController == null; 906 assert mNativeAwContents == 0; 907 } 908 909 private boolean isDestroyed() { 910 if (mIsDestroyed) { 911 assert mContentViewCore == null; 912 assert mWebContents == null; 913 assert mNavigationController == null; 914 assert mNativeAwContents == 0; 915 } else { 916 assert mContentViewCore != null; 917 assert mWebContents != null; 918 assert mNavigationController != null; 919 assert mNativeAwContents != 0; 920 } 921 return mIsDestroyed; 922 } 923 924 @VisibleForTesting 925 public ContentViewCore getContentViewCore() { 926 return mContentViewCore; 927 } 928 929 @VisibleForTesting 930 public WebContents getWebContents() { 931 return mWebContents; 932 } 933 934 @VisibleForTesting 935 public NavigationController getNavigationController() { 936 return mNavigationController; 937 } 938 939 // Can be called from any thread. 940 public AwSettings getSettings() { 941 return mSettings; 942 } 943 944 public AwPdfExporter getPdfExporter() { 945 if (isDestroyed()) return null; 946 if (mAwPdfExporter == null) { 947 mAwPdfExporter = new AwPdfExporter(mContainerView); 948 nativeCreatePdfExporter(mNativeAwContents, mAwPdfExporter); 949 } 950 return mAwPdfExporter; 951 } 952 953 public static void setAwDrawSWFunctionTable(long functionTablePointer) { 954 nativeSetAwDrawSWFunctionTable(functionTablePointer); 955 } 956 957 public static void setAwDrawGLFunctionTable(long functionTablePointer) { 958 nativeSetAwDrawGLFunctionTable(functionTablePointer); 959 } 960 961 public static long getAwDrawGLFunction() { 962 return nativeGetAwDrawGLFunction(); 963 } 964 965 public static void setShouldDownloadFavicons() { 966 nativeSetShouldDownloadFavicons(); 967 } 968 969 /** 970 * Disables contents of JS-to-Java bridge objects to be inspectable using 971 * Object.keys() method and "for .. in" loops. This is intended for applications 972 * targeting earlier Android releases where this was not possible, and we want 973 * to ensure backwards compatible behavior. 974 */ 975 public void disableJavascriptInterfacesInspection() { 976 if (!isDestroyed()) mContentViewCore.setAllowJavascriptInterfacesInspection(false); 977 } 978 979 /** 980 * Intended for test code. 981 * @return the number of native instances of this class. 982 */ 983 @VisibleForTesting 984 public static int getNativeInstanceCount() { 985 return nativeGetNativeInstanceCount(); 986 } 987 988 public long getAwDrawGLViewContext() { 989 // Only called during early construction, so client should not have had a chance to 990 // call destroy yet. 991 assert !isDestroyed(); 992 993 // Using the native pointer as the returned viewContext. This is matched by the 994 // reinterpret_cast back to BrowserViewRenderer pointer in the native DrawGLFunction. 995 return nativeGetAwDrawGLViewContext(mNativeAwContents); 996 } 997 998 // This is only to avoid heap allocations inside getGlobalVisibleRect. It should treated 999 // as a local variable in the function and not used anywhere else. 1000 private static final Rect sLocalGlobalVisibleRect = new Rect(); 1001 1002 private Rect getGlobalVisibleRect() { 1003 if (!mContainerView.getGlobalVisibleRect(sLocalGlobalVisibleRect)) { 1004 sLocalGlobalVisibleRect.setEmpty(); 1005 } 1006 return sLocalGlobalVisibleRect; 1007 } 1008 1009 //-------------------------------------------------------------------------------------------- 1010 // WebView[Provider] method implementations (where not provided by ContentViewCore) 1011 //-------------------------------------------------------------------------------------------- 1012 1013 public void onDraw(Canvas canvas) { 1014 mAwViewMethods.onDraw(canvas); 1015 } 1016 1017 public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 1018 mAwViewMethods.onMeasure(widthMeasureSpec, heightMeasureSpec); 1019 } 1020 1021 public int getContentHeightCss() { 1022 return (int) Math.ceil(mContentHeightDip); 1023 } 1024 1025 public int getContentWidthCss() { 1026 return (int) Math.ceil(mContentWidthDip); 1027 } 1028 1029 public Picture capturePicture() { 1030 if (isDestroyed()) return null; 1031 return new AwPicture(nativeCapturePicture(mNativeAwContents, 1032 mScrollOffsetManager.computeHorizontalScrollRange(), 1033 mScrollOffsetManager.computeVerticalScrollRange())); 1034 } 1035 1036 public void clearView() { 1037 if (!isDestroyed()) nativeClearView(mNativeAwContents); 1038 } 1039 1040 /** 1041 * Enable the onNewPicture callback. 1042 * @param enabled Flag to enable the callback. 1043 * @param invalidationOnly Flag to call back only on invalidation without providing a picture. 1044 */ 1045 public void enableOnNewPicture(boolean enabled, boolean invalidationOnly) { 1046 if (isDestroyed()) return; 1047 if (invalidationOnly) { 1048 mPictureListenerContentProvider = null; 1049 } else if (enabled && mPictureListenerContentProvider == null) { 1050 mPictureListenerContentProvider = new Callable<Picture>() { 1051 @Override 1052 public Picture call() { 1053 return capturePicture(); 1054 } 1055 }; 1056 } 1057 nativeEnableOnNewPicture(mNativeAwContents, enabled); 1058 } 1059 1060 public void findAllAsync(String searchString) { 1061 if (!isDestroyed()) nativeFindAllAsync(mNativeAwContents, searchString); 1062 } 1063 1064 public void findNext(boolean forward) { 1065 if (!isDestroyed()) nativeFindNext(mNativeAwContents, forward); 1066 } 1067 1068 public void clearMatches() { 1069 if (!isDestroyed()) nativeClearMatches(mNativeAwContents); 1070 } 1071 1072 /** 1073 * @return load progress of the WebContents. 1074 */ 1075 public int getMostRecentProgress() { 1076 // WebContentsDelegateAndroid conveniently caches the most recent notified value for us. 1077 return mWebContentsDelegate.getMostRecentProgress(); 1078 } 1079 1080 public Bitmap getFavicon() { 1081 return mFavicon; 1082 } 1083 1084 private void requestVisitedHistoryFromClient() { 1085 ValueCallback<String[]> callback = new ValueCallback<String[]>() { 1086 @Override 1087 public void onReceiveValue(final String[] value) { 1088 ThreadUtils.runOnUiThread(new Runnable() { 1089 @Override 1090 public void run() { 1091 if (!isDestroyed()) nativeAddVisitedLinks(mNativeAwContents, value); 1092 } 1093 }); 1094 } 1095 }; 1096 mContentsClient.getVisitedHistory(callback); 1097 } 1098 1099 /** 1100 * Load url without fixing up the url string. Consumers of ContentView are responsible for 1101 * ensuring the URL passed in is properly formatted (i.e. the scheme has been added if left 1102 * off during user input). 1103 * 1104 * @param params Parameters for this load. 1105 */ 1106 public void loadUrl(LoadUrlParams params) { 1107 if (isDestroyed()) return; 1108 1109 if (params.getLoadUrlType() == LoadUrlParams.LOAD_TYPE_DATA && 1110 !params.isBaseUrlDataScheme()) { 1111 // This allows data URLs with a non-data base URL access to file:///android_asset/ and 1112 // file:///android_res/ URLs. If AwSettings.getAllowFileAccess permits, it will also 1113 // allow access to file:// URLs (subject to OS level permission checks). 1114 params.setCanLoadLocalResources(true); 1115 } 1116 1117 // If we are reloading the same url, then set transition type as reload. 1118 if (params.getUrl() != null && 1119 params.getUrl().equals(mWebContents.getUrl()) && 1120 params.getTransitionType() == PageTransitionTypes.PAGE_TRANSITION_LINK) { 1121 params.setTransitionType(PageTransitionTypes.PAGE_TRANSITION_RELOAD); 1122 } 1123 params.setTransitionType( 1124 params.getTransitionType() | PageTransitionTypes.PAGE_TRANSITION_FROM_API); 1125 1126 // For WebView, always use the user agent override, which is set 1127 // every time the user agent in AwSettings is modified. 1128 params.setOverrideUserAgent(LoadUrlParams.UA_OVERRIDE_TRUE); 1129 1130 1131 // We don't pass extra headers to the content layer, as WebViewClassic 1132 // was adding them in a very narrow set of conditions. See http://crbug.com/306873 1133 // However, if the embedder is attempting to inject a Referer header for their 1134 // loadUrl call, then we set that separately and remove it from the extra headers map/ 1135 final String referer = "referer"; 1136 Map<String, String> extraHeaders = params.getExtraHeaders(); 1137 if (extraHeaders != null) { 1138 for (String header : extraHeaders.keySet()) { 1139 if (referer.equals(header.toLowerCase(Locale.US))) { 1140 params.setReferrer(new Referrer(extraHeaders.remove(header), 1)); 1141 params.setExtraHeaders(extraHeaders); 1142 break; 1143 } 1144 } 1145 } 1146 1147 nativeSetExtraHeadersForUrl( 1148 mNativeAwContents, params.getUrl(), params.getExtraHttpRequestHeadersString()); 1149 params.setExtraHeaders(new HashMap<String, String>()); 1150 1151 mNavigationController.loadUrl(params); 1152 1153 // The behavior of WebViewClassic uses the populateVisitedLinks callback in WebKit. 1154 // Chromium does not use this use code path and the best emulation of this behavior to call 1155 // request visited links once on the first URL load of the WebView. 1156 if (!mHasRequestedVisitedHistoryFromClient) { 1157 mHasRequestedVisitedHistoryFromClient = true; 1158 requestVisitedHistoryFromClient(); 1159 } 1160 1161 if (params.getLoadUrlType() == LoadUrlParams.LOAD_TYPE_DATA && 1162 params.getBaseUrl() != null) { 1163 // Data loads with a base url will be resolved in Blink, and not cause an onPageStarted 1164 // event to be sent. Sending the callback directly from here. 1165 mContentsClient.getCallbackHelper().postOnPageStarted(params.getBaseUrl()); 1166 } 1167 } 1168 1169 /** 1170 * Get the URL of the current page. 1171 * 1172 * @return The URL of the current page or null if it's empty. 1173 */ 1174 public String getUrl() { 1175 if (isDestroyed()) return null; 1176 String url = mWebContents.getUrl(); 1177 if (url == null || url.trim().isEmpty()) return null; 1178 return url; 1179 } 1180 1181 public void requestFocus() { 1182 mAwViewMethods.requestFocus(); 1183 } 1184 1185 public void setBackgroundColor(int color) { 1186 mBaseBackgroundColor = color; 1187 if (!isDestroyed()) nativeSetBackgroundColor(mNativeAwContents, color); 1188 } 1189 1190 /** 1191 * @see android.view.View#setLayerType() 1192 */ 1193 public void setLayerType(int layerType, Paint paint) { 1194 mAwViewMethods.setLayerType(layerType, paint); 1195 } 1196 1197 int getEffectiveBackgroundColor() { 1198 // Do not ask the ContentViewCore for the background color, as it will always 1199 // report white prior to initial navigation or post destruction, whereas we want 1200 // to use the client supplied base value in those cases. 1201 if (isDestroyed() || !mContentsClient.isCachedRendererBackgroundColorValid()) { 1202 return mBaseBackgroundColor; 1203 } 1204 return mContentsClient.getCachedRendererBackgroundColor(); 1205 } 1206 1207 public boolean isMultiTouchZoomSupported() { 1208 return mSettings.supportsMultiTouchZoom(); 1209 } 1210 1211 public View getZoomControlsForTest() { 1212 return mZoomControls.getZoomControlsViewForTest(); 1213 } 1214 1215 /** 1216 * @see ContentViewCore#getContentSettings() 1217 */ 1218 public ContentSettings getContentSettings() { 1219 return isDestroyed() ? null : mContentViewCore.getContentSettings(); 1220 } 1221 1222 /** 1223 * @see View#setOverScrollMode(int) 1224 */ 1225 public void setOverScrollMode(int mode) { 1226 if (mode != View.OVER_SCROLL_NEVER) { 1227 mOverScrollGlow = new OverScrollGlow(mContext, mContainerView); 1228 } else { 1229 mOverScrollGlow = null; 1230 } 1231 } 1232 1233 // TODO(mkosiba): In WebViewClassic these appear in some of the scroll extent calculation 1234 // methods but toggling them has no visiual effect on the content (in other words the scrolling 1235 // code behaves as if the scrollbar-related padding is in place but the onDraw code doesn't 1236 // take that into consideration). 1237 // http://crbug.com/269032 1238 private boolean mOverlayHorizontalScrollbar = true; 1239 private boolean mOverlayVerticalScrollbar = false; 1240 1241 /** 1242 * @see View#setScrollBarStyle(int) 1243 */ 1244 public void setScrollBarStyle(int style) { 1245 if (style == View.SCROLLBARS_INSIDE_OVERLAY 1246 || style == View.SCROLLBARS_OUTSIDE_OVERLAY) { 1247 mOverlayHorizontalScrollbar = mOverlayVerticalScrollbar = true; 1248 } else { 1249 mOverlayHorizontalScrollbar = mOverlayVerticalScrollbar = false; 1250 } 1251 } 1252 1253 /** 1254 * @see View#setHorizontalScrollbarOverlay(boolean) 1255 */ 1256 public void setHorizontalScrollbarOverlay(boolean overlay) { 1257 mOverlayHorizontalScrollbar = overlay; 1258 } 1259 1260 /** 1261 * @see View#setVerticalScrollbarOverlay(boolean) 1262 */ 1263 public void setVerticalScrollbarOverlay(boolean overlay) { 1264 mOverlayVerticalScrollbar = overlay; 1265 } 1266 1267 /** 1268 * @see View#overlayHorizontalScrollbar() 1269 */ 1270 public boolean overlayHorizontalScrollbar() { 1271 return mOverlayHorizontalScrollbar; 1272 } 1273 1274 /** 1275 * @see View#overlayVerticalScrollbar() 1276 */ 1277 public boolean overlayVerticalScrollbar() { 1278 return mOverlayVerticalScrollbar; 1279 } 1280 1281 /** 1282 * Called by the embedder when the scroll offset of the containing view has changed. 1283 * @see View#onScrollChanged(int,int) 1284 */ 1285 public void onContainerViewScrollChanged(int l, int t, int oldl, int oldt) { 1286 // A side-effect of View.onScrollChanged is that the scroll accessibility event being sent 1287 // by the base class implementation. This is completely hidden from the base classes and 1288 // cannot be prevented, which is why we need the code below. 1289 mScrollAccessibilityHelper.removePostedViewScrolledAccessibilityEventCallback(); 1290 mScrollOffsetManager.onContainerViewScrollChanged(l, t); 1291 } 1292 1293 /** 1294 * Called by the embedder when the containing view is to be scrolled or overscrolled. 1295 * @see View#onOverScrolled(int,int,int,int) 1296 */ 1297 public void onContainerViewOverScrolled(int scrollX, int scrollY, boolean clampedX, 1298 boolean clampedY) { 1299 int oldX = mContainerView.getScrollX(); 1300 int oldY = mContainerView.getScrollY(); 1301 1302 mScrollOffsetManager.onContainerViewOverScrolled(scrollX, scrollY, clampedX, clampedY); 1303 1304 if (mOverScrollGlow != null) { 1305 mOverScrollGlow.pullGlow(mContainerView.getScrollX(), mContainerView.getScrollY(), 1306 oldX, oldY, 1307 mScrollOffsetManager.computeMaximumHorizontalScrollOffset(), 1308 mScrollOffsetManager.computeMaximumVerticalScrollOffset()); 1309 } 1310 } 1311 1312 /** 1313 * @see android.webkit.WebView#requestChildRectangleOnScreen(View, Rect, boolean) 1314 */ 1315 public boolean requestChildRectangleOnScreen(View child, Rect rect, boolean immediate) { 1316 return mScrollOffsetManager.requestChildRectangleOnScreen( 1317 child.getLeft() - child.getScrollX(), child.getTop() - child.getScrollY(), 1318 rect, immediate); 1319 } 1320 1321 /** 1322 * @see View.computeScroll() 1323 */ 1324 public void computeScroll() { 1325 mScrollOffsetManager.computeScrollAndAbsorbGlow(mOverScrollGlow); 1326 } 1327 1328 /** 1329 * @see View#computeHorizontalScrollRange() 1330 */ 1331 public int computeHorizontalScrollRange() { 1332 return mScrollOffsetManager.computeHorizontalScrollRange(); 1333 } 1334 1335 /** 1336 * @see View#computeHorizontalScrollOffset() 1337 */ 1338 public int computeHorizontalScrollOffset() { 1339 return mScrollOffsetManager.computeHorizontalScrollOffset(); 1340 } 1341 1342 /** 1343 * @see View#computeVerticalScrollRange() 1344 */ 1345 public int computeVerticalScrollRange() { 1346 return mScrollOffsetManager.computeVerticalScrollRange(); 1347 } 1348 1349 /** 1350 * @see View#computeVerticalScrollOffset() 1351 */ 1352 public int computeVerticalScrollOffset() { 1353 return mScrollOffsetManager.computeVerticalScrollOffset(); 1354 } 1355 1356 /** 1357 * @see View#computeVerticalScrollExtent() 1358 */ 1359 public int computeVerticalScrollExtent() { 1360 return mScrollOffsetManager.computeVerticalScrollExtent(); 1361 } 1362 1363 /** 1364 * @see android.webkit.WebView#stopLoading() 1365 */ 1366 public void stopLoading() { 1367 if (!isDestroyed()) mWebContents.stop(); 1368 } 1369 1370 /** 1371 * @see android.webkit.WebView#reload() 1372 */ 1373 public void reload() { 1374 if (!isDestroyed()) mNavigationController.reload(true); 1375 } 1376 1377 /** 1378 * @see android.webkit.WebView#canGoBack() 1379 */ 1380 public boolean canGoBack() { 1381 return isDestroyed() ? false : mNavigationController.canGoBack(); 1382 } 1383 1384 /** 1385 * @see android.webkit.WebView#goBack() 1386 */ 1387 public void goBack() { 1388 if (!isDestroyed()) mNavigationController.goBack(); 1389 } 1390 1391 /** 1392 * @see android.webkit.WebView#canGoForward() 1393 */ 1394 public boolean canGoForward() { 1395 return isDestroyed() ? false : mNavigationController.canGoForward(); 1396 } 1397 1398 /** 1399 * @see android.webkit.WebView#goForward() 1400 */ 1401 public void goForward() { 1402 if (!isDestroyed()) mNavigationController.goForward(); 1403 } 1404 1405 /** 1406 * @see android.webkit.WebView#canGoBackOrForward(int) 1407 */ 1408 public boolean canGoBackOrForward(int steps) { 1409 return isDestroyed() ? false : mNavigationController.canGoToOffset(steps); 1410 } 1411 1412 /** 1413 * @see android.webkit.WebView#goBackOrForward(int) 1414 */ 1415 public void goBackOrForward(int steps) { 1416 if (!isDestroyed()) mNavigationController.goToOffset(steps); 1417 } 1418 1419 /** 1420 * @see android.webkit.WebView#pauseTimers() 1421 */ 1422 public void pauseTimers() { 1423 if (!isDestroyed()) ContentViewStatics.setWebKitSharedTimersSuspended(true); 1424 } 1425 1426 /** 1427 * @see android.webkit.WebView#resumeTimers() 1428 */ 1429 public void resumeTimers() { 1430 if (!isDestroyed()) ContentViewStatics.setWebKitSharedTimersSuspended(false); 1431 } 1432 1433 /** 1434 * @see android.webkit.WebView#onPause() 1435 */ 1436 public void onPause() { 1437 if (mIsPaused || isDestroyed()) return; 1438 mIsPaused = true; 1439 nativeSetIsPaused(mNativeAwContents, mIsPaused); 1440 mContentViewCore.onHide(); 1441 } 1442 1443 /** 1444 * @see android.webkit.WebView#onResume() 1445 */ 1446 public void onResume() { 1447 if (!mIsPaused || isDestroyed()) return; 1448 mIsPaused = false; 1449 nativeSetIsPaused(mNativeAwContents, mIsPaused); 1450 mContentViewCore.onShow(); 1451 } 1452 1453 /** 1454 * @see android.webkit.WebView#isPaused() 1455 */ 1456 public boolean isPaused() { 1457 return mIsPaused; 1458 } 1459 1460 /** 1461 * @see android.webkit.WebView#onCreateInputConnection(EditorInfo) 1462 */ 1463 public InputConnection onCreateInputConnection(EditorInfo outAttrs) { 1464 return mAwViewMethods.onCreateInputConnection(outAttrs); 1465 } 1466 1467 /** 1468 * @see android.webkit.WebView#onKeyUp(int, KeyEvent) 1469 */ 1470 public boolean onKeyUp(int keyCode, KeyEvent event) { 1471 return mAwViewMethods.onKeyUp(keyCode, event); 1472 } 1473 1474 /** 1475 * @see android.webkit.WebView#dispatchKeyEvent(KeyEvent) 1476 */ 1477 public boolean dispatchKeyEvent(KeyEvent event) { 1478 return mAwViewMethods.dispatchKeyEvent(event); 1479 } 1480 1481 /** 1482 * Clears the resource cache. Note that the cache is per-application, so this will clear the 1483 * cache for all WebViews used. 1484 * 1485 * @param includeDiskFiles if false, only the RAM cache is cleared 1486 */ 1487 public void clearCache(boolean includeDiskFiles) { 1488 if (!isDestroyed()) nativeClearCache(mNativeAwContents, includeDiskFiles); 1489 } 1490 1491 public void documentHasImages(Message message) { 1492 if (!isDestroyed()) nativeDocumentHasImages(mNativeAwContents, message); 1493 } 1494 1495 public void saveWebArchive( 1496 final String basename, boolean autoname, final ValueCallback<String> callback) { 1497 if (!autoname) { 1498 saveWebArchiveInternal(basename, callback); 1499 return; 1500 } 1501 // If auto-generating the file name, handle the name generation on a background thread 1502 // as it will require I/O access for checking whether previous files existed. 1503 new AsyncTask<Void, Void, String>() { 1504 @Override 1505 protected String doInBackground(Void... params) { 1506 return generateArchiveAutoNamePath(getOriginalUrl(), basename); 1507 } 1508 1509 @Override 1510 protected void onPostExecute(String result) { 1511 saveWebArchiveInternal(result, callback); 1512 } 1513 }.execute(); 1514 } 1515 1516 public String getOriginalUrl() { 1517 if (isDestroyed()) return null; 1518 NavigationHistory history = mNavigationController.getNavigationHistory(); 1519 int currentIndex = history.getCurrentEntryIndex(); 1520 if (currentIndex >= 0 && currentIndex < history.getEntryCount()) { 1521 return history.getEntryAtIndex(currentIndex).getOriginalUrl(); 1522 } 1523 return null; 1524 } 1525 1526 /** 1527 * @see ContentViewCore#getNavigationHistory() 1528 */ 1529 public NavigationHistory getNavigationHistory() { 1530 return isDestroyed() ? null : mNavigationController.getNavigationHistory(); 1531 } 1532 1533 /** 1534 * @see android.webkit.WebView#getTitle() 1535 */ 1536 public String getTitle() { 1537 return isDestroyed() ? null : mWebContents.getTitle(); 1538 } 1539 1540 /** 1541 * @see android.webkit.WebView#clearHistory() 1542 */ 1543 public void clearHistory() { 1544 if (!isDestroyed()) mNavigationController.clearHistory(); 1545 } 1546 1547 public String[] getHttpAuthUsernamePassword(String host, String realm) { 1548 return mBrowserContext.getHttpAuthDatabase(mContext) 1549 .getHttpAuthUsernamePassword(host, realm); 1550 } 1551 1552 public void setHttpAuthUsernamePassword(String host, String realm, String username, 1553 String password) { 1554 mBrowserContext.getHttpAuthDatabase(mContext) 1555 .setHttpAuthUsernamePassword(host, realm, username, password); 1556 } 1557 1558 /** 1559 * @see android.webkit.WebView#getCertificate() 1560 */ 1561 public SslCertificate getCertificate() { 1562 return isDestroyed() ? null 1563 : SslUtil.getCertificateFromDerBytes(nativeGetCertificate(mNativeAwContents)); 1564 } 1565 1566 /** 1567 * @see android.webkit.WebView#clearSslPreferences() 1568 */ 1569 public void clearSslPreferences() { 1570 if (!isDestroyed()) mNavigationController.clearSslPreferences(); 1571 } 1572 1573 // TODO(sgurun) remove after this rolls in. To keep internal tree happy. 1574 public void clearClientCertPreferences() { } 1575 1576 /** 1577 * Method to return all hit test values relevant to public WebView API. 1578 * Note that this expose more data than needed for WebView.getHitTestResult. 1579 * Unsafely returning reference to mutable internal object to avoid excessive 1580 * garbage allocation on repeated calls. 1581 */ 1582 public HitTestData getLastHitTestResult() { 1583 if (isDestroyed()) return null; 1584 nativeUpdateLastHitTestData(mNativeAwContents); 1585 return mPossiblyStaleHitTestData; 1586 } 1587 1588 /** 1589 * @see android.webkit.WebView#requestFocusNodeHref() 1590 */ 1591 public void requestFocusNodeHref(Message msg) { 1592 if (msg == null || isDestroyed()) return; 1593 1594 nativeUpdateLastHitTestData(mNativeAwContents); 1595 Bundle data = msg.getData(); 1596 1597 // In order to maintain compatibility with the old WebView's implementation, 1598 // the absolute (full) url is passed in the |url| field, not only the href attribute. 1599 // Note: HitTestData could be cleaned up at this point. See http://crbug.com/290992. 1600 data.putString("url", mPossiblyStaleHitTestData.href); 1601 data.putString("title", mPossiblyStaleHitTestData.anchorText); 1602 data.putString("src", mPossiblyStaleHitTestData.imgSrc); 1603 msg.setData(data); 1604 msg.sendToTarget(); 1605 } 1606 1607 /** 1608 * @see android.webkit.WebView#requestImageRef() 1609 */ 1610 public void requestImageRef(Message msg) { 1611 if (msg == null || isDestroyed()) return; 1612 1613 nativeUpdateLastHitTestData(mNativeAwContents); 1614 Bundle data = msg.getData(); 1615 data.putString("url", mPossiblyStaleHitTestData.imgSrc); 1616 msg.setData(data); 1617 msg.sendToTarget(); 1618 } 1619 1620 @VisibleForTesting 1621 public float getPageScaleFactor() { 1622 return mPageScaleFactor; 1623 } 1624 1625 /** 1626 * @see android.webkit.WebView#getScale() 1627 * 1628 * Please note that the scale returned is the page scale multiplied by 1629 * the screen density factor. See CTS WebViewTest.testSetInitialScale. 1630 */ 1631 public float getScale() { 1632 return (float) (mPageScaleFactor * mDIPScale); 1633 } 1634 1635 /** 1636 * @see android.webkit.WebView#flingScroll(int, int) 1637 */ 1638 public void flingScroll(int velocityX, int velocityY) { 1639 mScrollOffsetManager.flingScroll(velocityX, velocityY); 1640 } 1641 1642 /** 1643 * @see android.webkit.WebView#pageUp(boolean) 1644 */ 1645 public boolean pageUp(boolean top) { 1646 return mScrollOffsetManager.pageUp(top); 1647 } 1648 1649 /** 1650 * @see android.webkit.WebView#pageDown(boolean) 1651 */ 1652 public boolean pageDown(boolean bottom) { 1653 return mScrollOffsetManager.pageDown(bottom); 1654 } 1655 1656 /** 1657 * @see android.webkit.WebView#canZoomIn() 1658 */ 1659 // This method uses the term 'zoom' for legacy reasons, but relates 1660 // to what chrome calls the 'page scale factor'. 1661 public boolean canZoomIn() { 1662 final float zoomInExtent = mMaxPageScaleFactor - mPageScaleFactor; 1663 return zoomInExtent > ZOOM_CONTROLS_EPSILON; 1664 } 1665 1666 /** 1667 * @see android.webkit.WebView#canZoomOut() 1668 */ 1669 // This method uses the term 'zoom' for legacy reasons, but relates 1670 // to what chrome calls the 'page scale factor'. 1671 public boolean canZoomOut() { 1672 final float zoomOutExtent = mPageScaleFactor - mMinPageScaleFactor; 1673 return zoomOutExtent > ZOOM_CONTROLS_EPSILON; 1674 } 1675 1676 /** 1677 * @see android.webkit.WebView#zoomIn() 1678 */ 1679 // This method uses the term 'zoom' for legacy reasons, but relates 1680 // to what chrome calls the 'page scale factor'. 1681 public boolean zoomIn() { 1682 if (!canZoomIn()) { 1683 return false; 1684 } 1685 return zoomBy(1.25f); 1686 } 1687 1688 /** 1689 * @see android.webkit.WebView#zoomOut() 1690 */ 1691 // This method uses the term 'zoom' for legacy reasons, but relates 1692 // to what chrome calls the 'page scale factor'. 1693 public boolean zoomOut() { 1694 if (!canZoomOut()) { 1695 return false; 1696 } 1697 return zoomBy(0.8f); 1698 } 1699 1700 /** 1701 * @see android.webkit.WebView#zoomBy() 1702 */ 1703 // This method uses the term 'zoom' for legacy reasons, but relates 1704 // to what chrome calls the 'page scale factor'. 1705 public boolean zoomBy(float delta) { 1706 if (isDestroyed()) return false; 1707 if (delta < 0.01f || delta > 100.0f) { 1708 throw new IllegalStateException("zoom delta value outside [0.01, 100] range."); 1709 } 1710 return mContentViewCore.pinchByDelta(delta); 1711 } 1712 1713 /** 1714 * @see android.webkit.WebView#invokeZoomPicker() 1715 */ 1716 public void invokeZoomPicker() { 1717 if (!isDestroyed()) mContentViewCore.invokeZoomPicker(); 1718 } 1719 1720 /** 1721 * @see android.webkit.WebView#preauthorizePermission(Uri, long) 1722 */ 1723 public void preauthorizePermission(Uri origin, long resources) { 1724 if (isDestroyed()) return; 1725 nativePreauthorizePermission(mNativeAwContents, origin.toString(), resources); 1726 } 1727 1728 /** 1729 * @see ContentViewCore.evaluateJavaScript(String, JavaScriptCallback) 1730 */ 1731 public void evaluateJavaScript(String script, final ValueCallback<String> callback) { 1732 if (isDestroyed()) return; 1733 JavaScriptCallback jsCallback = null; 1734 if (callback != null) { 1735 jsCallback = new JavaScriptCallback() { 1736 @Override 1737 public void handleJavaScriptResult(String jsonResult) { 1738 callback.onReceiveValue(jsonResult); 1739 } 1740 }; 1741 } 1742 1743 mWebContents.evaluateJavaScript(script, jsCallback); 1744 } 1745 1746 // TODO(boliu): Remove this once Android side no longer calls this. 1747 public void evaluateJavaScriptEvenIfNotYetNavigated(String script) { 1748 if (!isDestroyed()) mWebContents.evaluateJavaScript(script, null); 1749 } 1750 1751 //-------------------------------------------------------------------------------------------- 1752 // View and ViewGroup method implementations 1753 //-------------------------------------------------------------------------------------------- 1754 1755 /** 1756 * @see android.webkit.View#onTouchEvent() 1757 */ 1758 public boolean onTouchEvent(MotionEvent event) { 1759 return mAwViewMethods.onTouchEvent(event); 1760 } 1761 1762 /** 1763 * @see android.view.View#onHoverEvent() 1764 */ 1765 public boolean onHoverEvent(MotionEvent event) { 1766 return mAwViewMethods.onHoverEvent(event); 1767 } 1768 1769 /** 1770 * @see android.view.View#onGenericMotionEvent() 1771 */ 1772 public boolean onGenericMotionEvent(MotionEvent event) { 1773 return isDestroyed() ? false : mContentViewCore.onGenericMotionEvent(event); 1774 } 1775 1776 /** 1777 * @see android.view.View#onConfigurationChanged() 1778 */ 1779 public void onConfigurationChanged(Configuration newConfig) { 1780 mAwViewMethods.onConfigurationChanged(newConfig); 1781 } 1782 1783 /** 1784 * @see android.view.View#onAttachedToWindow() 1785 */ 1786 public void onAttachedToWindow() { 1787 mTemporarilyDetached = false; 1788 mAwViewMethods.onAttachedToWindow(); 1789 } 1790 1791 /** 1792 * @see android.view.View#onDetachedFromWindow() 1793 */ 1794 @SuppressLint("MissingSuperCall") 1795 public void onDetachedFromWindow() { 1796 mAwViewMethods.onDetachedFromWindow(); 1797 } 1798 1799 /** 1800 * @see android.view.View#onWindowFocusChanged() 1801 */ 1802 public void onWindowFocusChanged(boolean hasWindowFocus) { 1803 mAwViewMethods.onWindowFocusChanged(hasWindowFocus); 1804 } 1805 1806 /** 1807 * @see android.view.View#onFocusChanged() 1808 */ 1809 public void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) { 1810 if (!mTemporarilyDetached) { 1811 mAwViewMethods.onFocusChanged(focused, direction, previouslyFocusedRect); 1812 } 1813 } 1814 1815 /** 1816 * @see android.view.View#onStartTemporaryDetach() 1817 */ 1818 public void onStartTemporaryDetach() { 1819 mTemporarilyDetached = true; 1820 } 1821 1822 /** 1823 * @see android.view.View#onFinishTemporaryDetach() 1824 */ 1825 public void onFinishTemporaryDetach() { 1826 mTemporarilyDetached = false; 1827 } 1828 1829 /** 1830 * @see android.view.View#onSizeChanged() 1831 */ 1832 public void onSizeChanged(int w, int h, int ow, int oh) { 1833 mAwViewMethods.onSizeChanged(w, h, ow, oh); 1834 } 1835 1836 /** 1837 * @see android.view.View#onVisibilityChanged() 1838 */ 1839 public void onVisibilityChanged(View changedView, int visibility) { 1840 mAwViewMethods.onVisibilityChanged(changedView, visibility); 1841 } 1842 1843 /** 1844 * @see android.view.View#onWindowVisibilityChanged() 1845 */ 1846 public void onWindowVisibilityChanged(int visibility) { 1847 mAwViewMethods.onWindowVisibilityChanged(visibility); 1848 } 1849 1850 private void setViewVisibilityInternal(boolean visible) { 1851 mIsViewVisible = visible; 1852 if (!isDestroyed()) nativeSetViewVisibility(mNativeAwContents, mIsViewVisible); 1853 } 1854 1855 private void setWindowVisibilityInternal(boolean visible) { 1856 mIsWindowVisible = visible; 1857 if (!isDestroyed()) nativeSetWindowVisibility(mNativeAwContents, mIsWindowVisible); 1858 } 1859 1860 /** 1861 * Key for opaque state in bundle. Note this is only public for tests. 1862 */ 1863 public static final String SAVE_RESTORE_STATE_KEY = "WEBVIEW_CHROMIUM_STATE"; 1864 1865 /** 1866 * Save the state of this AwContents into provided Bundle. 1867 * @return False if saving state failed. 1868 */ 1869 public boolean saveState(Bundle outState) { 1870 if (isDestroyed() || outState == null) return false; 1871 1872 byte[] state = nativeGetOpaqueState(mNativeAwContents); 1873 if (state == null) return false; 1874 1875 outState.putByteArray(SAVE_RESTORE_STATE_KEY, state); 1876 return true; 1877 } 1878 1879 /** 1880 * Restore the state of this AwContents into provided Bundle. 1881 * @param inState Must be a bundle returned by saveState. 1882 * @return False if restoring state failed. 1883 */ 1884 public boolean restoreState(Bundle inState) { 1885 if (isDestroyed() || inState == null) return false; 1886 1887 byte[] state = inState.getByteArray(SAVE_RESTORE_STATE_KEY); 1888 if (state == null) return false; 1889 1890 boolean result = nativeRestoreFromOpaqueState(mNativeAwContents, state); 1891 1892 // The onUpdateTitle callback normally happens when a page is loaded, 1893 // but is optimized out in the restoreState case because the title is 1894 // already restored. See WebContentsImpl::UpdateTitleForEntry. So we 1895 // call the callback explicitly here. 1896 if (result) mContentsClient.onReceivedTitle(mWebContents.getTitle()); 1897 1898 return result; 1899 } 1900 1901 /** 1902 * @see ContentViewCore#addPossiblyUnsafeJavascriptInterface(Object, String, Class) 1903 */ 1904 public void addPossiblyUnsafeJavascriptInterface(Object object, String name, 1905 Class<? extends Annotation> requiredAnnotation) { 1906 if (isDestroyed()) return; 1907 mContentViewCore.addPossiblyUnsafeJavascriptInterface(object, name, requiredAnnotation); 1908 } 1909 1910 /** 1911 * @see android.webkit.WebView#removeJavascriptInterface(String) 1912 */ 1913 public void removeJavascriptInterface(String interfaceName) { 1914 if (!isDestroyed()) mContentViewCore.removeJavascriptInterface(interfaceName); 1915 } 1916 1917 /** 1918 * If native accessibility (not script injection) is enabled, and if this is 1919 * running on JellyBean or later, returns an AccessibilityNodeProvider that 1920 * implements native accessibility for this view. Returns null otherwise. 1921 * @return The AccessibilityNodeProvider, if available, or null otherwise. 1922 */ 1923 public AccessibilityNodeProvider getAccessibilityNodeProvider() { 1924 return isDestroyed() ? null : mContentViewCore.getAccessibilityNodeProvider(); 1925 } 1926 1927 /** 1928 * @see android.webkit.WebView#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 1929 */ 1930 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 1931 if (!isDestroyed()) mContentViewCore.onInitializeAccessibilityNodeInfo(info); 1932 } 1933 1934 /** 1935 * @see android.webkit.WebView#onInitializeAccessibilityEvent(AccessibilityEvent) 1936 */ 1937 public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 1938 if (!isDestroyed()) mContentViewCore.onInitializeAccessibilityEvent(event); 1939 } 1940 1941 public boolean supportsAccessibilityAction(int action) { 1942 return isDestroyed() ? false : mContentViewCore.supportsAccessibilityAction(action); 1943 } 1944 1945 /** 1946 * @see android.webkit.WebView#performAccessibilityAction(int, Bundle) 1947 */ 1948 public boolean performAccessibilityAction(int action, Bundle arguments) { 1949 return isDestroyed() ? false 1950 : mContentViewCore.performAccessibilityAction(action, arguments); 1951 } 1952 1953 /** 1954 * @see android.webkit.WebView#clearFormData() 1955 */ 1956 public void hideAutofillPopup() { 1957 if (mAwAutofillClient != null) { 1958 mAwAutofillClient.hideAutofillPopup(); 1959 } 1960 } 1961 1962 public void setNetworkAvailable(boolean networkUp) { 1963 if (!isDestroyed()) nativeSetJsOnlineProperty(mNativeAwContents, networkUp); 1964 } 1965 1966 //-------------------------------------------------------------------------------------------- 1967 // Methods called from native via JNI 1968 //-------------------------------------------------------------------------------------------- 1969 1970 @CalledByNative 1971 private static void onDocumentHasImagesResponse(boolean result, Message message) { 1972 message.arg1 = result ? 1 : 0; 1973 message.sendToTarget(); 1974 } 1975 1976 @CalledByNative 1977 private void onReceivedTouchIconUrl(String url, boolean precomposed) { 1978 mContentsClient.onReceivedTouchIconUrl(url, precomposed); 1979 } 1980 1981 @CalledByNative 1982 private void onReceivedIcon(Bitmap bitmap) { 1983 mContentsClient.onReceivedIcon(bitmap); 1984 mFavicon = bitmap; 1985 } 1986 1987 /** Callback for generateMHTML. */ 1988 @CalledByNative 1989 private static void generateMHTMLCallback( 1990 String path, long size, ValueCallback<String> callback) { 1991 if (callback == null) return; 1992 callback.onReceiveValue(size < 0 ? null : path); 1993 } 1994 1995 @CalledByNative 1996 private void onReceivedHttpAuthRequest(AwHttpAuthHandler handler, String host, String realm) { 1997 mContentsClient.onReceivedHttpAuthRequest(handler, host, realm); 1998 } 1999 2000 private class AwGeolocationCallback implements GeolocationPermissions.Callback { 2001 2002 @Override 2003 public void invoke(final String origin, final boolean allow, final boolean retain) { 2004 ThreadUtils.runOnUiThread(new Runnable() { 2005 @Override 2006 public void run() { 2007 if (retain) { 2008 if (allow) { 2009 mBrowserContext.getGeolocationPermissions().allow(origin); 2010 } else { 2011 mBrowserContext.getGeolocationPermissions().deny(origin); 2012 } 2013 } 2014 if (isDestroyed()) return; 2015 nativeInvokeGeolocationCallback(mNativeAwContents, allow, origin); 2016 } 2017 }); 2018 } 2019 } 2020 2021 @CalledByNative 2022 private void onGeolocationPermissionsShowPrompt(String origin) { 2023 if (isDestroyed()) return; 2024 AwGeolocationPermissions permissions = mBrowserContext.getGeolocationPermissions(); 2025 // Reject if geoloaction is disabled, or the origin has a retained deny 2026 if (!mSettings.getGeolocationEnabled()) { 2027 nativeInvokeGeolocationCallback(mNativeAwContents, false, origin); 2028 return; 2029 } 2030 // Allow if the origin has a retained allow 2031 if (permissions.hasOrigin(origin)) { 2032 nativeInvokeGeolocationCallback(mNativeAwContents, permissions.isOriginAllowed(origin), 2033 origin); 2034 return; 2035 } 2036 mContentsClient.onGeolocationPermissionsShowPrompt( 2037 origin, new AwGeolocationCallback()); 2038 } 2039 2040 @CalledByNative 2041 private void onGeolocationPermissionsHidePrompt() { 2042 mContentsClient.onGeolocationPermissionsHidePrompt(); 2043 } 2044 2045 @CalledByNative 2046 private void onPermissionRequest(AwPermissionRequest awPermissionRequest) { 2047 mContentsClient.onPermissionRequest(awPermissionRequest); 2048 } 2049 2050 @CalledByNative 2051 private void onPermissionRequestCanceled(AwPermissionRequest awPermissionRequest) { 2052 mContentsClient.onPermissionRequestCanceled(awPermissionRequest); 2053 } 2054 2055 @CalledByNative 2056 public void onFindResultReceived(int activeMatchOrdinal, int numberOfMatches, 2057 boolean isDoneCounting) { 2058 mContentsClient.onFindResultReceived(activeMatchOrdinal, numberOfMatches, isDoneCounting); 2059 } 2060 2061 @CalledByNative 2062 public void onNewPicture() { 2063 // Don't call capturePicture() here but instead defer it until the posted task runs within 2064 // the callback helper, to avoid doubling back into the renderer compositor in the middle 2065 // of the notification it is sending up to here. 2066 mContentsClient.getCallbackHelper().postOnNewPicture(mPictureListenerContentProvider); 2067 } 2068 2069 // Called as a result of nativeUpdateLastHitTestData. 2070 @CalledByNative 2071 private void updateHitTestData( 2072 int type, String extra, String href, String anchorText, String imgSrc) { 2073 mPossiblyStaleHitTestData.hitTestResultType = type; 2074 mPossiblyStaleHitTestData.hitTestResultExtraData = extra; 2075 mPossiblyStaleHitTestData.href = href; 2076 mPossiblyStaleHitTestData.anchorText = anchorText; 2077 mPossiblyStaleHitTestData.imgSrc = imgSrc; 2078 } 2079 2080 @CalledByNative 2081 private boolean requestDrawGL(Canvas canvas, boolean waitForCompletion) { 2082 return mNativeGLDelegate.requestDrawGL(canvas, waitForCompletion, mContainerView); 2083 } 2084 2085 private static final boolean SUPPORTS_ON_ANIMATION = 2086 Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN; 2087 2088 @CalledByNative 2089 private void postInvalidateOnAnimation() { 2090 if (SUPPORTS_ON_ANIMATION && !mWindowAndroid.isInsideVSync()) { 2091 mContainerView.postInvalidateOnAnimation(); 2092 } else { 2093 mContainerView.invalidate(); 2094 } 2095 } 2096 2097 // Call postInvalidateOnAnimation for invalidations. This is only used to synchronize 2098 // draw functor destruction. 2099 @CalledByNative 2100 private void invalidateOnFunctorDestroy() { 2101 mContainerView.invalidate(); 2102 } 2103 2104 @CalledByNative 2105 private int[] getLocationOnScreen() { 2106 int[] result = new int[2]; 2107 mContainerView.getLocationOnScreen(result); 2108 return result; 2109 } 2110 2111 @CalledByNative 2112 private void onWebLayoutPageScaleFactorChanged(float webLayoutPageScaleFactor) { 2113 // This change notification comes from the renderer thread, not from the cc/ impl thread. 2114 mLayoutSizer.onPageScaleChanged(webLayoutPageScaleFactor); 2115 } 2116 2117 @CalledByNative 2118 private void onWebLayoutContentsSizeChanged(int widthCss, int heightCss) { 2119 // This change notification comes from the renderer thread, not from the cc/ impl thread. 2120 mLayoutSizer.onContentSizeChanged(widthCss, heightCss); 2121 } 2122 2123 @CalledByNative 2124 private void scrollContainerViewTo(int x, int y) { 2125 mScrollOffsetManager.scrollContainerViewTo(x, y); 2126 } 2127 2128 @CalledByNative 2129 private boolean isFlingActive() { 2130 return mScrollOffsetManager.isFlingActive(); 2131 } 2132 2133 @CalledByNative 2134 private void updateScrollState(int maxContainerViewScrollOffsetX, 2135 int maxContainerViewScrollOffsetY, int contentWidthDip, int contentHeightDip, 2136 float pageScaleFactor, float minPageScaleFactor, float maxPageScaleFactor) { 2137 mContentWidthDip = contentWidthDip; 2138 mContentHeightDip = contentHeightDip; 2139 mScrollOffsetManager.setMaxScrollOffset(maxContainerViewScrollOffsetX, 2140 maxContainerViewScrollOffsetY); 2141 setPageScaleFactorAndLimits(pageScaleFactor, minPageScaleFactor, maxPageScaleFactor); 2142 } 2143 2144 @CalledByNative 2145 private void setAwAutofillClient(AwAutofillClient client) { 2146 mAwAutofillClient = client; 2147 client.init(mContentViewCore); 2148 } 2149 2150 @CalledByNative 2151 private void didOverscroll(int deltaX, int deltaY) { 2152 if (mOverScrollGlow != null) { 2153 mOverScrollGlow.setOverScrollDeltas(deltaX, deltaY); 2154 } 2155 2156 mScrollOffsetManager.overScrollBy(deltaX, deltaY); 2157 2158 if (mOverScrollGlow != null && mOverScrollGlow.isAnimating()) { 2159 mContainerView.invalidate(); 2160 } 2161 } 2162 2163 // ------------------------------------------------------------------------------------------- 2164 // Helper methods 2165 // ------------------------------------------------------------------------------------------- 2166 2167 private void setPageScaleFactorAndLimits( 2168 float pageScaleFactor, float minPageScaleFactor, float maxPageScaleFactor) { 2169 if (mPageScaleFactor == pageScaleFactor && 2170 mMinPageScaleFactor == minPageScaleFactor && 2171 mMaxPageScaleFactor == maxPageScaleFactor) { 2172 return; 2173 } 2174 mMinPageScaleFactor = minPageScaleFactor; 2175 mMaxPageScaleFactor = maxPageScaleFactor; 2176 if (mPageScaleFactor != pageScaleFactor) { 2177 float oldPageScaleFactor = mPageScaleFactor; 2178 mPageScaleFactor = pageScaleFactor; 2179 mContentsClient.getCallbackHelper().postOnScaleChangedScaled( 2180 (float) (oldPageScaleFactor * mDIPScale), 2181 (float) (mPageScaleFactor * mDIPScale)); 2182 } 2183 } 2184 2185 private void saveWebArchiveInternal(String path, final ValueCallback<String> callback) { 2186 if (path == null || isDestroyed()) { 2187 ThreadUtils.runOnUiThread(new Runnable() { 2188 @Override 2189 public void run() { 2190 callback.onReceiveValue(null); 2191 } 2192 }); 2193 } else { 2194 nativeGenerateMHTML(mNativeAwContents, path, callback); 2195 } 2196 } 2197 2198 /** 2199 * Try to generate a pathname for saving an MHTML archive. This roughly follows WebView's 2200 * autoname logic. 2201 */ 2202 private static String generateArchiveAutoNamePath(String originalUrl, String baseName) { 2203 String name = null; 2204 if (originalUrl != null && !originalUrl.isEmpty()) { 2205 try { 2206 String path = new URL(originalUrl).getPath(); 2207 int lastSlash = path.lastIndexOf('/'); 2208 if (lastSlash > 0) { 2209 name = path.substring(lastSlash + 1); 2210 } else { 2211 name = path; 2212 } 2213 } catch (MalformedURLException e) { 2214 // If it fails parsing the URL, we'll just rely on the default name below. 2215 } 2216 } 2217 2218 if (TextUtils.isEmpty(name)) name = "index"; 2219 2220 String testName = baseName + name + WEB_ARCHIVE_EXTENSION; 2221 if (!new File(testName).exists()) return testName; 2222 2223 for (int i = 1; i < 100; i++) { 2224 testName = baseName + name + "-" + i + WEB_ARCHIVE_EXTENSION; 2225 if (!new File(testName).exists()) return testName; 2226 } 2227 2228 Log.e(TAG, "Unable to auto generate archive name for path: " + baseName); 2229 return null; 2230 } 2231 2232 @Override 2233 public void extractSmartClipData(int x, int y, int width, int height) { 2234 if (!isDestroyed()) mContentViewCore.extractSmartClipData(x, y, width, height); 2235 } 2236 2237 @Override 2238 public void setSmartClipResultHandler(final Handler resultHandler) { 2239 if (resultHandler == null) { 2240 mContentViewCore.setSmartClipDataListener(null); 2241 return; 2242 } 2243 mContentViewCore.setSmartClipDataListener(new ContentViewCore.SmartClipDataListener() { 2244 public void onSmartClipDataExtracted(String text, String html, Rect clipRect) { 2245 Bundle bundle = new Bundle(); 2246 bundle.putString("url", mContentViewCore.getWebContents().getVisibleUrl()); 2247 bundle.putString("title", mContentViewCore.getWebContents().getTitle()); 2248 bundle.putParcelable("rect", clipRect); 2249 bundle.putString("text", text); 2250 bundle.putString("html", html); 2251 try { 2252 Message msg = Message.obtain(resultHandler, 0); 2253 msg.setData(bundle); 2254 msg.sendToTarget(); 2255 } catch (Exception e) { 2256 Log.e(TAG, "Error calling handler for smart clip data: ", e); 2257 } 2258 } 2259 }); 2260 } 2261 2262 // -------------------------------------------------------------------------------------------- 2263 // This is the AwViewMethods implementation that does real work. The AwViewMethodsImpl is 2264 // hooked up to the WebView in embedded mode and to the FullScreenView in fullscreen mode, 2265 // but not to both at the same time. 2266 private class AwViewMethodsImpl implements AwViewMethods { 2267 private int mLayerType = View.LAYER_TYPE_NONE; 2268 private ComponentCallbacks2 mComponentCallbacks; 2269 2270 // Only valid within software onDraw(). 2271 private final Rect mClipBoundsTemporary = new Rect(); 2272 2273 @Override 2274 public void onDraw(Canvas canvas) { 2275 if (isDestroyed()) { 2276 canvas.drawColor(getEffectiveBackgroundColor()); 2277 return; 2278 } 2279 2280 // For hardware draws, the clip at onDraw time could be different 2281 // from the clip during DrawGL. 2282 if (!canvas.isHardwareAccelerated() && !canvas.getClipBounds(mClipBoundsTemporary)) { 2283 return; 2284 } 2285 2286 mScrollOffsetManager.syncScrollOffsetFromOnDraw(); 2287 Rect globalVisibleRect = getGlobalVisibleRect(); 2288 if (!nativeOnDraw(mNativeAwContents, canvas, canvas.isHardwareAccelerated(), 2289 mContainerView.getScrollX(), mContainerView.getScrollY(), 2290 globalVisibleRect.left, globalVisibleRect.top, 2291 globalVisibleRect.right, globalVisibleRect.bottom)) { 2292 // Can happen during initialization when compositor is not set 2293 // up. Or when clearView 2294 // is in effect. Just draw background color instead. 2295 canvas.drawColor(getEffectiveBackgroundColor()); 2296 } 2297 2298 if (mOverScrollGlow != null && mOverScrollGlow.drawEdgeGlows(canvas, 2299 mScrollOffsetManager.computeMaximumHorizontalScrollOffset(), 2300 mScrollOffsetManager.computeMaximumVerticalScrollOffset())) { 2301 mContainerView.invalidate(); 2302 } 2303 } 2304 2305 @Override 2306 public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 2307 mLayoutSizer.onMeasure(widthMeasureSpec, heightMeasureSpec); 2308 } 2309 2310 @Override 2311 public void requestFocus() { 2312 if (isDestroyed()) return; 2313 if (!mContainerView.isInTouchMode() && mSettings.shouldFocusFirstNode()) { 2314 nativeFocusFirstNode(mNativeAwContents); 2315 } 2316 } 2317 2318 @Override 2319 public void setLayerType(int layerType, Paint paint) { 2320 mLayerType = layerType; 2321 updateHardwareAcceleratedFeaturesToggle(); 2322 } 2323 2324 private void updateHardwareAcceleratedFeaturesToggle() { 2325 mSettings.setEnableSupportedHardwareAcceleratedFeatures( 2326 mIsAttachedToWindow && mContainerView.isHardwareAccelerated() && 2327 (mLayerType == View.LAYER_TYPE_NONE 2328 || mLayerType == View.LAYER_TYPE_HARDWARE)); 2329 } 2330 2331 @Override 2332 public InputConnection onCreateInputConnection(EditorInfo outAttrs) { 2333 return isDestroyed() ? null : mContentViewCore.onCreateInputConnection(outAttrs); 2334 } 2335 2336 @Override 2337 public boolean onKeyUp(int keyCode, KeyEvent event) { 2338 return isDestroyed() ? false : mContentViewCore.onKeyUp(keyCode, event); 2339 } 2340 2341 @Override 2342 public boolean dispatchKeyEvent(KeyEvent event) { 2343 if (isDestroyed()) return false; 2344 if (isDpadEvent(event)) { 2345 mSettings.setSpatialNavigationEnabled(true); 2346 } 2347 return mContentViewCore.dispatchKeyEvent(event); 2348 } 2349 2350 private boolean isDpadEvent(KeyEvent event) { 2351 if (event.getAction() == KeyEvent.ACTION_DOWN) { 2352 switch (event.getKeyCode()) { 2353 case KeyEvent.KEYCODE_DPAD_CENTER: 2354 case KeyEvent.KEYCODE_DPAD_DOWN: 2355 case KeyEvent.KEYCODE_DPAD_UP: 2356 case KeyEvent.KEYCODE_DPAD_LEFT: 2357 case KeyEvent.KEYCODE_DPAD_RIGHT: 2358 return true; 2359 } 2360 } 2361 return false; 2362 } 2363 2364 @Override 2365 public boolean onTouchEvent(MotionEvent event) { 2366 if (isDestroyed()) return false; 2367 if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { 2368 mSettings.setSpatialNavigationEnabled(false); 2369 } 2370 2371 mScrollOffsetManager.setProcessingTouchEvent(true); 2372 boolean rv = mContentViewCore.onTouchEvent(event); 2373 mScrollOffsetManager.setProcessingTouchEvent(false); 2374 2375 if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { 2376 int actionIndex = event.getActionIndex(); 2377 2378 // Note this will trigger IPC back to browser even if nothing is 2379 // hit. 2380 nativeRequestNewHitTestDataAt(mNativeAwContents, 2381 (int) Math.round(event.getX(actionIndex) / mDIPScale), 2382 (int) Math.round(event.getY(actionIndex) / mDIPScale)); 2383 } 2384 2385 if (mOverScrollGlow != null) { 2386 if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { 2387 mOverScrollGlow.setShouldPull(true); 2388 } else if (event.getActionMasked() == MotionEvent.ACTION_UP || 2389 event.getActionMasked() == MotionEvent.ACTION_CANCEL) { 2390 mOverScrollGlow.setShouldPull(false); 2391 mOverScrollGlow.releaseAll(); 2392 } 2393 } 2394 2395 return rv; 2396 } 2397 2398 @Override 2399 public boolean onHoverEvent(MotionEvent event) { 2400 return isDestroyed() ? false : mContentViewCore.onHoverEvent(event); 2401 } 2402 2403 @Override 2404 public boolean onGenericMotionEvent(MotionEvent event) { 2405 return isDestroyed() ? false : mContentViewCore.onGenericMotionEvent(event); 2406 } 2407 2408 @Override 2409 public void onConfigurationChanged(Configuration newConfig) { 2410 if (!isDestroyed()) mContentViewCore.onConfigurationChanged(newConfig); 2411 } 2412 2413 @Override 2414 public void onAttachedToWindow() { 2415 if (isDestroyed()) return; 2416 if (mIsAttachedToWindow) { 2417 Log.w(TAG, "onAttachedToWindow called when already attached. Ignoring"); 2418 return; 2419 } 2420 mIsAttachedToWindow = true; 2421 2422 mContentViewCore.onAttachedToWindow(); 2423 nativeOnAttachedToWindow(mNativeAwContents, mContainerView.getWidth(), 2424 mContainerView.getHeight()); 2425 updateHardwareAcceleratedFeaturesToggle(); 2426 2427 if (mComponentCallbacks != null) return; 2428 mComponentCallbacks = new AwComponentCallbacks(); 2429 mContext.registerComponentCallbacks(mComponentCallbacks); 2430 } 2431 2432 @Override 2433 public void onDetachedFromWindow() { 2434 if (isDestroyed()) return; 2435 if (!mIsAttachedToWindow) { 2436 Log.w(TAG, "onDetachedFromWindow called when already detached. Ignoring"); 2437 return; 2438 } 2439 mIsAttachedToWindow = false; 2440 hideAutofillPopup(); 2441 nativeOnDetachedFromWindow(mNativeAwContents); 2442 2443 mContentViewCore.onDetachedFromWindow(); 2444 updateHardwareAcceleratedFeaturesToggle(); 2445 2446 if (mComponentCallbacks != null) { 2447 mContext.unregisterComponentCallbacks(mComponentCallbacks); 2448 mComponentCallbacks = null; 2449 } 2450 2451 mScrollAccessibilityHelper.removePostedCallbacks(); 2452 mNativeGLDelegate.detachGLFunctor(); 2453 } 2454 2455 @Override 2456 public void onWindowFocusChanged(boolean hasWindowFocus) { 2457 if (isDestroyed()) return; 2458 mWindowFocused = hasWindowFocus; 2459 mContentViewCore.onWindowFocusChanged(hasWindowFocus); 2460 } 2461 2462 @Override 2463 public void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) { 2464 if (isDestroyed()) return; 2465 mContainerViewFocused = focused; 2466 mContentViewCore.onFocusChanged(focused); 2467 } 2468 2469 @Override 2470 public void onSizeChanged(int w, int h, int ow, int oh) { 2471 if (isDestroyed()) return; 2472 mScrollOffsetManager.setContainerViewSize(w, h); 2473 // The AwLayoutSizer needs to go first so that if we're in 2474 // fixedLayoutSize mode the update 2475 // to enter fixedLayoutSize mode is sent before the first resize 2476 // update. 2477 mLayoutSizer.onSizeChanged(w, h, ow, oh); 2478 mContentViewCore.onPhysicalBackingSizeChanged(w, h); 2479 mContentViewCore.onSizeChanged(w, h, ow, oh); 2480 nativeOnSizeChanged(mNativeAwContents, w, h, ow, oh); 2481 } 2482 2483 @Override 2484 public void onVisibilityChanged(View changedView, int visibility) { 2485 boolean viewVisible = mContainerView.getVisibility() == View.VISIBLE; 2486 if (mIsViewVisible == viewVisible) return; 2487 setViewVisibilityInternal(viewVisible); 2488 } 2489 2490 @Override 2491 public void onWindowVisibilityChanged(int visibility) { 2492 boolean windowVisible = visibility == View.VISIBLE; 2493 if (mIsWindowVisible == windowVisible) return; 2494 setWindowVisibilityInternal(windowVisible); 2495 } 2496 } 2497 2498 // Return true if the GeolocationPermissionAPI should be used. 2499 @CalledByNative 2500 private boolean useLegacyGeolocationPermissionAPI() { 2501 // Always return true since we are not ready to swap the geolocation yet. 2502 // TODO: If we decide not to migrate the geolocation, there are some unreachable 2503 // code need to remove. http://crbug.com/396184. 2504 return true; 2505 } 2506 2507 //-------------------------------------------------------------------------------------------- 2508 // Native methods 2509 //-------------------------------------------------------------------------------------------- 2510 2511 private static native long nativeInit(AwBrowserContext browserContext); 2512 private static native void nativeDestroy(long nativeAwContents); 2513 private static native void nativeSetAwDrawSWFunctionTable(long functionTablePointer); 2514 private static native void nativeSetAwDrawGLFunctionTable(long functionTablePointer); 2515 private static native long nativeGetAwDrawGLFunction(); 2516 private static native int nativeGetNativeInstanceCount(); 2517 private static native void nativeSetShouldDownloadFavicons(); 2518 2519 private native void nativeSetJavaPeers(long nativeAwContents, AwContents awContents, 2520 AwWebContentsDelegate webViewWebContentsDelegate, 2521 AwContentsClientBridge contentsClientBridge, 2522 AwContentsIoThreadClient ioThreadClient, 2523 InterceptNavigationDelegate navigationInterceptionDelegate); 2524 private native long nativeGetWebContents(long nativeAwContents); 2525 2526 private native void nativeDocumentHasImages(long nativeAwContents, Message message); 2527 private native void nativeGenerateMHTML( 2528 long nativeAwContents, String path, ValueCallback<String> callback); 2529 2530 private native void nativeAddVisitedLinks(long nativeAwContents, String[] visitedLinks); 2531 private native boolean nativeOnDraw(long nativeAwContents, Canvas canvas, 2532 boolean isHardwareAccelerated, int scrollX, int scrollY, 2533 int visibleLeft, int visibleTop, int visibleRight, int visibleBottom); 2534 private native void nativeFindAllAsync(long nativeAwContents, String searchString); 2535 private native void nativeFindNext(long nativeAwContents, boolean forward); 2536 private native void nativeClearMatches(long nativeAwContents); 2537 private native void nativeClearCache(long nativeAwContents, boolean includeDiskFiles); 2538 private native byte[] nativeGetCertificate(long nativeAwContents); 2539 2540 // Coordinates in desity independent pixels. 2541 private native void nativeRequestNewHitTestDataAt(long nativeAwContents, int x, int y); 2542 private native void nativeUpdateLastHitTestData(long nativeAwContents); 2543 2544 private native void nativeOnSizeChanged(long nativeAwContents, int w, int h, int ow, int oh); 2545 private native void nativeScrollTo(long nativeAwContents, int x, int y); 2546 private native void nativeSetViewVisibility(long nativeAwContents, boolean visible); 2547 private native void nativeSetWindowVisibility(long nativeAwContents, boolean visible); 2548 private native void nativeSetIsPaused(long nativeAwContents, boolean paused); 2549 private native void nativeOnAttachedToWindow(long nativeAwContents, int w, int h); 2550 private static native void nativeOnDetachedFromWindow(long nativeAwContents); 2551 private native void nativeSetDipScale(long nativeAwContents, float dipScale); 2552 2553 // Returns null if save state fails. 2554 private native byte[] nativeGetOpaqueState(long nativeAwContents); 2555 2556 // Returns false if restore state fails. 2557 private native boolean nativeRestoreFromOpaqueState(long nativeAwContents, byte[] state); 2558 2559 private native long nativeReleasePopupAwContents(long nativeAwContents); 2560 private native void nativeFocusFirstNode(long nativeAwContents); 2561 private native void nativeSetBackgroundColor(long nativeAwContents, int color); 2562 2563 private native long nativeGetAwDrawGLViewContext(long nativeAwContents); 2564 private native long nativeCapturePicture(long nativeAwContents, int width, int height); 2565 private native void nativeEnableOnNewPicture(long nativeAwContents, boolean enabled); 2566 private native void nativeClearView(long nativeAwContents); 2567 private native void nativeSetExtraHeadersForUrl(long nativeAwContents, 2568 String url, String extraHeaders); 2569 2570 private native void nativeInvokeGeolocationCallback( 2571 long nativeAwContents, boolean value, String requestingFrame); 2572 2573 private native void nativeSetJsOnlineProperty(long nativeAwContents, boolean networkUp); 2574 2575 private native void nativeTrimMemory(long nativeAwContents, int level, boolean visible); 2576 2577 private native void nativeCreatePdfExporter(long nativeAwContents, AwPdfExporter awPdfExporter); 2578 2579 private native void nativePreauthorizePermission(long nativeAwContents, String origin, 2580 long resources); 2581 } 2582