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