package org.chromium.android_webview;
+import android.annotation.SuppressLint;
+import android.app.Activity;
import android.content.ComponentCallbacks2;
import android.content.Context;
-import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
+import android.graphics.Paint;
import android.graphics.Picture;
import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
+import android.net.Uri;
import android.net.http.SslCertificate;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;
+import android.util.Pair;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
-import android.view.ViewTreeObserver;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityNodeProvider;
import android.webkit.ValueCallback;
import android.widget.OverScroller;
-import com.google.common.annotations.VisibleForTesting;
-
+import org.chromium.android_webview.permission.AwPermissionRequest;
import org.chromium.base.CalledByNative;
import org.chromium.base.JNINamespace;
import org.chromium.base.ThreadUtils;
+import org.chromium.base.VisibleForTesting;
+import org.chromium.components.navigation_interception.InterceptNavigationDelegate;
+import org.chromium.components.navigation_interception.NavigationParams;
import org.chromium.content.browser.ContentSettings;
-import org.chromium.content.browser.ContentVideoView;
import org.chromium.content.browser.ContentViewClient;
import org.chromium.content.browser.ContentViewCore;
import org.chromium.content.browser.ContentViewStatics;
-import org.chromium.content.browser.LoadUrlParams;
-import org.chromium.content.browser.NavigationHistory;
-import org.chromium.content.browser.PageTransitionTypes;
+import org.chromium.content.browser.WebContentsObserverAndroid;
import org.chromium.content.common.CleanupReference;
-import org.chromium.components.navigation_interception.InterceptNavigationDelegate;
-import org.chromium.components.navigation_interception.NavigationParams;
-import org.chromium.net.GURLUtils;
+import org.chromium.content_public.browser.GestureStateListener;
+import org.chromium.content_public.browser.JavaScriptCallback;
+import org.chromium.content_public.browser.LoadUrlParams;
+import org.chromium.content_public.browser.NavigationController;
+import org.chromium.content_public.browser.NavigationHistory;
+import org.chromium.content_public.browser.WebContents;
+import org.chromium.content_public.common.Referrer;
+import org.chromium.ui.base.ActivityWindowAndroid;
+import org.chromium.ui.base.PageTransitionTypes;
+import org.chromium.ui.base.WindowAndroid;
import org.chromium.ui.gfx.DeviceDisplayInfo;
import java.io.File;
import java.lang.annotation.Annotation;
import java.net.MalformedURLException;
import java.net.URL;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
import java.util.concurrent.Callable;
-import java.util.ArrayList;
-import java.util.List;
/**
* Exposes the native AwContents class, and together these classes wrap the ContentViewCore
* @see View#getScrollBarStyle()
*/
int super_getScrollBarStyle();
+ }
+ /**
+ * Interface that consumers of {@link AwContents} must implement to support
+ * native GL rendering.
+ */
+ public interface NativeGLDelegate {
/**
* Requests a callback on the native DrawGL method (see getAwDrawGLFunction)
* if called from within onDraw, |canvas| will be non-null and hardware accelerated.
- * otherwise, |canvas| will be null, and the container view itself will be hardware
- * accelerated.
+ * Otherwise, |canvas| will be null, and the container view itself will be hardware
+ * accelerated. If |waitForCompletion| is true, this method will not return until
+ * functor has returned.
+ * Should avoid setting |waitForCompletion| when |canvas| is not null.
+ * |containerView| is the view where the AwContents should be drawn.
*
* @return false indicates the GL draw request was not accepted, and the caller
* should fallback to the SW path.
*/
- boolean requestDrawGL(Canvas canvas);
+ boolean requestDrawGL(Canvas canvas, boolean waitForCompletion, View containerView);
+
+ /**
+ * Detaches the GLFunctor from the view tree.
+ */
+ void detachGLFunctor();
}
- private int mNativeAwContents;
+ /**
+ * Class to facilitate dependency injection. Subclasses by test code to provide mock versions of
+ * certain AwContents dependencies.
+ */
+ public static class DependencyFactory {
+ public AwLayoutSizer createLayoutSizer() {
+ return new AwLayoutSizer();
+ }
+
+ public AwScrollOffsetManager createScrollOffsetManager(
+ AwScrollOffsetManager.Delegate delegate, OverScroller overScroller) {
+ return new AwScrollOffsetManager(delegate, overScroller);
+ }
+ }
+
+ private long mNativeAwContents;
private final AwBrowserContext mBrowserContext;
- private final ViewGroup mContainerView;
+ private ViewGroup mContainerView;
+ private final AwLayoutChangeListener mLayoutChangeListener;
+ private final Context mContext;
private ContentViewCore mContentViewCore;
+ private WindowAndroid mWindowAndroid;
+ private WebContents mWebContents;
+ private NavigationController mNavigationController;
private final AwContentsClient mContentsClient;
+ private final AwContentViewClient mContentViewClient;
+ private WebContentsObserverAndroid mWebContentsObserver;
private final AwContentsClientBridge mContentsClientBridge;
- private final AwWebContentsDelegate mWebContentsDelegate;
+ private final AwWebContentsDelegateAdapter mWebContentsDelegate;
private final AwContentsIoThreadClient mIoThreadClient;
private final InterceptNavigationDelegateImpl mInterceptNavigationDelegate;
- private final InternalAccessDelegate mInternalAccessAdapter;
+ private InternalAccessDelegate mInternalAccessAdapter;
+ private final NativeGLDelegate mNativeGLDelegate;
private final AwLayoutSizer mLayoutSizer;
private final AwZoomControls mZoomControls;
private final AwScrollOffsetManager mScrollOffsetManager;
// Must call nativeUpdateLastHitTestData first to update this before use.
private final HitTestData mPossiblyStaleHitTestData = new HitTestData();
- private DefaultVideoPosterRequestHandler mDefaultVideoPosterRequestHandler;
+ private final DefaultVideoPosterRequestHandler mDefaultVideoPosterRequestHandler;
// Bound method for suppling Picture instances to the AwContentsClient. Will be null if the
// picture listener API has not yet been enabled, or if it is using invalidation-only mode.
private boolean mContainerViewFocused;
private boolean mWindowFocused;
- private boolean mClearViewActive;
- private boolean mPictureListenerEnabled;
-
- // These come from the compositor and are updated immediately (in contrast to the values in
+ // These come from the compositor and are updated synchronously (in contrast to the values in
// ContentViewCore, which are updated at end of every frame).
private float mPageScaleFactor = 1.0f;
+ private float mMinPageScaleFactor = 1.0f;
+ private float mMaxPageScaleFactor = 1.0f;
private float mContentWidthDip;
private float mContentHeightDip;
- private AwAutofillManagerDelegate mAwAutofillManagerDelegate;
+ private AwAutofillClient mAwAutofillClient;
+
+ private AwPdfExporter mAwPdfExporter;
+
+ private AwViewMethods mAwViewMethods;
+ private final FullScreenTransitionsState mFullScreenTransitionsState;
+
+ // This flag indicates that ShouldOverrideUrlNavigation should be posted
+ // through the resourcethrottle. This is only used for popup windows.
+ private boolean mDeferredShouldOverrideUrlLoadingIsPendingForPopup;
+
+ // The framework may temporarily detach our container view, for example during layout if
+ // we are a child of a ListView. This may cause many toggles of View focus, which we suppress
+ // when in this state.
+ private boolean mTemporarilyDetached;
- private ComponentCallbacks2 mComponentCallbacks;
+ // True when this AwContents has been destroyed.
+ // Do not use directly, call isDestroyed() instead.
+ private boolean mIsDestroyed = false;
private static final class DestroyRunnable implements Runnable {
- private int mNativeAwContents;
- private DestroyRunnable(int nativeAwContents) {
+ private final long mNativeAwContents;
+ private DestroyRunnable(long nativeAwContents) {
mNativeAwContents = nativeAwContents;
}
@Override
public void run() {
- // This is a no-op if not currently attached.
- nativeOnDetachedFromWindow(mNativeAwContents);
nativeDestroy(mNativeAwContents);
}
}
+ /**
+ * A class that stores the state needed to enter and exit fullscreen.
+ */
+ private static class FullScreenTransitionsState {
+ private final ViewGroup mInitialContainerView;
+ private final InternalAccessDelegate mInitialInternalAccessAdapter;
+ private final AwViewMethods mInitialAwViewMethods;
+ private FullScreenView mFullScreenView;
+
+ private FullScreenTransitionsState(ViewGroup initialContainerView,
+ InternalAccessDelegate initialInternalAccessAdapter,
+ AwViewMethods initialAwViewMethods) {
+ mInitialContainerView = initialContainerView;
+ mInitialInternalAccessAdapter = initialInternalAccessAdapter;
+ mInitialAwViewMethods = initialAwViewMethods;
+ }
+
+ private void enterFullScreen(FullScreenView fullScreenView) {
+ mFullScreenView = fullScreenView;
+ }
+
+ private void exitFullScreen() {
+ mFullScreenView = null;
+ }
+
+ private boolean isFullScreen() {
+ return mFullScreenView != null;
+ }
+
+ private ViewGroup getInitialContainerView() {
+ return mInitialContainerView;
+ }
+
+ private InternalAccessDelegate getInitialInternalAccessDelegate() {
+ return mInitialInternalAccessAdapter;
+ }
+
+ private AwViewMethods getInitialAwViewMethods() {
+ return mInitialAwViewMethods;
+ }
+
+ private FullScreenView getFullScreenView() {
+ return mFullScreenView;
+ }
+ }
+
// Reference to the active mNativeAwContents pointer while it is active use
// (ie before it is destroyed).
private CleanupReference mCleanupReference;
- // A list of references to native pointers where the Java counterpart has been
- // destroyed, but are held here because they are waiting for onDetachFromWindow
- // to release GL resources. This is cleared inside onDetachFromWindow.
- private List<CleanupReference> mPendingDetachCleanupReferences;
-
//--------------------------------------------------------------------------------------------
- private class IoThreadClientImpl implements AwContentsIoThreadClient {
+ private class IoThreadClientImpl extends AwContentsIoThreadClient {
// All methods are called on the IO thread.
@Override
}
@Override
- public InterceptedRequestData shouldInterceptRequest(final String url,
- boolean isMainFrame) {
- InterceptedRequestData interceptedRequestData;
+ public AwWebResourceResponse shouldInterceptRequest(
+ AwContentsClient.ShouldInterceptRequestParams params) {
+ String url = params.url;
+ AwWebResourceResponse awWebResourceResponse;
// Return the response directly if the url is default video poster url.
- interceptedRequestData = mDefaultVideoPosterRequestHandler.shouldInterceptRequest(url);
- if (interceptedRequestData != null) return interceptedRequestData;
+ awWebResourceResponse = mDefaultVideoPosterRequestHandler.shouldInterceptRequest(url);
+ if (awWebResourceResponse != null) return awWebResourceResponse;
- interceptedRequestData = mContentsClient.shouldInterceptRequest(url);
+ awWebResourceResponse = mContentsClient.shouldInterceptRequest(params);
- if (interceptedRequestData == null) {
+ if (awWebResourceResponse == null) {
mContentsClient.getCallbackHelper().postOnLoadResource(url);
}
- if (isMainFrame && interceptedRequestData != null &&
- interceptedRequestData.getData() == null) {
+ if (params.isMainFrame && awWebResourceResponse != null &&
+ awWebResourceResponse.getData() == null) {
// In this case the intercepted URLRequest job will simulate an empty response
// which doesn't trigger the onReceivedError callback. For WebViewClassic
// compatibility we synthesize that callback. http://crbug.com/180950
ErrorCodeConversionHelper.ERROR_UNKNOWN,
null /* filled in by the glue layer */, url);
}
- return interceptedRequestData;
+ return awWebResourceResponse;
}
@Override
}
@Override
- public void onDownloadStart(String url,
- String userAgent,
- String contentDisposition,
- String mimeType,
- long contentLength) {
+ public boolean shouldAcceptThirdPartyCookies() {
+ return mSettings.getAcceptThirdPartyCookies();
+ }
+
+ @Override
+ public void onDownloadStart(String url, String userAgent,
+ String contentDisposition, String mimeType, long contentLength) {
mContentsClient.getCallbackHelper().postOnDownloadStart(url, userAgent,
contentDisposition, mimeType, contentLength);
}
}
//--------------------------------------------------------------------------------------------
+ // When the navigation is for a newly created WebView (i.e. a popup), intercept the navigation
+ // here for implementing shouldOverrideUrlLoading. This is to send the shouldOverrideUrlLoading
+ // callback to the correct WebViewClient that is associated with the WebView.
+ // Otherwise, use this delegate only to post onPageStarted messages.
+ //
+ // We are not using WebContentsObserver.didStartLoading because of stale URLs, out of order
+ // onPageStarted's and double onPageStarted's.
+ //
private class InterceptNavigationDelegateImpl implements InterceptNavigationDelegate {
- private String mLastLoadUrlAddress;
-
- public void onUrlLoadRequested(String url) {
- mLastLoadUrlAddress = url;
- }
-
@Override
public boolean shouldIgnoreNavigation(NavigationParams navigationParams) {
final String url = navigationParams.url;
- final int transitionType = navigationParams.pageTransitionType;
- final boolean isLoadUrl =
- (transitionType & PageTransitionTypes.PAGE_TRANSITION_FROM_API) != 0;
- final boolean isBackForward =
- (transitionType & PageTransitionTypes.PAGE_TRANSITION_FORWARD_BACK) != 0;
- final boolean isReload =
- (transitionType & PageTransitionTypes.PAGE_TRANSITION_CORE_MASK) ==
- PageTransitionTypes.PAGE_TRANSITION_RELOAD;
- final boolean isRedirect = navigationParams.isRedirect;
-
boolean ignoreNavigation = false;
-
- // Any navigation from loadUrl, goBack/Forward, or reload, are considered application
- // initiated and hence will not yield a shouldOverrideUrlLoading() callback.
- // TODO(joth): Using PageTransitionTypes should be sufficient to determine all app
- // initiated navigations, and so mLastLoadUrlAddress should be removed.
- if ((isLoadUrl && !isRedirect) || isBackForward || isReload ||
- mLastLoadUrlAddress != null && mLastLoadUrlAddress.equals(url)) {
- // Support the case where the user clicks on a link that takes them back to the
- // same page.
- mLastLoadUrlAddress = null;
-
- // If the embedder requested the load of a certain URL via the loadUrl API, then we
- // do not offer it to AwContentsClient.shouldOverrideUrlLoading.
- // The embedder is also not allowed to intercept POST requests because of
- // crbug.com/155250.
- } else if (!navigationParams.isPost) {
- ignoreNavigation = mContentsClient.shouldOverrideUrlLoading(url);
+ if (mDeferredShouldOverrideUrlLoadingIsPendingForPopup) {
+ mDeferredShouldOverrideUrlLoadingIsPendingForPopup = false;
+ // If this is used for all navigations in future, cases for application initiated
+ // load, redirect and backforward should also be filtered out.
+ if (!navigationParams.isPost) {
+ ignoreNavigation = mContentsClient.shouldOverrideUrlLoading(url);
+ }
}
-
- // The existing contract is that shouldOverrideUrlLoading callbacks are delivered before
- // onPageStarted callbacks; third party apps depend on this behavior.
- // Using a ResouceThrottle to implement the navigation interception feature results in
- // the WebContentsObserver.didStartLoading callback happening before the
- // ResourceThrottle has a chance to run.
- // To preserve the ordering the onPageStarted callback is synthesized from the
- // shouldOverrideUrlLoading, and only if the navigation was not ignored (this
- // balances out with the onPageFinished callback, which is suppressed in the
- // AwContentsClient if the navigation was ignored).
+ // The shouldOverrideUrlLoading call might have resulted in posting messages to the
+ // UI thread. Using sendMessage here (instead of calling onPageStarted directly)
+ // will allow those to run in order.
if (!ignoreNavigation) {
- // The shouldOverrideUrlLoading call might have resulted in posting messages to the
- // UI thread. Using sendMessage here (instead of calling onPageStarted directly)
- // will allow those to run in order.
mContentsClient.getCallbackHelper().postOnPageStarted(url);
}
-
return ignoreNavigation;
}
}
}
@Override
- public void setFixedLayoutSize(int widthDip, int heightDip) {
- if (mNativeAwContents == 0) return;
- nativeSetFixedLayoutSize(mNativeAwContents, widthDip, heightDip);
+ public boolean isLayoutParamsHeightWrapContent() {
+ return mContainerView.getLayoutParams() != null &&
+ mContainerView.getLayoutParams().height == ViewGroup.LayoutParams.WRAP_CONTENT;
}
@Override
- public boolean isLayoutParamsHeightWrapContent() {
- return mContainerView.getLayoutParams() != null &&
- mContainerView.getLayoutParams().height == ViewGroup.LayoutParams.WRAP_CONTENT;
+ public void setForceZeroLayoutHeight(boolean forceZeroHeight) {
+ getSettings().setForceZeroLayoutHeight(forceZeroHeight);
}
}
@Override
public void scrollNativeTo(int x, int y) {
- if (mNativeAwContents == 0) return;
- nativeScrollTo(mNativeAwContents, x, y);
+ if (!isDestroyed()) nativeScrollTo(mNativeAwContents, x, y);
}
@Override
}
//--------------------------------------------------------------------------------------------
- private class AwGestureStateListener implements ContentViewCore.GestureStateListener {
+ private class AwGestureStateListener extends GestureStateListener {
@Override
- public void onPinchGestureStart() {
+ public void onPinchStarted() {
// While it's possible to re-layout the view during a pinch gesture, the effect is very
// janky (especially that the page scale update notification comes from the renderer
// main thread, not from the impl thread, so it's usually out of sync with what's on
}
@Override
- public void onPinchGestureEnd() {
+ public void onPinchEnded() {
mLayoutSizer.unfreezeLayoutRequests();
}
@Override
- public void onFlingStartGesture(int velocityX, int velocityY) {
- mScrollOffsetManager.onFlingStartGesture(velocityX, velocityY);
- }
-
- @Override
public void onFlingCancelGesture() {
mScrollOffsetManager.onFlingCancelGesture();
}
@Override
- public void onUnhandledFlingStartEvent() {
- mScrollOffsetManager.onUnhandledFlingStartEvent();
+ public void onUnhandledFlingStartEvent(int velocityX, int velocityY) {
+ mScrollOffsetManager.onUnhandledFlingStartEvent(velocityX, velocityY);
}
@Override
//--------------------------------------------------------------------------------------------
private class AwComponentCallbacks implements ComponentCallbacks2 {
- @Override
- public void onTrimMemory(int level) {
- if (mNativeAwContents == 0) return;
- nativeTrimMemory(mNativeAwContents, level);
- }
-
- @Override
- public void onLowMemory() {
- }
-
- @Override
- public void onConfigurationChanged(Configuration configuration) {
- }
+ @Override
+ public void onTrimMemory(final int level) {
+ if (isDestroyed()) return;
+ boolean visibleRectEmpty = getGlobalVisibleRect().isEmpty();
+ final boolean visible = mIsViewVisible && mIsWindowVisible && !visibleRectEmpty;
+ nativeTrimMemory(mNativeAwContents, level, visible);
+ }
+
+ @Override
+ public void onLowMemory() {}
+
+ @Override
+ public void onConfigurationChanged(Configuration configuration) {}
};
//--------------------------------------------------------------------------------------------
/**
* @param browserContext the browsing context to associate this view contents with.
* @param containerView the view-hierarchy item this object will be bound to.
+ * @param context the context to use, usually containerView.getContext().
* @param internalAccessAdapter to access private methods on containerView.
- * @param contentsClient will receive API callbacks from this WebView Contents
- * @param isAccessFromFileURLsGrantedByDefault passed to AwSettings.
+ * @param nativeGLDelegate to access the GL functor provided by the WebView.
+ * @param contentsClient will receive API callbacks from this WebView Contents.
+ * @param awSettings AwSettings instance used to configure the AwContents.
*
* This constructor uses the default view sizing policy.
*/
- public AwContents(AwBrowserContext browserContext, ViewGroup containerView,
- InternalAccessDelegate internalAccessAdapter, AwContentsClient contentsClient,
- boolean isAccessFromFileURLsGrantedByDefault) {
- this(browserContext, containerView, internalAccessAdapter, contentsClient,
- isAccessFromFileURLsGrantedByDefault, new AwLayoutSizer());
- }
-
- public AwContents(AwBrowserContext browserContext, ViewGroup containerView,
- InternalAccessDelegate internalAccessAdapter, AwContentsClient contentsClient,
- boolean isAccessFromFileURLsGrantedByDefault, AwLayoutSizer layoutSizer) {
- this(browserContext, containerView, internalAccessAdapter, contentsClient,
- isAccessFromFileURLsGrantedByDefault, layoutSizer, false);
- }
-
- private static ContentViewCore createAndInitializeContentViewCore(ViewGroup containerView,
- InternalAccessDelegate internalDispatcher, int nativeWebContents,
- ContentViewCore.GestureStateListener pinchGestureStateListener,
- ContentViewClient contentViewClient,
- ContentViewCore.ZoomControlsDelegate zoomControlsDelegate) {
- ContentViewCore contentViewCore = new ContentViewCore(containerView.getContext());
- // Note INPUT_EVENTS_DELIVERED_IMMEDIATELY is passed to avoid triggering vsync in the
- // compositor, not because input events are delivered immediately.
- contentViewCore.initialize(containerView, internalDispatcher, nativeWebContents, null,
- ContentViewCore.INPUT_EVENTS_DELIVERED_IMMEDIATELY);
- contentViewCore.setGestureStateListener(pinchGestureStateListener);
- contentViewCore.setContentViewClient(contentViewClient);
- contentViewCore.setZoomControlsDelegate(zoomControlsDelegate);
- return contentViewCore;
+ public AwContents(AwBrowserContext browserContext, ViewGroup containerView, Context context,
+ InternalAccessDelegate internalAccessAdapter, NativeGLDelegate nativeGLDelegate,
+ AwContentsClient contentsClient, AwSettings awSettings) {
+ this(browserContext, containerView, context, internalAccessAdapter, nativeGLDelegate,
+ contentsClient, awSettings, new DependencyFactory());
}
/**
- * @param layoutSizer the AwLayoutSizer instance implementing the sizing policy for the view.
+ * @param dependencyFactory an instance of the DependencyFactory used to provide instances of
+ * classes that this class depends on.
*
* This version of the constructor is used in test code to inject test versions of the above
- * documented classes
+ * documented classes.
*/
- public AwContents(AwBrowserContext browserContext, ViewGroup containerView,
- InternalAccessDelegate internalAccessAdapter, AwContentsClient contentsClient,
- boolean isAccessFromFileURLsGrantedByDefault, AwLayoutSizer layoutSizer,
- boolean supportsLegacyQuirks) {
- this(browserContext, containerView, internalAccessAdapter, contentsClient,
- layoutSizer, new AwSettings(containerView.getContext(),
- isAccessFromFileURLsGrantedByDefault, supportsLegacyQuirks));
- }
-
- public AwContents(AwBrowserContext browserContext, ViewGroup containerView,
- InternalAccessDelegate internalAccessAdapter, AwContentsClient contentsClient,
- AwLayoutSizer layoutSizer, AwSettings settings) {
+ public AwContents(AwBrowserContext browserContext, ViewGroup containerView, Context context,
+ InternalAccessDelegate internalAccessAdapter, NativeGLDelegate nativeGLDelegate,
+ AwContentsClient contentsClient, AwSettings settings,
+ DependencyFactory dependencyFactory) {
mBrowserContext = browserContext;
mContainerView = containerView;
+ mContext = context;
mInternalAccessAdapter = internalAccessAdapter;
+ mNativeGLDelegate = nativeGLDelegate;
mContentsClient = contentsClient;
- mLayoutSizer = layoutSizer;
+ mAwViewMethods = new AwViewMethodsImpl();
+ mFullScreenTransitionsState = new FullScreenTransitionsState(
+ mContainerView, mInternalAccessAdapter, mAwViewMethods);
+ mContentViewClient = new AwContentViewClient(contentsClient, settings, this, mContext);
+ mLayoutSizer = dependencyFactory.createLayoutSizer();
mSettings = settings;
- mDIPScale = DeviceDisplayInfo.create(mContainerView.getContext()).getDIPScale();
+ mDIPScale = DeviceDisplayInfo.create(mContext).getDIPScale();
mLayoutSizer.setDelegate(new AwLayoutSizerDelegate());
mLayoutSizer.setDIPScale(mDIPScale);
- mWebContentsDelegate = new AwWebContentsDelegateAdapter(contentsClient, mContainerView);
- mContentsClientBridge = new AwContentsClientBridge(contentsClient);
+ mWebContentsDelegate = new AwWebContentsDelegateAdapter(
+ contentsClient, mContainerView, mContext);
+ mContentsClientBridge = new AwContentsClientBridge(contentsClient,
+ mBrowserContext.getKeyStore(), AwContentsStatics.getClientCertLookupTable());
mZoomControls = new AwZoomControls(this);
mIoThreadClient = new IoThreadClientImpl();
mInterceptNavigationDelegate = new InterceptNavigationDelegateImpl();
AwSettings.ZoomSupportChangeListener zoomListener =
new AwSettings.ZoomSupportChangeListener() {
@Override
- public void onGestureZoomSupportChanged(boolean supportsGestureZoom) {
- mContentViewCore.updateMultiTouchZoomSupport(supportsGestureZoom);
- mContentViewCore.updateDoubleTapSupport(supportsGestureZoom);
+ public void onGestureZoomSupportChanged(
+ boolean supportsDoubleTapZoom, boolean supportsMultiTouchZoom) {
+ if (isDestroyed()) return;
+ mContentViewCore.updateDoubleTapSupport(supportsDoubleTapZoom);
+ mContentViewCore.updateMultiTouchZoomSupport(supportsMultiTouchZoom);
}
};
mSettings.setDefaultVideoPosterURL(
mDefaultVideoPosterRequestHandler.getDefaultVideoPosterURL());
mSettings.setDIPScale(mDIPScale);
- mScrollOffsetManager = new AwScrollOffsetManager(new AwScrollOffsetManagerDelegate(),
- new OverScroller(mContainerView.getContext()));
+ mScrollOffsetManager = dependencyFactory.createScrollOffsetManager(
+ new AwScrollOffsetManagerDelegate(), new OverScroller(mContext));
mScrollAccessibilityHelper = new ScrollAccessibilityHelper(mContainerView);
setOverScrollMode(mContainerView.getOverScrollMode());
setScrollBarStyle(mInternalAccessAdapter.super_getScrollBarStyle());
- mContainerView.addOnLayoutChangeListener(new AwLayoutChangeListener());
+ mLayoutChangeListener = new AwLayoutChangeListener();
+ mContainerView.addOnLayoutChangeListener(mLayoutChangeListener);
setNewAwContents(nativeInit(mBrowserContext));
- onVisibilityChanged(mContainerView, mContainerView.getVisibility());
- onWindowVisibilityChanged(mContainerView.getWindowVisibility());
+ onContainerViewChanged();
+ }
+
+ private static ContentViewCore createAndInitializeContentViewCore(ViewGroup containerView,
+ Context context, InternalAccessDelegate internalDispatcher, long nativeWebContents,
+ GestureStateListener gestureStateListener,
+ ContentViewClient contentViewClient,
+ ContentViewCore.ZoomControlsDelegate zoomControlsDelegate,
+ WindowAndroid windowAndroid) {
+ ContentViewCore contentViewCore = new ContentViewCore(context);
+ contentViewCore.initialize(containerView, internalDispatcher, nativeWebContents,
+ windowAndroid);
+ contentViewCore.addGestureStateListener(gestureStateListener);
+ contentViewCore.setContentViewClient(contentViewClient);
+ contentViewCore.setZoomControlsDelegate(zoomControlsDelegate);
+ return contentViewCore;
+ }
+
+ boolean isFullScreen() {
+ return mFullScreenTransitionsState.isFullScreen();
}
/**
- * Common initialization routine for adopting a native AwContents instance into this
+ * Transitions this {@link AwContents} to fullscreen mode and returns the
+ * {@link View} where the contents will be drawn while in fullscreen, or null
+ * if this AwContents has already been destroyed.
+ */
+ View enterFullScreen() {
+ assert !isFullScreen();
+ if (isDestroyed()) return null;
+
+ // Detach to tear down the GL functor if this is still associated with the old
+ // container view. It will be recreated during the next call to onDraw attached to
+ // the new container view.
+ onDetachedFromWindow();
+
+ // In fullscreen mode FullScreenView owns the AwViewMethodsImpl and AwContents
+ // a NullAwViewMethods.
+ FullScreenView fullScreenView = new FullScreenView(mContext, mAwViewMethods);
+ mFullScreenTransitionsState.enterFullScreen(fullScreenView);
+ mAwViewMethods = new NullAwViewMethods(this, mInternalAccessAdapter, mContainerView);
+ mContainerView.removeOnLayoutChangeListener(mLayoutChangeListener);
+ fullScreenView.addOnLayoutChangeListener(mLayoutChangeListener);
+
+ // Associate this AwContents with the FullScreenView.
+ setInternalAccessAdapter(fullScreenView.getInternalAccessAdapter());
+ setContainerView(fullScreenView);
+
+ return fullScreenView;
+ }
+
+ /**
+ * Returns this {@link AwContents} to embedded mode, where the {@link AwContents} are drawn
+ * in the WebView.
+ */
+ void exitFullScreen() {
+ if (!isFullScreen() || isDestroyed())
+ // exitFullScreen() can be called without a prior call to enterFullScreen() if a
+ // "misbehave" app overrides onShowCustomView but does not add the custom view to
+ // the window. Exiting avoids a crash.
+ return;
+
+ // Detach to tear down the GL functor if this is still associated with the old
+ // container view. It will be recreated during the next call to onDraw attached to
+ // the new container view.
+ // NOTE: we cannot use mAwViewMethods here because its type is NullAwViewMethods.
+ AwViewMethods awViewMethodsImpl = mFullScreenTransitionsState.getInitialAwViewMethods();
+ awViewMethodsImpl.onDetachedFromWindow();
+
+ // Swap the view delegates. In embedded mode the FullScreenView owns a
+ // NullAwViewMethods and AwContents the AwViewMethodsImpl.
+ FullScreenView fullscreenView = mFullScreenTransitionsState.getFullScreenView();
+ fullscreenView.setAwViewMethods(new NullAwViewMethods(
+ this, fullscreenView.getInternalAccessAdapter(), fullscreenView));
+ mAwViewMethods = awViewMethodsImpl;
+ ViewGroup initialContainerView = mFullScreenTransitionsState.getInitialContainerView();
+ initialContainerView.addOnLayoutChangeListener(mLayoutChangeListener);
+ fullscreenView.removeOnLayoutChangeListener(mLayoutChangeListener);
+
+ // Re-associate this AwContents with the WebView.
+ setInternalAccessAdapter(mFullScreenTransitionsState.getInitialInternalAccessDelegate());
+ setContainerView(initialContainerView);
+
+ mFullScreenTransitionsState.exitFullScreen();
+ }
+
+ private void setInternalAccessAdapter(InternalAccessDelegate internalAccessAdapter) {
+ mInternalAccessAdapter = internalAccessAdapter;
+ mContentViewCore.setContainerViewInternals(mInternalAccessAdapter);
+ }
+
+ private void setContainerView(ViewGroup newContainerView) {
+ mContainerView = newContainerView;
+ mContentViewCore.setContainerView(mContainerView);
+ if (mAwPdfExporter != null) {
+ mAwPdfExporter.setContainerView(mContainerView);
+ }
+ mWebContentsDelegate.setContainerView(mContainerView);
+
+ onContainerViewChanged();
+ }
+
+ /**
+ * Reconciles the state of this AwContents object with the state of the new container view.
+ */
+ private void onContainerViewChanged() {
+ // NOTE: mAwViewMethods is used by the old container view, the WebView, so it might refer
+ // to a NullAwViewMethods when in fullscreen. To ensure that the state is reconciled with
+ // the new container view correctly, we bypass mAwViewMethods and use the real
+ // implementation directly.
+ AwViewMethods awViewMethodsImpl = mFullScreenTransitionsState.getInitialAwViewMethods();
+ awViewMethodsImpl.onVisibilityChanged(mContainerView, mContainerView.getVisibility());
+ awViewMethodsImpl.onWindowVisibilityChanged(mContainerView.getWindowVisibility());
+
+ // We should stop running WebView tests in JellyBean devices, see crbug/161864.
+ // Until then we skip calling isAttachedToWindow() as it has only been introduced in K.
+ if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.KITKAT
+ || mContainerView.isAttachedToWindow()) {
+ awViewMethodsImpl.onAttachedToWindow();
+ } else {
+ awViewMethodsImpl.onDetachedFromWindow();
+ }
+ awViewMethodsImpl.onSizeChanged(
+ mContainerView.getWidth(), mContainerView.getHeight(), 0, 0);
+ awViewMethodsImpl.onWindowFocusChanged(mContainerView.hasWindowFocus());
+ awViewMethodsImpl.onFocusChanged(mContainerView.hasFocus(), 0, null);
+ mContainerView.requestLayout();
+ }
+
+ /* Common initialization routine for adopting a native AwContents instance into this
* java instance.
*
* TAKE CARE! This method can get called multiple times per java instance. Code accordingly.
* ^^^^^^^^^ See the native class declaration for more details on relative object lifetimes.
*/
- private void setNewAwContents(int newAwContentsPtr) {
+ private void setNewAwContents(long newAwContentsPtr) {
if (mNativeAwContents != 0) {
- destroy();
+ destroyNatives();
mContentViewCore = null;
+ mWebContents = null;
+ mNavigationController = null;
}
assert mNativeAwContents == 0 && mCleanupReference == null && mContentViewCore == null;
// bind all the native->java relationships.
mCleanupReference = new CleanupReference(this, new DestroyRunnable(mNativeAwContents));
- int nativeWebContents = nativeGetWebContents(mNativeAwContents);
+ long nativeWebContents = nativeGetWebContents(mNativeAwContents);
+
+ mWindowAndroid = mContext instanceof Activity ?
+ new ActivityWindowAndroid((Activity) mContext) :
+ new WindowAndroid(mContext.getApplicationContext());
mContentViewCore = createAndInitializeContentViewCore(
- mContainerView, mInternalAccessAdapter, nativeWebContents,
- new AwGestureStateListener(), mContentsClient.getContentViewClient(),
- mZoomControls);
+ mContainerView, mContext, mInternalAccessAdapter, nativeWebContents,
+ new AwGestureStateListener(), mContentViewClient, mZoomControls, mWindowAndroid);
nativeSetJavaPeers(mNativeAwContents, this, mWebContentsDelegate, mContentsClientBridge,
mIoThreadClient, mInterceptNavigationDelegate);
- mContentsClient.installWebContentsObserver(mContentViewCore);
+ mWebContents = mContentViewCore.getWebContents();
+ mNavigationController = mWebContents.getNavigationController();
+ installWebContentsObserver();
mSettings.setWebContents(nativeWebContents);
nativeSetDipScale(mNativeAwContents, (float) mDIPScale);
- updateGlobalVisibleRect();
-
- // The only call to onShow. onHide should never be called.
mContentViewCore.onShow();
- }
+ }
+
+ private void installWebContentsObserver() {
+ if (mWebContentsObserver != null) {
+ mWebContentsObserver.detachFromWebContents();
+ }
+ mWebContentsObserver = new AwWebContentsObserver(mWebContents, mContentsClient);
+ }
/**
* Called on the "source" AwContents that is opening the popup window to
* provide the AwContents to host the pop up content.
*/
public void supplyContentsForPopup(AwContents newContents) {
- int popupNativeAwContents = nativeReleasePopupAwContents(mNativeAwContents);
+ long popupNativeAwContents = nativeReleasePopupAwContents(mNativeAwContents);
if (popupNativeAwContents == 0) {
Log.w(TAG, "Popup WebView bind failed: no pending content.");
if (newContents != null) newContents.destroy();
// Recap: supplyContentsForPopup() is called on the parent window's content, this method is
// called on the popup window's content.
- private void receivePopupContents(int popupNativeAwContents) {
+ private void receivePopupContents(long popupNativeAwContents) {
+ mDeferredShouldOverrideUrlLoadingIsPendingForPopup = true;
// Save existing view state.
final boolean wasAttached = mIsAttachedToWindow;
final boolean wasViewVisible = mIsViewVisible;
if (wasWindowFocused) onWindowFocusChanged(false);
if (wasViewVisible) setViewVisibilityInternal(false);
if (wasWindowVisible) setWindowVisibilityInternal(false);
+ if (wasAttached) onDetachedFromWindow();
if (!wasPaused) onPause();
- // Not calling onDetachedFromWindow here because native code requires GL context to release
- // GL resources. This case is properly handled when destroy is called while still attached
- // to window.
+
+ // Save injected JavaScript interfaces.
+ Map<String, Pair<Object, Class>> javascriptInterfaces =
+ new HashMap<String, Pair<Object, Class>>();
+ if (mContentViewCore != null) {
+ javascriptInterfaces.putAll(mContentViewCore.getJavascriptInterfaces());
+ }
setNewAwContents(popupNativeAwContents);
// Finally refresh all view state for mContentViewCore and mNativeAwContents.
if (!wasPaused) onResume();
- if (wasAttached) onAttachedToWindow();
+ if (wasAttached) {
+ onAttachedToWindow();
+ postInvalidateOnAnimation();
+ }
onSizeChanged(mContainerView.getWidth(), mContainerView.getHeight(), 0, 0);
if (wasWindowVisible) setWindowVisibilityInternal(true);
if (wasViewVisible) setViewVisibilityInternal(true);
if (wasWindowFocused) onWindowFocusChanged(wasWindowFocused);
if (wasFocused) onFocusChanged(true, 0, null);
+
+ // Restore injected JavaScript interfaces.
+ for (Map.Entry<String, Pair<Object, Class>> entry : javascriptInterfaces.entrySet()) {
+ @SuppressWarnings("unchecked")
+ Class<? extends Annotation> requiredAnnotation = entry.getValue().second;
+ mContentViewCore.addPossiblyUnsafeJavascriptInterface(
+ entry.getValue().first,
+ entry.getKey(),
+ requiredAnnotation);
+ }
}
/**
- * Deletes the native counterpart of this object. Normally happens immediately,
- * but maybe deferred until the appropriate time for GL resource cleanup. Either way
- * this is transparent to the caller: after this function returns the object is
- * effectively dead and methods are no-ops.
+ * Destroys this object and deletes its native counterpart.
*/
public void destroy() {
+ mIsDestroyed = true;
+ destroyNatives();
+ }
+
+ /**
+ * Deletes the native counterpart of this object.
+ */
+ private void destroyNatives() {
if (mCleanupReference != null) {
- // We explicitly do not null out the mContentViewCore reference here
- // because ContentViewCore already has code to deal with the case
- // methods are called on it after it's been destroyed, and other
- // code relies on AwContents.mContentViewCore to be non-null.
+ assert mNativeAwContents != 0;
+ // If we are attached, we have to call native detach to clean up
+ // hardware resources.
+ if (mIsAttachedToWindow) {
+ nativeOnDetachedFromWindow(mNativeAwContents);
+ }
+
+ mWebContentsObserver.detachFromWebContents();
+ mWebContentsObserver = null;
mContentViewCore.destroy();
+ mContentViewCore = null;
mNativeAwContents = 0;
+ mWebContents = null;
+ mNavigationController = null;
- // We cannot destroy immediately if we are still attached to the window.
- // Instead if we make sure to null out the native pointer so there is no more native
- // calls, and delay the actual destroy until onDetachedFromWindow.
- if (mIsAttachedToWindow) {
- if (mPendingDetachCleanupReferences == null) {
- mPendingDetachCleanupReferences = new ArrayList<CleanupReference>();
- }
- mPendingDetachCleanupReferences.add(mCleanupReference);
- } else {
- mCleanupReference.cleanupNow();
- }
+ mCleanupReference.cleanupNow();
mCleanupReference = null;
}
- assert !mContentViewCore.isAlive();
+ assert mContentViewCore == null;
+ assert mWebContents == null;
+ assert mNavigationController == null;
assert mNativeAwContents == 0;
}
+ private boolean isDestroyed() {
+ if (mIsDestroyed) {
+ assert mContentViewCore == null;
+ assert mWebContents == null;
+ assert mNavigationController == null;
+ assert mNativeAwContents == 0;
+ } else {
+ assert mContentViewCore != null;
+ assert mWebContents != null;
+ assert mNavigationController != null;
+ assert mNativeAwContents != 0;
+ }
+ return mIsDestroyed;
+ }
+
@VisibleForTesting
public ContentViewCore getContentViewCore() {
return mContentViewCore;
}
+ @VisibleForTesting
+ public WebContents getWebContents() {
+ return mWebContents;
+ }
+
+ @VisibleForTesting
+ public NavigationController getNavigationController() {
+ return mNavigationController;
+ }
+
// Can be called from any thread.
public AwSettings getSettings() {
return mSettings;
}
- public static void setAwDrawSWFunctionTable(int functionTablePointer) {
+ public AwPdfExporter getPdfExporter() {
+ if (isDestroyed()) return null;
+ if (mAwPdfExporter == null) {
+ mAwPdfExporter = new AwPdfExporter(mContainerView);
+ nativeCreatePdfExporter(mNativeAwContents, mAwPdfExporter);
+ }
+ return mAwPdfExporter;
+ }
+
+ public static void setAwDrawSWFunctionTable(long functionTablePointer) {
nativeSetAwDrawSWFunctionTable(functionTablePointer);
}
- public static void setAwDrawGLFunctionTable(int functionTablePointer) {
+ public static void setAwDrawGLFunctionTable(long functionTablePointer) {
nativeSetAwDrawGLFunctionTable(functionTablePointer);
}
- public static int getAwDrawGLFunction() {
+ public static long getAwDrawGLFunction() {
return nativeGetAwDrawGLFunction();
}
}
/**
+ * Disables contents of JS-to-Java bridge objects to be inspectable using
+ * Object.keys() method and "for .. in" loops. This is intended for applications
+ * targeting earlier Android releases where this was not possible, and we want
+ * to ensure backwards compatible behavior.
+ */
+ public void disableJavascriptInterfacesInspection() {
+ if (!isDestroyed()) mContentViewCore.setAllowJavascriptInterfacesInspection(false);
+ }
+
+ /**
* Intended for test code.
* @return the number of native instances of this class.
*/
return nativeGetNativeInstanceCount();
}
- public int getAwDrawGLViewContext() {
+ public long getAwDrawGLViewContext() {
// Only called during early construction, so client should not have had a chance to
// call destroy yet.
- assert mNativeAwContents != 0;
+ assert !isDestroyed();
// Using the native pointer as the returned viewContext. This is matched by the
// reinterpret_cast back to BrowserViewRenderer pointer in the native DrawGLFunction.
return nativeGetAwDrawGLViewContext(mNativeAwContents);
}
- // This is only to avoid heap allocations inside updateGLobalVisibleRect. It should treated
+ // This is only to avoid heap allocations inside getGlobalVisibleRect. It should treated
// as a local variable in the function and not used anywhere else.
private static final Rect sLocalGlobalVisibleRect = new Rect();
- @CalledByNative
- private void updateGlobalVisibleRect() {
- if (mNativeAwContents == 0) return;
+ private Rect getGlobalVisibleRect() {
if (!mContainerView.getGlobalVisibleRect(sLocalGlobalVisibleRect)) {
sLocalGlobalVisibleRect.setEmpty();
}
-
- nativeSetGlobalVisibleRect(mNativeAwContents, sLocalGlobalVisibleRect.left,
- sLocalGlobalVisibleRect.top, sLocalGlobalVisibleRect.right,
- sLocalGlobalVisibleRect.bottom);
+ return sLocalGlobalVisibleRect;
}
//--------------------------------------------------------------------------------------------
// WebView[Provider] method implementations (where not provided by ContentViewCore)
//--------------------------------------------------------------------------------------------
- // Only valid within onDraw().
- private final Rect mClipBoundsTemporary = new Rect();
-
public void onDraw(Canvas canvas) {
- if (mNativeAwContents == 0) {
- canvas.drawColor(getEffectiveBackgroundColor());
- return;
- }
-
- mScrollOffsetManager.syncScrollOffsetFromOnDraw();
- canvas.getClipBounds(mClipBoundsTemporary);
-
- if (mClearViewActive) {
- canvas.drawColor(getEffectiveBackgroundColor());
- } else if (!nativeOnDraw(mNativeAwContents, canvas, canvas.isHardwareAccelerated(),
- mContainerView.getScrollX(), mContainerView.getScrollY(),
- mClipBoundsTemporary.left, mClipBoundsTemporary.top,
- mClipBoundsTemporary.right, mClipBoundsTemporary.bottom)) {
- Log.w(TAG, "nativeOnDraw failed; clearing to background color.");
- canvas.drawColor(getEffectiveBackgroundColor());
- }
-
- if (mOverScrollGlow != null && mOverScrollGlow.drawEdgeGlows(canvas,
- mScrollOffsetManager.computeMaximumHorizontalScrollOffset(),
- mScrollOffsetManager.computeMaximumVerticalScrollOffset())) {
- mContainerView.invalidate();
- }
+ mAwViewMethods.onDraw(canvas);
}
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- mLayoutSizer.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ mAwViewMethods.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
public int getContentHeightCss() {
}
public Picture capturePicture() {
- if (mNativeAwContents == 0) return null;
+ if (isDestroyed()) return null;
return new AwPicture(nativeCapturePicture(mNativeAwContents,
- mScrollOffsetManager.computeHorizontalScrollRange(),
- mScrollOffsetManager.computeVerticalScrollRange()));
+ mScrollOffsetManager.computeHorizontalScrollRange(),
+ mScrollOffsetManager.computeVerticalScrollRange()));
}
public void clearView() {
- mClearViewActive = true;
- syncOnNewPictureStateToNative();
- mContainerView.invalidate();
+ if (!isDestroyed()) nativeClearView(mNativeAwContents);
}
/**
* @param invalidationOnly Flag to call back only on invalidation without providing a picture.
*/
public void enableOnNewPicture(boolean enabled, boolean invalidationOnly) {
- if (mNativeAwContents == 0) return;
+ if (isDestroyed()) return;
if (invalidationOnly) {
mPictureListenerContentProvider = null;
} else if (enabled && mPictureListenerContentProvider == null) {
}
};
}
- mPictureListenerEnabled = enabled;
- syncOnNewPictureStateToNative();
- }
-
- private void syncOnNewPictureStateToNative() {
- nativeEnableOnNewPicture(mNativeAwContents, mPictureListenerEnabled || mClearViewActive);
+ nativeEnableOnNewPicture(mNativeAwContents, enabled);
}
public void findAllAsync(String searchString) {
- if (mNativeAwContents == 0) return;
- nativeFindAllAsync(mNativeAwContents, searchString);
+ if (!isDestroyed()) nativeFindAllAsync(mNativeAwContents, searchString);
}
public void findNext(boolean forward) {
- if (mNativeAwContents == 0) return;
- nativeFindNext(mNativeAwContents, forward);
+ if (!isDestroyed()) nativeFindNext(mNativeAwContents, forward);
}
public void clearMatches() {
- if (mNativeAwContents == 0) return;
- nativeClearMatches(mNativeAwContents);
+ if (!isDestroyed()) nativeClearMatches(mNativeAwContents);
}
/**
ThreadUtils.runOnUiThread(new Runnable() {
@Override
public void run() {
- if (mNativeAwContents == 0) return;
- nativeAddVisitedLinks(mNativeAwContents, value);
+ if (!isDestroyed()) nativeAddVisitedLinks(mNativeAwContents, value);
}
});
}
* ensuring the URL passed in is properly formatted (i.e. the scheme has been added if left
* off during user input).
*
- * @param pararms Parameters for this load.
+ * @param params Parameters for this load.
*/
public void loadUrl(LoadUrlParams params) {
+ if (isDestroyed()) return;
+
if (params.getLoadUrlType() == LoadUrlParams.LOAD_TYPE_DATA &&
- !params.isBaseUrlDataScheme()) {
+ !params.isBaseUrlDataScheme()) {
// This allows data URLs with a non-data base URL access to file:///android_asset/ and
// file:///android_res/ URLs. If AwSettings.getAllowFileAccess permits, it will also
// allow access to file:// URLs (subject to OS level permission checks).
// If we are reloading the same url, then set transition type as reload.
if (params.getUrl() != null &&
- params.getUrl().equals(mContentViewCore.getUrl()) &&
- params.getTransitionType() == PageTransitionTypes.PAGE_TRANSITION_LINK) {
+ params.getUrl().equals(mWebContents.getUrl()) &&
+ params.getTransitionType() == PageTransitionTypes.PAGE_TRANSITION_LINK) {
params.setTransitionType(PageTransitionTypes.PAGE_TRANSITION_RELOAD);
}
params.setTransitionType(
// every time the user agent in AwSettings is modified.
params.setOverrideUserAgent(LoadUrlParams.UA_OVERRIDE_TRUE);
- mContentViewCore.loadUrl(params);
- suppressInterceptionForThisNavigation();
+ // We don't pass extra headers to the content layer, as WebViewClassic
+ // was adding them in a very narrow set of conditions. See http://crbug.com/306873
+ // However, if the embedder is attempting to inject a Referer header for their
+ // loadUrl call, then we set that separately and remove it from the extra headers map/
+ final String referer = "referer";
+ Map<String, String> extraHeaders = params.getExtraHeaders();
+ if (extraHeaders != null) {
+ for (String header : extraHeaders.keySet()) {
+ if (referer.equals(header.toLowerCase(Locale.US))) {
+ params.setReferrer(new Referrer(extraHeaders.remove(header), 1));
+ params.setExtraHeaders(extraHeaders);
+ break;
+ }
+ }
+ }
+
+ nativeSetExtraHeadersForUrl(
+ mNativeAwContents, params.getUrl(), params.getExtraHttpRequestHeadersString());
+ params.setExtraHeaders(new HashMap<String, String>());
+
+ mNavigationController.loadUrl(params);
// The behavior of WebViewClassic uses the populateVisitedLinks callback in WebKit.
// Chromium does not use this use code path and the best emulation of this behavior to call
// request visited links once on the first URL load of the WebView.
if (!mHasRequestedVisitedHistoryFromClient) {
- mHasRequestedVisitedHistoryFromClient = true;
- requestVisitedHistoryFromClient();
+ mHasRequestedVisitedHistoryFromClient = true;
+ requestVisitedHistoryFromClient();
}
- }
- private void suppressInterceptionForThisNavigation() {
- if (mInterceptNavigationDelegate != null) {
- // getUrl returns a sanitized address in the same format that will be used for
- // callbacks, so it's safe to use string comparison as an equality check later on.
- mInterceptNavigationDelegate.onUrlLoadRequested(mContentViewCore.getUrl());
+ if (params.getLoadUrlType() == LoadUrlParams.LOAD_TYPE_DATA &&
+ params.getBaseUrl() != null) {
+ // Data loads with a base url will be resolved in Blink, and not cause an onPageStarted
+ // event to be sent. Sending the callback directly from here.
+ mContentsClient.getCallbackHelper().postOnPageStarted(params.getBaseUrl());
}
}
* @return The URL of the current page or null if it's empty.
*/
public String getUrl() {
- String url = mContentViewCore.getUrl();
+ if (isDestroyed()) return null;
+ String url = mWebContents.getUrl();
if (url == null || url.trim().isEmpty()) return null;
return url;
}
public void requestFocus() {
- if (mNativeAwContents == 0) return;
- if (!mContainerView.isInTouchMode() && mSettings.shouldFocusFirstNode()) {
- nativeFocusFirstNode(mNativeAwContents);
- }
+ mAwViewMethods.requestFocus();
}
public void setBackgroundColor(int color) {
mBaseBackgroundColor = color;
- if (mNativeAwContents != 0) nativeSetBackgroundColor(mNativeAwContents, color);
+ if (!isDestroyed()) nativeSetBackgroundColor(mNativeAwContents, color);
}
- private int getEffectiveBackgroundColor() {
+ /**
+ * @see android.view.View#setLayerType()
+ */
+ public void setLayerType(int layerType, Paint paint) {
+ mAwViewMethods.setLayerType(layerType, paint);
+ }
+
+ int getEffectiveBackgroundColor() {
// Do not ask the ContentViewCore for the background color, as it will always
// report white prior to initial navigation or post destruction, whereas we want
// to use the client supplied base value in those cases.
- if (mNativeAwContents == 0 || !mContentsClient.isCachedRendererBackgroundColorValid()) {
+ if (isDestroyed() || !mContentsClient.isCachedRendererBackgroundColorValid()) {
return mBaseBackgroundColor;
}
return mContentsClient.getCachedRendererBackgroundColor();
}
public boolean isMultiTouchZoomSupported() {
- return mSettings.supportsGestureZoom();
+ return mSettings.supportsMultiTouchZoom();
}
public View getZoomControlsForTest() {
* @see ContentViewCore#getContentSettings()
*/
public ContentSettings getContentSettings() {
- return mContentViewCore.getContentSettings();
+ return isDestroyed() ? null : mContentViewCore.getContentSettings();
}
/**
*/
public void setOverScrollMode(int mode) {
if (mode != View.OVER_SCROLL_NEVER) {
- mOverScrollGlow = new OverScrollGlow(mContainerView);
+ mOverScrollGlow = new OverScrollGlow(mContext, mContainerView);
} else {
mOverScrollGlow = null;
}
}
/**
- * @see WebView#requestChildRectangleOnScreen(View, Rect, boolean)
+ * @see android.webkit.WebView#requestChildRectangleOnScreen(View, Rect, boolean)
*/
public boolean requestChildRectangleOnScreen(View child, Rect rect, boolean immediate) {
return mScrollOffsetManager.requestChildRectangleOnScreen(
* @see android.webkit.WebView#stopLoading()
*/
public void stopLoading() {
- mContentViewCore.stopLoading();
+ if (!isDestroyed()) mWebContents.stop();
}
/**
* @see android.webkit.WebView#reload()
*/
public void reload() {
- mContentViewCore.reload();
+ if (!isDestroyed()) mNavigationController.reload(true);
}
/**
* @see android.webkit.WebView#canGoBack()
*/
public boolean canGoBack() {
- return mContentViewCore.canGoBack();
+ return isDestroyed() ? false : mNavigationController.canGoBack();
}
/**
* @see android.webkit.WebView#goBack()
*/
public void goBack() {
- mContentViewCore.goBack();
-
- suppressInterceptionForThisNavigation();
+ if (!isDestroyed()) mNavigationController.goBack();
}
/**
* @see android.webkit.WebView#canGoForward()
*/
public boolean canGoForward() {
- return mContentViewCore.canGoForward();
+ return isDestroyed() ? false : mNavigationController.canGoForward();
}
/**
* @see android.webkit.WebView#goForward()
*/
public void goForward() {
- mContentViewCore.goForward();
-
- suppressInterceptionForThisNavigation();
+ if (!isDestroyed()) mNavigationController.goForward();
}
/**
* @see android.webkit.WebView#canGoBackOrForward(int)
*/
public boolean canGoBackOrForward(int steps) {
- return mContentViewCore.canGoToOffset(steps);
+ return isDestroyed() ? false : mNavigationController.canGoToOffset(steps);
}
/**
* @see android.webkit.WebView#goBackOrForward(int)
*/
public void goBackOrForward(int steps) {
- mContentViewCore.goToOffset(steps);
-
- suppressInterceptionForThisNavigation();
+ if (!isDestroyed()) mNavigationController.goToOffset(steps);
}
/**
* @see android.webkit.WebView#pauseTimers()
*/
public void pauseTimers() {
- ContentViewStatics.setWebKitSharedTimersSuspended(true);
+ if (!isDestroyed()) ContentViewStatics.setWebKitSharedTimersSuspended(true);
}
/**
* @see android.webkit.WebView#resumeTimers()
*/
public void resumeTimers() {
- ContentViewStatics.setWebKitSharedTimersSuspended(false);
+ if (!isDestroyed()) ContentViewStatics.setWebKitSharedTimersSuspended(false);
}
/**
* @see android.webkit.WebView#onPause()
*/
public void onPause() {
- if (mIsPaused || mNativeAwContents == 0) return;
+ if (mIsPaused || isDestroyed()) return;
mIsPaused = true;
nativeSetIsPaused(mNativeAwContents, mIsPaused);
+ mContentViewCore.onHide();
}
/**
* @see android.webkit.WebView#onResume()
*/
public void onResume() {
- if (!mIsPaused || mNativeAwContents == 0) return;
+ if (!mIsPaused || isDestroyed()) return;
mIsPaused = false;
nativeSetIsPaused(mNativeAwContents, mIsPaused);
+ mContentViewCore.onShow();
}
/**
* @see android.webkit.WebView#onCreateInputConnection(EditorInfo)
*/
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
- return mContentViewCore.onCreateInputConnection(outAttrs);
+ return mAwViewMethods.onCreateInputConnection(outAttrs);
}
/**
* @see android.webkit.WebView#onKeyUp(int, KeyEvent)
*/
public boolean onKeyUp(int keyCode, KeyEvent event) {
- return mContentViewCore.onKeyUp(keyCode, event);
- }
-
- private boolean isDpadEvent(KeyEvent event) {
- if (event.getAction() == KeyEvent.ACTION_DOWN) {
- switch (event.getKeyCode()) {
- case KeyEvent.KEYCODE_DPAD_CENTER:
- case KeyEvent.KEYCODE_DPAD_DOWN:
- case KeyEvent.KEYCODE_DPAD_UP:
- case KeyEvent.KEYCODE_DPAD_LEFT:
- case KeyEvent.KEYCODE_DPAD_RIGHT:
- return true;
- }
- }
- return false;
+ return mAwViewMethods.onKeyUp(keyCode, event);
}
/**
* @see android.webkit.WebView#dispatchKeyEvent(KeyEvent)
*/
public boolean dispatchKeyEvent(KeyEvent event) {
- if (isDpadEvent(event)) {
- mSettings.setSpatialNavigationEnabled(true);
- }
- return mContentViewCore.dispatchKeyEvent(event);
+ return mAwViewMethods.dispatchKeyEvent(event);
}
/**
* @param includeDiskFiles if false, only the RAM cache is cleared
*/
public void clearCache(boolean includeDiskFiles) {
- if (mNativeAwContents == 0) return;
- nativeClearCache(mNativeAwContents, includeDiskFiles);
+ if (!isDestroyed()) nativeClearCache(mNativeAwContents, includeDiskFiles);
}
public void documentHasImages(Message message) {
- if (mNativeAwContents == 0) return;
- nativeDocumentHasImages(mNativeAwContents, message);
+ if (!isDestroyed()) nativeDocumentHasImages(mNativeAwContents, message);
}
public void saveWebArchive(
}
public String getOriginalUrl() {
- NavigationHistory history = mContentViewCore.getNavigationHistory();
+ if (isDestroyed()) return null;
+ NavigationHistory history = mNavigationController.getNavigationHistory();
int currentIndex = history.getCurrentEntryIndex();
if (currentIndex >= 0 && currentIndex < history.getEntryCount()) {
return history.getEntryAtIndex(currentIndex).getOriginalUrl();
* @see ContentViewCore#getNavigationHistory()
*/
public NavigationHistory getNavigationHistory() {
- return mContentViewCore.getNavigationHistory();
+ return isDestroyed() ? null : mNavigationController.getNavigationHistory();
}
/**
* @see android.webkit.WebView#getTitle()
*/
public String getTitle() {
- return mContentViewCore.getTitle();
+ return isDestroyed() ? null : mWebContents.getTitle();
}
/**
* @see android.webkit.WebView#clearHistory()
*/
public void clearHistory() {
- mContentViewCore.clearHistory();
+ if (!isDestroyed()) mNavigationController.clearHistory();
}
public String[] getHttpAuthUsernamePassword(String host, String realm) {
- return mBrowserContext.getHttpAuthDatabase(mContentViewCore.getContext())
+ return mBrowserContext.getHttpAuthDatabase(mContext)
.getHttpAuthUsernamePassword(host, realm);
}
public void setHttpAuthUsernamePassword(String host, String realm, String username,
String password) {
- mBrowserContext.getHttpAuthDatabase(mContentViewCore.getContext())
+ mBrowserContext.getHttpAuthDatabase(mContext)
.setHttpAuthUsernamePassword(host, realm, username, password);
}
* @see android.webkit.WebView#getCertificate()
*/
public SslCertificate getCertificate() {
- if (mNativeAwContents == 0) return null;
- return SslUtil.getCertificateFromDerBytes(nativeGetCertificate(mNativeAwContents));
+ return isDestroyed() ? null
+ : SslUtil.getCertificateFromDerBytes(nativeGetCertificate(mNativeAwContents));
}
/**
* @see android.webkit.WebView#clearSslPreferences()
*/
public void clearSslPreferences() {
- mContentViewCore.clearSslPreferences();
+ if (!isDestroyed()) mNavigationController.clearSslPreferences();
}
+ // TODO(sgurun) remove after this rolls in. To keep internal tree happy.
+ public void clearClientCertPreferences() { }
+
/**
* Method to return all hit test values relevant to public WebView API.
* Note that this expose more data than needed for WebView.getHitTestResult.
* garbage allocation on repeated calls.
*/
public HitTestData getLastHitTestResult() {
- if (mNativeAwContents == 0) return null;
+ if (isDestroyed()) return null;
nativeUpdateLastHitTestData(mNativeAwContents);
return mPossiblyStaleHitTestData;
}
* @see android.webkit.WebView#requestFocusNodeHref()
*/
public void requestFocusNodeHref(Message msg) {
- if (msg == null || mNativeAwContents == 0) return;
+ if (msg == null || isDestroyed()) return;
nativeUpdateLastHitTestData(mNativeAwContents);
Bundle data = msg.getData();
// In order to maintain compatibility with the old WebView's implementation,
// the absolute (full) url is passed in the |url| field, not only the href attribute.
// Note: HitTestData could be cleaned up at this point. See http://crbug.com/290992.
- data.putString("url", mPossiblyStaleHitTestData.hitTestResultExtraData);
+ data.putString("url", mPossiblyStaleHitTestData.href);
data.putString("title", mPossiblyStaleHitTestData.anchorText);
data.putString("src", mPossiblyStaleHitTestData.imgSrc);
msg.setData(data);
* @see android.webkit.WebView#requestImageRef()
*/
public void requestImageRef(Message msg) {
- if (msg == null || mNativeAwContents == 0) return;
+ if (msg == null || isDestroyed()) return;
nativeUpdateLastHitTestData(mNativeAwContents);
Bundle data = msg.getData();
msg.sendToTarget();
}
+ @VisibleForTesting
+ public float getPageScaleFactor() {
+ return mPageScaleFactor;
+ }
+
/**
* @see android.webkit.WebView#getScale()
*
* the screen density factor. See CTS WebViewTest.testSetInitialScale.
*/
public float getScale() {
- return (float)(mPageScaleFactor * mDIPScale);
+ return (float) (mPageScaleFactor * mDIPScale);
}
/**
// This method uses the term 'zoom' for legacy reasons, but relates
// to what chrome calls the 'page scale factor'.
public boolean canZoomIn() {
- final float zoomInExtent = mContentViewCore.getRenderCoordinates().getMaxPageScaleFactor()
- - mPageScaleFactor;
+ final float zoomInExtent = mMaxPageScaleFactor - mPageScaleFactor;
return zoomInExtent > ZOOM_CONTROLS_EPSILON;
}
// This method uses the term 'zoom' for legacy reasons, but relates
// to what chrome calls the 'page scale factor'.
public boolean canZoomOut() {
- final float zoomOutExtent = mPageScaleFactor
- - mContentViewCore.getRenderCoordinates().getMinPageScaleFactor();
+ final float zoomOutExtent = mPageScaleFactor - mMinPageScaleFactor;
return zoomOutExtent > ZOOM_CONTROLS_EPSILON;
}
if (!canZoomIn()) {
return false;
}
- return mContentViewCore.pinchByDelta(1.25f);
+ return zoomBy(1.25f);
}
/**
if (!canZoomOut()) {
return false;
}
- return mContentViewCore.pinchByDelta(0.8f);
+ return zoomBy(0.8f);
+ }
+
+ /**
+ * @see android.webkit.WebView#zoomBy()
+ */
+ // This method uses the term 'zoom' for legacy reasons, but relates
+ // to what chrome calls the 'page scale factor'.
+ public boolean zoomBy(float delta) {
+ if (isDestroyed()) return false;
+ if (delta < 0.01f || delta > 100.0f) {
+ throw new IllegalStateException("zoom delta value outside [0.01, 100] range.");
+ }
+ return mContentViewCore.pinchByDelta(delta);
}
/**
* @see android.webkit.WebView#invokeZoomPicker()
*/
public void invokeZoomPicker() {
- mContentViewCore.invokeZoomPicker();
+ if (!isDestroyed()) mContentViewCore.invokeZoomPicker();
}
/**
- * @see ContentViewCore.evaluateJavaScript(String, ContentViewCore.JavaScriptCallback)
+ * @see android.webkit.WebView#preauthorizePermission(Uri, long)
+ */
+ public void preauthorizePermission(Uri origin, long resources) {
+ if (isDestroyed()) return;
+ nativePreauthorizePermission(mNativeAwContents, origin.toString(), resources);
+ }
+
+ /**
+ * @see ContentViewCore.evaluateJavaScript(String, JavaScriptCallback)
*/
public void evaluateJavaScript(String script, final ValueCallback<String> callback) {
- ContentViewCore.JavaScriptCallback jsCallback = null;
+ if (isDestroyed()) return;
+ JavaScriptCallback jsCallback = null;
if (callback != null) {
- jsCallback = new ContentViewCore.JavaScriptCallback() {
+ jsCallback = new JavaScriptCallback() {
@Override
public void handleJavaScriptResult(String jsonResult) {
callback.onReceiveValue(jsonResult);
};
}
- mContentViewCore.evaluateJavaScript(script, jsCallback);
+ mWebContents.evaluateJavaScript(script, jsCallback);
}
- /**
- * @see ContentViewCore.evaluateJavaScriptEvenIfNotYetNavigated(String)
- */
+ // TODO(boliu): Remove this once Android side no longer calls this.
public void evaluateJavaScriptEvenIfNotYetNavigated(String script) {
- mContentViewCore.evaluateJavaScriptEvenIfNotYetNavigated(script);
+ if (!isDestroyed()) mWebContents.evaluateJavaScript(script, null);
}
//--------------------------------------------------------------------------------------------
* @see android.webkit.View#onTouchEvent()
*/
public boolean onTouchEvent(MotionEvent event) {
- if (mNativeAwContents == 0) return false;
-
- if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
- mSettings.setSpatialNavigationEnabled(false);
- }
-
- mScrollOffsetManager.setProcessingTouchEvent(true);
- boolean rv = mContentViewCore.onTouchEvent(event);
- mScrollOffsetManager.setProcessingTouchEvent(false);
-
- if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
- int actionIndex = event.getActionIndex();
-
- // Note this will trigger IPC back to browser even if nothing is hit.
- nativeRequestNewHitTestDataAt(mNativeAwContents,
- (int)Math.round(event.getX(actionIndex) / mDIPScale),
- (int)Math.round(event.getY(actionIndex) / mDIPScale));
- }
-
- if (mOverScrollGlow != null && event.getActionMasked() == MotionEvent.ACTION_UP) {
- mOverScrollGlow.releaseAll();
- }
-
- return rv;
+ return mAwViewMethods.onTouchEvent(event);
}
/**
* @see android.view.View#onHoverEvent()
*/
public boolean onHoverEvent(MotionEvent event) {
- return mContentViewCore.onHoverEvent(event);
+ return mAwViewMethods.onHoverEvent(event);
}
/**
* @see android.view.View#onGenericMotionEvent()
*/
public boolean onGenericMotionEvent(MotionEvent event) {
- return mContentViewCore.onGenericMotionEvent(event);
+ return isDestroyed() ? false : mContentViewCore.onGenericMotionEvent(event);
}
/**
* @see android.view.View#onConfigurationChanged()
*/
public void onConfigurationChanged(Configuration newConfig) {
- mContentViewCore.onConfigurationChanged(newConfig);
+ mAwViewMethods.onConfigurationChanged(newConfig);
}
/**
* @see android.view.View#onAttachedToWindow()
- *
- * Note that this is also called from receivePopupContents.
*/
public void onAttachedToWindow() {
- if (mNativeAwContents == 0) return;
- mIsAttachedToWindow = true;
-
- mContentViewCore.onAttachedToWindow();
- nativeOnAttachedToWindow(mNativeAwContents, mContainerView.getWidth(),
- mContainerView.getHeight());
-
- if (mComponentCallbacks != null) return;
- mComponentCallbacks = new AwComponentCallbacks();
- mContainerView.getContext().registerComponentCallbacks(mComponentCallbacks);
+ mTemporarilyDetached = false;
+ mAwViewMethods.onAttachedToWindow();
}
/**
* @see android.view.View#onDetachedFromWindow()
*/
+ @SuppressLint("MissingSuperCall")
public void onDetachedFromWindow() {
- mIsAttachedToWindow = false;
- hideAutofillPopup();
- if (mNativeAwContents != 0) {
- nativeOnDetachedFromWindow(mNativeAwContents);
- }
-
- mContentViewCore.onDetachedFromWindow();
-
- if (mComponentCallbacks != null) {
- mContainerView.getContext().unregisterComponentCallbacks(mComponentCallbacks);
- mComponentCallbacks = null;
- }
-
- mScrollAccessibilityHelper.removePostedCallbacks();
-
- if (mPendingDetachCleanupReferences != null) {
- for (int i = 0; i < mPendingDetachCleanupReferences.size(); ++i) {
- mPendingDetachCleanupReferences.get(i).cleanupNow();
- }
- mPendingDetachCleanupReferences = null;
- }
+ mAwViewMethods.onDetachedFromWindow();
}
/**
* @see android.view.View#onWindowFocusChanged()
*/
public void onWindowFocusChanged(boolean hasWindowFocus) {
- mWindowFocused = hasWindowFocus;
- mContentViewCore.onWindowFocusChanged(hasWindowFocus);
+ mAwViewMethods.onWindowFocusChanged(hasWindowFocus);
}
/**
* @see android.view.View#onFocusChanged()
*/
public void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
- mContainerViewFocused = focused;
- mContentViewCore.onFocusChanged(focused);
+ if (!mTemporarilyDetached) {
+ mAwViewMethods.onFocusChanged(focused, direction, previouslyFocusedRect);
+ }
+ }
+
+ /**
+ * @see android.view.View#onStartTemporaryDetach()
+ */
+ public void onStartTemporaryDetach() {
+ mTemporarilyDetached = true;
+ }
+
+ /**
+ * @see android.view.View#onFinishTemporaryDetach()
+ */
+ public void onFinishTemporaryDetach() {
+ mTemporarilyDetached = false;
}
/**
* @see android.view.View#onSizeChanged()
*/
public void onSizeChanged(int w, int h, int ow, int oh) {
- if (mNativeAwContents == 0) return;
- mScrollOffsetManager.setContainerViewSize(w, h);
- // The AwLayoutSizer needs to go first so that if we're in fixedLayoutSize mode the update
- // to enter fixedLayoutSize mode is sent before the first resize update.
- mLayoutSizer.onSizeChanged(w, h, ow, oh);
- mContentViewCore.onPhysicalBackingSizeChanged(w, h);
- mContentViewCore.onSizeChanged(w, h, ow, oh);
- nativeOnSizeChanged(mNativeAwContents, w, h, ow, oh);
+ mAwViewMethods.onSizeChanged(w, h, ow, oh);
}
/**
* @see android.view.View#onVisibilityChanged()
*/
public void onVisibilityChanged(View changedView, int visibility) {
- boolean viewVisible = mContainerView.getVisibility() == View.VISIBLE;
- if (mIsViewVisible == viewVisible) return;
- setViewVisibilityInternal(viewVisible);
+ mAwViewMethods.onVisibilityChanged(changedView, visibility);
}
/**
* @see android.view.View#onWindowVisibilityChanged()
*/
public void onWindowVisibilityChanged(int visibility) {
- boolean windowVisible = visibility == View.VISIBLE;
- if (mIsWindowVisible == windowVisible) return;
- setWindowVisibilityInternal(windowVisible);
+ mAwViewMethods.onWindowVisibilityChanged(visibility);
}
private void setViewVisibilityInternal(boolean visible) {
mIsViewVisible = visible;
- if (mNativeAwContents == 0) return;
- nativeSetViewVisibility(mNativeAwContents, mIsViewVisible);
+ if (!isDestroyed()) nativeSetViewVisibility(mNativeAwContents, mIsViewVisible);
}
private void setWindowVisibilityInternal(boolean visible) {
mIsWindowVisible = visible;
- if (mNativeAwContents == 0) return;
- nativeSetWindowVisibility(mNativeAwContents, mIsWindowVisible);
+ if (!isDestroyed()) nativeSetWindowVisibility(mNativeAwContents, mIsWindowVisible);
}
/**
* @return False if saving state failed.
*/
public boolean saveState(Bundle outState) {
- if (mNativeAwContents == 0 || outState == null) return false;
+ if (isDestroyed() || outState == null) return false;
byte[] state = nativeGetOpaqueState(mNativeAwContents);
if (state == null) return false;
* @return False if restoring state failed.
*/
public boolean restoreState(Bundle inState) {
- if (mNativeAwContents == 0 || inState == null) return false;
+ if (isDestroyed() || inState == null) return false;
byte[] state = inState.getByteArray(SAVE_RESTORE_STATE_KEY);
if (state == null) return false;
// but is optimized out in the restoreState case because the title is
// already restored. See WebContentsImpl::UpdateTitleForEntry. So we
// call the callback explicitly here.
- if (result) mContentsClient.onReceivedTitle(mContentViewCore.getTitle());
+ if (result) mContentsClient.onReceivedTitle(mWebContents.getTitle());
return result;
}
*/
public void addPossiblyUnsafeJavascriptInterface(Object object, String name,
Class<? extends Annotation> requiredAnnotation) {
+ if (isDestroyed()) return;
mContentViewCore.addPossiblyUnsafeJavascriptInterface(object, name, requiredAnnotation);
}
* @see android.webkit.WebView#removeJavascriptInterface(String)
*/
public void removeJavascriptInterface(String interfaceName) {
- mContentViewCore.removeJavascriptInterface(interfaceName);
+ if (!isDestroyed()) mContentViewCore.removeJavascriptInterface(interfaceName);
}
/**
* @return The AccessibilityNodeProvider, if available, or null otherwise.
*/
public AccessibilityNodeProvider getAccessibilityNodeProvider() {
- return mContentViewCore.getAccessibilityNodeProvider();
+ return isDestroyed() ? null : mContentViewCore.getAccessibilityNodeProvider();
}
/**
* @see android.webkit.WebView#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)
*/
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
- mContentViewCore.onInitializeAccessibilityNodeInfo(info);
+ if (!isDestroyed()) mContentViewCore.onInitializeAccessibilityNodeInfo(info);
}
/**
* @see android.webkit.WebView#onInitializeAccessibilityEvent(AccessibilityEvent)
*/
public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
- mContentViewCore.onInitializeAccessibilityEvent(event);
+ if (!isDestroyed()) mContentViewCore.onInitializeAccessibilityEvent(event);
}
public boolean supportsAccessibilityAction(int action) {
- return mContentViewCore.supportsAccessibilityAction(action);
+ return isDestroyed() ? false : mContentViewCore.supportsAccessibilityAction(action);
}
/**
* @see android.webkit.WebView#performAccessibilityAction(int, Bundle)
*/
public boolean performAccessibilityAction(int action, Bundle arguments) {
- return mContentViewCore.performAccessibilityAction(action, arguments);
+ return isDestroyed() ? false
+ : mContentViewCore.performAccessibilityAction(action, arguments);
}
/**
* @see android.webkit.WebView#clearFormData()
*/
public void hideAutofillPopup() {
- if (mAwAutofillManagerDelegate != null)
- mAwAutofillManagerDelegate.hideAutofillPopup();
+ if (mAwAutofillClient != null) {
+ mAwAutofillClient.hideAutofillPopup();
+ }
}
public void setNetworkAvailable(boolean networkUp) {
- if (mNativeAwContents == 0) return;
- nativeSetJsOnlineProperty(mNativeAwContents, networkUp);
+ if (!isDestroyed()) nativeSetJsOnlineProperty(mNativeAwContents, networkUp);
}
//--------------------------------------------------------------------------------------------
mBrowserContext.getGeolocationPermissions().deny(origin);
}
}
- if (mNativeAwContents == 0) return;
+ if (isDestroyed()) return;
nativeInvokeGeolocationCallback(mNativeAwContents, allow, origin);
}
});
@CalledByNative
private void onGeolocationPermissionsShowPrompt(String origin) {
- if (mNativeAwContents == 0) return;
+ if (isDestroyed()) return;
AwGeolocationPermissions permissions = mBrowserContext.getGeolocationPermissions();
// Reject if geoloaction is disabled, or the origin has a retained deny
if (!mSettings.getGeolocationEnabled()) {
}
@CalledByNative
+ private void onPermissionRequest(AwPermissionRequest awPermissionRequest) {
+ mContentsClient.onPermissionRequest(awPermissionRequest);
+ }
+
+ @CalledByNative
+ private void onPermissionRequestCanceled(AwPermissionRequest awPermissionRequest) {
+ mContentsClient.onPermissionRequestCanceled(awPermissionRequest);
+ }
+
+ @CalledByNative
public void onFindResultReceived(int activeMatchOrdinal, int numberOfMatches,
boolean isDoneCounting) {
mContentsClient.onFindResultReceived(activeMatchOrdinal, numberOfMatches, isDoneCounting);
@CalledByNative
public void onNewPicture() {
- // Clear up any results from a previous clearView call
- if (mClearViewActive) {
- mClearViewActive = false;
- mContainerView.invalidate();
- syncOnNewPictureStateToNative();
- }
-
// Don't call capturePicture() here but instead defer it until the posted task runs within
// the callback helper, to avoid doubling back into the renderer compositor in the middle
// of the notification it is sending up to here.
}
@CalledByNative
- private boolean requestDrawGL(Canvas canvas) {
- return mInternalAccessAdapter.requestDrawGL(canvas);
+ private boolean requestDrawGL(Canvas canvas, boolean waitForCompletion) {
+ return mNativeGLDelegate.requestDrawGL(canvas, waitForCompletion, mContainerView);
}
private static final boolean SUPPORTS_ON_ANIMATION =
@CalledByNative
private void postInvalidateOnAnimation() {
- if (SUPPORTS_ON_ANIMATION) {
+ if (SUPPORTS_ON_ANIMATION && !mWindowAndroid.isInsideVSync()) {
mContainerView.postInvalidateOnAnimation();
} else {
- mContainerView.postInvalidate();
+ mContainerView.invalidate();
}
}
+ // Call postInvalidateOnAnimation for invalidations. This is only used to synchronize
+ // draw functor destruction.
+ @CalledByNative
+ private void invalidateOnFunctorDestroy() {
+ mContainerView.invalidate();
+ }
+
@CalledByNative
private int[] getLocationOnScreen() {
int[] result = new int[2];
}
@CalledByNative
- private void setMaxContainerViewScrollOffset(int maxX, int maxY) {
- mScrollOffsetManager.setMaxScrollOffset(maxX, maxY);
- }
-
- @CalledByNative
private void scrollContainerViewTo(int x, int y) {
mScrollOffsetManager.scrollContainerViewTo(x, y);
}
}
@CalledByNative
- private void setContentsSize(int widthDip, int heightDip) {
- mContentWidthDip = widthDip;
- mContentHeightDip = heightDip;
- }
-
- @CalledByNative
- private void setPageScaleFactor(float pageScaleFactor) {
- if (mPageScaleFactor == pageScaleFactor)
- return;
- float oldPageScaleFactor = mPageScaleFactor;
- mPageScaleFactor = pageScaleFactor;
- mContentsClient.getCallbackHelper().postOnScaleChangedScaled(
- (float)(oldPageScaleFactor * mDIPScale), (float)(mPageScaleFactor * mDIPScale));
+ private void updateScrollState(int maxContainerViewScrollOffsetX,
+ int maxContainerViewScrollOffsetY, int contentWidthDip, int contentHeightDip,
+ float pageScaleFactor, float minPageScaleFactor, float maxPageScaleFactor) {
+ mContentWidthDip = contentWidthDip;
+ mContentHeightDip = contentHeightDip;
+ mScrollOffsetManager.setMaxScrollOffset(maxContainerViewScrollOffsetX,
+ maxContainerViewScrollOffsetY);
+ setPageScaleFactorAndLimits(pageScaleFactor, minPageScaleFactor, maxPageScaleFactor);
}
@CalledByNative
- private void setAwAutofillManagerDelegate(AwAutofillManagerDelegate delegate) {
- mAwAutofillManagerDelegate = delegate;
- delegate.init(mContentViewCore);
+ private void setAwAutofillClient(AwAutofillClient client) {
+ mAwAutofillClient = client;
+ client.init(mContentViewCore);
}
@CalledByNative
// Helper methods
// -------------------------------------------------------------------------------------------
+ private void setPageScaleFactorAndLimits(
+ float pageScaleFactor, float minPageScaleFactor, float maxPageScaleFactor) {
+ if (mPageScaleFactor == pageScaleFactor &&
+ mMinPageScaleFactor == minPageScaleFactor &&
+ mMaxPageScaleFactor == maxPageScaleFactor) {
+ return;
+ }
+ mMinPageScaleFactor = minPageScaleFactor;
+ mMaxPageScaleFactor = maxPageScaleFactor;
+ if (mPageScaleFactor != pageScaleFactor) {
+ float oldPageScaleFactor = mPageScaleFactor;
+ mPageScaleFactor = pageScaleFactor;
+ mContentsClient.getCallbackHelper().postOnScaleChangedScaled(
+ (float) (oldPageScaleFactor * mDIPScale),
+ (float) (mPageScaleFactor * mDIPScale));
+ }
+ }
+
private void saveWebArchiveInternal(String path, final ValueCallback<String> callback) {
- if (path == null || mNativeAwContents == 0) {
+ if (path == null || isDestroyed()) {
ThreadUtils.runOnUiThread(new Runnable() {
@Override
public void run() {
return null;
}
+ public void extractSmartClipData(int x, int y, int width, int height) {
+ if (!isDestroyed()) mContentViewCore.extractSmartClipData(x, y, width, height);
+ }
+
+ public void setSmartClipDataListener(ContentViewCore.SmartClipDataListener listener) {
+ if (!isDestroyed()) mContentViewCore.setSmartClipDataListener(listener);
+ }
+
+ // --------------------------------------------------------------------------------------------
+ // This is the AwViewMethods implementation that does real work. The AwViewMethodsImpl is
+ // hooked up to the WebView in embedded mode and to the FullScreenView in fullscreen mode,
+ // but not to both at the same time.
+ private class AwViewMethodsImpl implements AwViewMethods {
+ private int mLayerType = View.LAYER_TYPE_NONE;
+ private ComponentCallbacks2 mComponentCallbacks;
+
+ // Only valid within software onDraw().
+ private final Rect mClipBoundsTemporary = new Rect();
+
+ @Override
+ public void onDraw(Canvas canvas) {
+ if (isDestroyed()) {
+ canvas.drawColor(getEffectiveBackgroundColor());
+ return;
+ }
+
+ // For hardware draws, the clip at onDraw time could be different
+ // from the clip during DrawGL.
+ if (!canvas.isHardwareAccelerated() && !canvas.getClipBounds(mClipBoundsTemporary)) {
+ return;
+ }
+
+ mScrollOffsetManager.syncScrollOffsetFromOnDraw();
+ Rect globalVisibleRect = getGlobalVisibleRect();
+ if (!nativeOnDraw(mNativeAwContents, canvas, canvas.isHardwareAccelerated(),
+ mContainerView.getScrollX(), mContainerView.getScrollY(),
+ globalVisibleRect.left, globalVisibleRect.top,
+ globalVisibleRect.right, globalVisibleRect.bottom)) {
+ // Can happen during initialization when compositor is not set
+ // up. Or when clearView
+ // is in effect. Just draw background color instead.
+ canvas.drawColor(getEffectiveBackgroundColor());
+ }
+
+ if (mOverScrollGlow != null && mOverScrollGlow.drawEdgeGlows(canvas,
+ mScrollOffsetManager.computeMaximumHorizontalScrollOffset(),
+ mScrollOffsetManager.computeMaximumVerticalScrollOffset())) {
+ mContainerView.invalidate();
+ }
+ }
+
+ @Override
+ public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ mLayoutSizer.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+
+ @Override
+ public void requestFocus() {
+ if (isDestroyed()) return;
+ if (!mContainerView.isInTouchMode() && mSettings.shouldFocusFirstNode()) {
+ nativeFocusFirstNode(mNativeAwContents);
+ }
+ }
+
+ @Override
+ public void setLayerType(int layerType, Paint paint) {
+ mLayerType = layerType;
+ updateHardwareAcceleratedFeaturesToggle();
+ }
+
+ private void updateHardwareAcceleratedFeaturesToggle() {
+ mSettings.setEnableSupportedHardwareAcceleratedFeatures(
+ mIsAttachedToWindow && mContainerView.isHardwareAccelerated() &&
+ (mLayerType == View.LAYER_TYPE_NONE
+ || mLayerType == View.LAYER_TYPE_HARDWARE));
+ }
+
+ @Override
+ public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
+ return isDestroyed() ? null : mContentViewCore.onCreateInputConnection(outAttrs);
+ }
+
+ @Override
+ public boolean onKeyUp(int keyCode, KeyEvent event) {
+ return isDestroyed() ? false : mContentViewCore.onKeyUp(keyCode, event);
+ }
+
+ @Override
+ public boolean dispatchKeyEvent(KeyEvent event) {
+ if (isDestroyed()) return false;
+ if (isDpadEvent(event)) {
+ mSettings.setSpatialNavigationEnabled(true);
+ }
+ return mContentViewCore.dispatchKeyEvent(event);
+ }
+
+ private boolean isDpadEvent(KeyEvent event) {
+ if (event.getAction() == KeyEvent.ACTION_DOWN) {
+ switch (event.getKeyCode()) {
+ case KeyEvent.KEYCODE_DPAD_CENTER:
+ case KeyEvent.KEYCODE_DPAD_DOWN:
+ case KeyEvent.KEYCODE_DPAD_UP:
+ case KeyEvent.KEYCODE_DPAD_LEFT:
+ case KeyEvent.KEYCODE_DPAD_RIGHT:
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ if (isDestroyed()) return false;
+ if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
+ mSettings.setSpatialNavigationEnabled(false);
+ }
+
+ mScrollOffsetManager.setProcessingTouchEvent(true);
+ boolean rv = mContentViewCore.onTouchEvent(event);
+ mScrollOffsetManager.setProcessingTouchEvent(false);
+
+ if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
+ int actionIndex = event.getActionIndex();
+
+ // Note this will trigger IPC back to browser even if nothing is
+ // hit.
+ nativeRequestNewHitTestDataAt(mNativeAwContents,
+ (int) Math.round(event.getX(actionIndex) / mDIPScale),
+ (int) Math.round(event.getY(actionIndex) / mDIPScale));
+ }
+
+ if (mOverScrollGlow != null) {
+ if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
+ mOverScrollGlow.setShouldPull(true);
+ } else if (event.getActionMasked() == MotionEvent.ACTION_UP ||
+ event.getActionMasked() == MotionEvent.ACTION_CANCEL) {
+ mOverScrollGlow.setShouldPull(false);
+ mOverScrollGlow.releaseAll();
+ }
+ }
+
+ return rv;
+ }
+
+ @Override
+ public boolean onHoverEvent(MotionEvent event) {
+ return isDestroyed() ? false : mContentViewCore.onHoverEvent(event);
+ }
+
+ @Override
+ public boolean onGenericMotionEvent(MotionEvent event) {
+ return isDestroyed() ? false : mContentViewCore.onGenericMotionEvent(event);
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ if (!isDestroyed()) mContentViewCore.onConfigurationChanged(newConfig);
+ }
+
+ @Override
+ public void onAttachedToWindow() {
+ if (isDestroyed()) return;
+ if (mIsAttachedToWindow) {
+ Log.w(TAG, "onAttachedToWindow called when already attached. Ignoring");
+ return;
+ }
+ mIsAttachedToWindow = true;
+
+ mContentViewCore.onAttachedToWindow();
+ nativeOnAttachedToWindow(mNativeAwContents, mContainerView.getWidth(),
+ mContainerView.getHeight());
+ updateHardwareAcceleratedFeaturesToggle();
+
+ if (mComponentCallbacks != null) return;
+ mComponentCallbacks = new AwComponentCallbacks();
+ mContext.registerComponentCallbacks(mComponentCallbacks);
+ }
+
+ @Override
+ public void onDetachedFromWindow() {
+ if (isDestroyed()) return;
+ if (!mIsAttachedToWindow) {
+ Log.w(TAG, "onDetachedFromWindow called when already detached. Ignoring");
+ return;
+ }
+ mIsAttachedToWindow = false;
+ hideAutofillPopup();
+ nativeOnDetachedFromWindow(mNativeAwContents);
+
+ mContentViewCore.onDetachedFromWindow();
+ updateHardwareAcceleratedFeaturesToggle();
+
+ if (mComponentCallbacks != null) {
+ mContext.unregisterComponentCallbacks(mComponentCallbacks);
+ mComponentCallbacks = null;
+ }
+
+ mScrollAccessibilityHelper.removePostedCallbacks();
+ mNativeGLDelegate.detachGLFunctor();
+ }
+
+ @Override
+ public void onWindowFocusChanged(boolean hasWindowFocus) {
+ if (isDestroyed()) return;
+ mWindowFocused = hasWindowFocus;
+ mContentViewCore.onWindowFocusChanged(hasWindowFocus);
+ }
+
+ @Override
+ public void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
+ if (isDestroyed()) return;
+ mContainerViewFocused = focused;
+ mContentViewCore.onFocusChanged(focused);
+ }
+
+ @Override
+ public void onSizeChanged(int w, int h, int ow, int oh) {
+ if (isDestroyed()) return;
+ mScrollOffsetManager.setContainerViewSize(w, h);
+ // The AwLayoutSizer needs to go first so that if we're in
+ // fixedLayoutSize mode the update
+ // to enter fixedLayoutSize mode is sent before the first resize
+ // update.
+ mLayoutSizer.onSizeChanged(w, h, ow, oh);
+ mContentViewCore.onPhysicalBackingSizeChanged(w, h);
+ mContentViewCore.onSizeChanged(w, h, ow, oh);
+ nativeOnSizeChanged(mNativeAwContents, w, h, ow, oh);
+ }
+
+ @Override
+ public void onVisibilityChanged(View changedView, int visibility) {
+ boolean viewVisible = mContainerView.getVisibility() == View.VISIBLE;
+ if (mIsViewVisible == viewVisible) return;
+ setViewVisibilityInternal(viewVisible);
+ }
+
+ @Override
+ public void onWindowVisibilityChanged(int visibility) {
+ boolean windowVisible = visibility == View.VISIBLE;
+ if (mIsWindowVisible == windowVisible) return;
+ setWindowVisibilityInternal(windowVisible);
+ }
+ }
+
+ // Return true if the GeolocationPermissionAPI should be used.
+ @CalledByNative
+ private boolean useLegacyGeolocationPermissionAPI() {
+ // Always return true since we are not ready to swap the geolocation yet.
+ // TODO: If we decide not to migrate the geolocation, there are some unreachable
+ // code need to remove. http://crbug.com/396184.
+ return true;
+ }
+
//--------------------------------------------------------------------------------------------
// Native methods
//--------------------------------------------------------------------------------------------
- private static native int nativeInit(AwBrowserContext browserContext);
- private static native void nativeDestroy(int nativeAwContents);
- private static native void nativeSetAwDrawSWFunctionTable(int functionTablePointer);
- private static native void nativeSetAwDrawGLFunctionTable(int functionTablePointer);
- private static native int nativeGetAwDrawGLFunction();
+ private static native long nativeInit(AwBrowserContext browserContext);
+ private static native void nativeDestroy(long nativeAwContents);
+ private static native void nativeSetAwDrawSWFunctionTable(long functionTablePointer);
+ private static native void nativeSetAwDrawGLFunctionTable(long functionTablePointer);
+ private static native long nativeGetAwDrawGLFunction();
private static native int nativeGetNativeInstanceCount();
private static native void nativeSetShouldDownloadFavicons();
- private native void nativeSetJavaPeers(int nativeAwContents, AwContents awContents,
+
+ private native void nativeSetJavaPeers(long nativeAwContents, AwContents awContents,
AwWebContentsDelegate webViewWebContentsDelegate,
AwContentsClientBridge contentsClientBridge,
AwContentsIoThreadClient ioThreadClient,
InterceptNavigationDelegate navigationInterceptionDelegate);
- private native int nativeGetWebContents(int nativeAwContents);
+ private native long nativeGetWebContents(long nativeAwContents);
- private native void nativeDocumentHasImages(int nativeAwContents, Message message);
+ private native void nativeDocumentHasImages(long nativeAwContents, Message message);
private native void nativeGenerateMHTML(
- int nativeAwContents, String path, ValueCallback<String> callback);
-
- private native void nativeAddVisitedLinks(int nativeAwContents, String[] visitedLinks);
- private native boolean nativeOnDraw(int nativeAwContents, Canvas canvas,
- boolean isHardwareAccelerated, int scrollX, int ScrollY,
- int clipLeft, int clipTop, int clipRight, int clipBottom);
- private native void nativeSetGlobalVisibleRect(int nativeAwContents, int visibleLeft,
- int visibleTop, int visibleRight, int visibleBottom);
- private native void nativeFindAllAsync(int nativeAwContents, String searchString);
- private native void nativeFindNext(int nativeAwContents, boolean forward);
- private native void nativeClearMatches(int nativeAwContents);
- private native void nativeClearCache(int nativeAwContents, boolean includeDiskFiles);
- private native byte[] nativeGetCertificate(int nativeAwContents);
+ long nativeAwContents, String path, ValueCallback<String> callback);
+
+ private native void nativeAddVisitedLinks(long nativeAwContents, String[] visitedLinks);
+ private native boolean nativeOnDraw(long nativeAwContents, Canvas canvas,
+ boolean isHardwareAccelerated, int scrollX, int scrollY,
+ int visibleLeft, int visibleTop, int visibleRight, int visibleBottom);
+ private native void nativeFindAllAsync(long nativeAwContents, String searchString);
+ private native void nativeFindNext(long nativeAwContents, boolean forward);
+ private native void nativeClearMatches(long nativeAwContents);
+ private native void nativeClearCache(long nativeAwContents, boolean includeDiskFiles);
+ private native byte[] nativeGetCertificate(long nativeAwContents);
// Coordinates in desity independent pixels.
- private native void nativeRequestNewHitTestDataAt(int nativeAwContents, int x, int y);
- private native void nativeUpdateLastHitTestData(int nativeAwContents);
-
- private native void nativeOnSizeChanged(int nativeAwContents, int w, int h, int ow, int oh);
- private native void nativeScrollTo(int nativeAwContents, int x, int y);
- private native void nativeSetViewVisibility(int nativeAwContents, boolean visible);
- private native void nativeSetWindowVisibility(int nativeAwContents, boolean visible);
- private native void nativeSetIsPaused(int nativeAwContents, boolean paused);
- private native void nativeOnAttachedToWindow(int nativeAwContents, int w, int h);
- private static native void nativeOnDetachedFromWindow(int nativeAwContents);
- private native void nativeSetDipScale(int nativeAwContents, float dipScale);
- private native void nativeSetFixedLayoutSize(int nativeAwContents, int widthDip, int heightDip);
+ private native void nativeRequestNewHitTestDataAt(long nativeAwContents, int x, int y);
+ private native void nativeUpdateLastHitTestData(long nativeAwContents);
+
+ private native void nativeOnSizeChanged(long nativeAwContents, int w, int h, int ow, int oh);
+ private native void nativeScrollTo(long nativeAwContents, int x, int y);
+ private native void nativeSetViewVisibility(long nativeAwContents, boolean visible);
+ private native void nativeSetWindowVisibility(long nativeAwContents, boolean visible);
+ private native void nativeSetIsPaused(long nativeAwContents, boolean paused);
+ private native void nativeOnAttachedToWindow(long nativeAwContents, int w, int h);
+ private static native void nativeOnDetachedFromWindow(long nativeAwContents);
+ private native void nativeSetDipScale(long nativeAwContents, float dipScale);
// Returns null if save state fails.
- private native byte[] nativeGetOpaqueState(int nativeAwContents);
+ private native byte[] nativeGetOpaqueState(long nativeAwContents);
// Returns false if restore state fails.
- private native boolean nativeRestoreFromOpaqueState(int nativeAwContents, byte[] state);
+ private native boolean nativeRestoreFromOpaqueState(long nativeAwContents, byte[] state);
- private native int nativeReleasePopupAwContents(int nativeAwContents);
- private native void nativeFocusFirstNode(int nativeAwContents);
- private native void nativeSetBackgroundColor(int nativeAwContents, int color);
+ private native long nativeReleasePopupAwContents(long nativeAwContents);
+ private native void nativeFocusFirstNode(long nativeAwContents);
+ private native void nativeSetBackgroundColor(long nativeAwContents, int color);
- private native int nativeGetAwDrawGLViewContext(int nativeAwContents);
- private native int nativeCapturePicture(int nativeAwContents, int width, int height);
- private native void nativeEnableOnNewPicture(int nativeAwContents, boolean enabled);
+ private native long nativeGetAwDrawGLViewContext(long nativeAwContents);
+ private native long nativeCapturePicture(long nativeAwContents, int width, int height);
+ private native void nativeEnableOnNewPicture(long nativeAwContents, boolean enabled);
+ private native void nativeClearView(long nativeAwContents);
+ private native void nativeSetExtraHeadersForUrl(long nativeAwContents,
+ String url, String extraHeaders);
private native void nativeInvokeGeolocationCallback(
- int nativeAwContents, boolean value, String requestingFrame);
+ long nativeAwContents, boolean value, String requestingFrame);
+
+ private native void nativeSetJsOnlineProperty(long nativeAwContents, boolean networkUp);
+
+ private native void nativeTrimMemory(long nativeAwContents, int level, boolean visible);
- private native void nativeSetJsOnlineProperty(int nativeAwContents, boolean networkUp);
+ private native void nativeCreatePdfExporter(long nativeAwContents, AwPdfExporter awPdfExporter);
- private native void nativeTrimMemory(int nativeAwContents, int level);
+ private native void nativePreauthorizePermission(long nativeAwContents, String origin,
+ long resources);
}