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