package org.chromium.android_webview;
+import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.ComponentCallbacks2;
import android.content.Context;
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.net.Uri;
import android.net.http.SslCertificate;
import android.os.AsyncTask;
import android.os.Build;
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.content.browser.NavigationHistory;
import org.chromium.content.browser.PageTransitionTypes;
import org.chromium.content.common.CleanupReference;
+import org.chromium.content_public.Referrer;
import org.chromium.content_public.browser.GestureStateListener;
import org.chromium.ui.base.ActivityWindowAndroid;
import org.chromium.ui.base.WindowAndroid;
import java.lang.annotation.Annotation;
import java.net.MalformedURLException;
import java.net.URL;
-import java.util.ArrayList;
import java.util.HashMap;
-import java.util.List;
+import java.util.Locale;
+import java.util.Map;
import java.util.concurrent.Callable;
/**
* @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();
+ }
+
+ /**
+ * 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 final AwContentsClient mContentsClient;
private final AwContentViewClient mContentViewClient;
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;
private float mContentWidthDip;
private float mContentHeightDip;
- private AwAutofillManagerDelegate mAwAutofillManagerDelegate;
-
- private ComponentCallbacks2 mComponentCallbacks;
+ 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 static final class DestroyRunnable implements Runnable {
private final long mNativeAwContents;
private DestroyRunnable(long 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);
}
}
@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);
}
}
//--------------------------------------------------------------------------------------------
private class AwComponentCallbacks implements ComponentCallbacks2 {
@Override
- public void onTrimMemory(int level) {
+ public void onTrimMemory(final int level) {
if (mNativeAwContents == 0) return;
- nativeTrimMemory(mNativeAwContents, level);
+ boolean visibleRectEmpty = getGlobalVisibleRect().isEmpty();
+ final boolean visible = mIsViewVisible && mIsWindowVisible && !visibleRectEmpty;
+ nativeTrimMemory(mNativeAwContents, level, visible);
}
@Override
/**
* @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 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,
- AwSettings awSettings) {
- this(browserContext, containerView, internalAccessAdapter, contentsClient, awSettings,
- new AwLayoutSizer());
+ 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.
*/
- public AwContents(AwBrowserContext browserContext, ViewGroup containerView,
- InternalAccessDelegate internalAccessAdapter, AwContentsClient contentsClient,
- AwSettings settings, AwLayoutSizer layoutSizer) {
+ 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;
- mContentViewClient = new AwContentViewClient(contentsClient, settings);
- 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();
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,
- InternalAccessDelegate internalDispatcher, int nativeWebContents,
+ Context context, InternalAccessDelegate internalDispatcher, long nativeWebContents,
GestureStateListener gestureStateListener,
ContentViewClient contentViewClient,
ContentViewCore.ZoomControlsDelegate zoomControlsDelegate) {
- Context context = containerView.getContext();
ContentViewCore contentViewCore = new ContentViewCore(context);
contentViewCore.initialize(containerView, internalDispatcher, nativeWebContents,
context instanceof Activity ?
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.
+ */
+ View enterFullScreen() {
+ assert !isFullScreen();
+
+ // 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() {
+ assert isFullScreen();
+
+ // 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());
+ if (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.
// bind all the native->java relationships.
mCleanupReference = new CleanupReference(this, new DestroyRunnable(mNativeAwContents));
- int nativeWebContents = nativeGetWebContents(mNativeAwContents);
+ long nativeWebContents = nativeGetWebContents(mNativeAwContents);
mContentViewCore = createAndInitializeContentViewCore(
- mContainerView, mInternalAccessAdapter, nativeWebContents,
+ mContainerView, mContext, mInternalAccessAdapter, nativeWebContents,
new AwGestureStateListener(), mContentViewClient, mZoomControls);
nativeSetJavaPeers(mNativeAwContents, this, mWebContentsDelegate, mContentsClientBridge,
mIoThreadClient, mInterceptNavigationDelegate);
mContentsClient.installWebContentsObserver(mContentViewCore);
mSettings.setWebContents(nativeWebContents);
nativeSetDipScale(mNativeAwContents, (float) mDIPScale);
- updateGlobalVisibleRect();
// The only call to onShow. onHide should never be called.
mContentViewCore.onShow();
* 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;
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.
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);
}
/**
- * 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.
+ * Deletes the native counterpart of this object.
*/
public void destroy() {
if (mCleanupReference != null) {
+ assert mNativeAwContents != 0;
+ // If we are attached, we have to call native detach to clean up
+ // hardware resources.
+ if (mIsAttachedToWindow) {
+ nativeOnDetachedFromWindow(mNativeAwContents);
+ }
+
// 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
mContentViewCore.destroy();
mNativeAwContents = 0;
- // 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;
}
return mAwPdfExporter;
}
- public static void setAwDrawSWFunctionTable(int functionTablePointer) {
+ 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() {
+ 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;
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 (!nativeOnDraw(mNativeAwContents, canvas, canvas.isHardwareAccelerated(),
- mContainerView.getScrollX(), mContainerView.getScrollY(),
- mClipBoundsTemporary.left, mClipBoundsTemporary.top,
- mClipBoundsTemporary.right, mClipBoundsTemporary.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();
- }
+ 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;
return new AwPicture(nativeCapturePicture(mNativeAwContents,
- mScrollOffsetManager.computeHorizontalScrollRange(),
- mScrollOffsetManager.computeVerticalScrollRange()));
+ mScrollOffsetManager.computeHorizontalScrollRange(),
+ mScrollOffsetManager.computeVerticalScrollRange()));
}
public void clearView() {
* @param params Parameters for this load.
*/
public void loadUrl(LoadUrlParams params) {
+ if (mNativeAwContents == 0) return;
+
if (params.getLoadUrlType() == LoadUrlParams.LOAD_TYPE_DATA &&
!params.isBaseUrlDataScheme()) {
// This allows data URLs with a non-data base URL access to file:///android_asset/ and
if (params.getUrl() != null &&
params.getUrl().equals(mContentViewCore.getUrl()) &&
params.getTransitionType() == PageTransitionTypes.PAGE_TRANSITION_LINK) {
- params.setTransitionType(PageTransitionTypes.PAGE_TRANSITION_RELOAD);
+ params.setTransitionType(PageTransitionTypes.PAGE_TRANSITION_RELOAD);
}
params.setTransitionType(
params.getTransitionType() | PageTransitionTypes.PAGE_TRANSITION_FROM_API);
// every time the user agent in AwSettings is modified.
params.setOverrideUserAgent(LoadUrlParams.UA_OVERRIDE_TRUE);
+
// 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
- if (mNativeAwContents != 0) {
- nativeSetExtraHeadersForUrl(
- mNativeAwContents, params.getUrl(), params.getExtraHttpRequestHeadersString());
+ // 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>());
+ nativeSendCheckRenderThreadResponsiveness(mNativeAwContents);
mContentViewCore.loadUrl(params);
// The behavior of WebViewClassic uses the populateVisitedLinks callback in WebKit.
}
public void requestFocus() {
- if (mNativeAwContents == 0) return;
- if (!mContainerView.isInTouchMode() && mSettings.shouldFocusFirstNode()) {
- nativeFocusFirstNode(mNativeAwContents);
- }
+ mAwViewMethods.requestFocus();
}
public void setBackgroundColor(int color) {
if (mNativeAwContents != 0) 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.
*/
public void setOverScrollMode(int mode) {
if (mode != View.OVER_SCROLL_NEVER) {
- mOverScrollGlow = new OverScrollGlow(mContainerView);
+ mOverScrollGlow = new OverScrollGlow(mContext, mContainerView);
} else {
mOverScrollGlow = null;
}
* @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);
}
/**
}
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);
}
mContentViewCore.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.
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 (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#preauthorizePermission(Uri, long)
+ */
+ public void preauthorizePermission(Uri origin, long resources) {
+ if (mNativeAwContents == 0) return;
+ nativePreauthorizePermission(mNativeAwContents, origin.toString(), resources);
+ }
+
+ /**
* @see ContentViewCore.evaluateJavaScript(String, ContentViewCore.JavaScriptCallback)
*/
public void evaluateJavaScript(String script, final ValueCallback<String> callback) {
* @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#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());
- mSettings.setEnableSupportedHardwareAcceleratedFeatures(
- mContainerView.isHardwareAccelerated());
-
- 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();
-
- mSettings.setEnableSupportedHardwareAcceleratedFeatures(false);
-
- 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) {
* @see android.webkit.WebView#clearFormData()
*/
public void hideAutofillPopup() {
- if (mAwAutofillManagerDelegate != null)
- mAwAutofillManagerDelegate.hideAutofillPopup();
+ if (mAwAutofillClient != null) {
+ mAwAutofillClient.hideAutofillPopup();
+ }
}
public void setNetworkAvailable(boolean networkUp) {
}
@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
- 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 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 setPageScaleFactorAndLimits(
+ private void updateScrollState(int maxContainerViewScrollOffsetX,
+ int maxContainerViewScrollOffsetY, int contentWidthDip, int contentHeightDip,
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));
- }
+ 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) {
ThreadUtils.runOnUiThread(new Runnable() {
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 (mNativeAwContents == 0) {
+ 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 (mNativeAwContents == 0) 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 mContentViewCore.onCreateInputConnection(outAttrs);
+ }
+
+ @Override
+ public boolean onKeyUp(int keyCode, KeyEvent event) {
+ return mContentViewCore.onKeyUp(keyCode, event);
+ }
+
+ @Override
+ public boolean dispatchKeyEvent(KeyEvent event) {
+ 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 (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) {
+ 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 mContentViewCore.onHoverEvent(event);
+ }
+
+ @Override
+ public boolean onGenericMotionEvent(MotionEvent event) {
+ return mContentViewCore.onGenericMotionEvent(event);
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ mContentViewCore.onConfigurationChanged(newConfig);
+ }
+
+ @Override
+ public void onAttachedToWindow() {
+ if (mNativeAwContents == 0) 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 (!mIsAttachedToWindow) {
+ Log.w(TAG, "onDetachedFromWindow called when already detached. Ignoring");
+ return;
+ }
+ mIsAttachedToWindow = false;
+ hideAutofillPopup();
+ if (mNativeAwContents != 0) {
+ nativeOnDetachedFromWindow(mNativeAwContents);
+ }
+
+ mContentViewCore.onDetachedFromWindow();
+ updateHardwareAcceleratedFeaturesToggle();
+
+ if (mComponentCallbacks != null) {
+ mContext.unregisterComponentCallbacks(mComponentCallbacks);
+ mComponentCallbacks = null;
+ }
+
+ mScrollAccessibilityHelper.removePostedCallbacks();
+ mNativeGLDelegate.detachGLFunctor();
+ }
+
+ @Override
+ public void onWindowFocusChanged(boolean hasWindowFocus) {
+ mWindowFocused = hasWindowFocus;
+ mContentViewCore.onWindowFocusChanged(hasWindowFocus);
+ }
+
+ @Override
+ public void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
+ mContainerViewFocused = focused;
+ mContentViewCore.onFocusChanged(focused);
+ }
+
+ @Override
+ 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);
+ }
+
+ @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 long nativeInit(AwBrowserContext browserContext);
private static native void nativeDestroy(long nativeAwContents);
- private static native void nativeSetAwDrawSWFunctionTable(int functionTablePointer);
- private static native void nativeSetAwDrawGLFunctionTable(int functionTablePointer);
- private static native int nativeGetAwDrawGLFunction();
+ 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(long nativeAwContents, AwContents awContents,
AwWebContentsDelegate webViewWebContentsDelegate,
AwContentsClientBridge contentsClientBridge,
AwContentsIoThreadClient ioThreadClient,
InterceptNavigationDelegate navigationInterceptionDelegate);
- private native int nativeGetWebContents(long nativeAwContents);
+ private native long nativeGetWebContents(long nativeAwContents);
private native void nativeDocumentHasImages(long nativeAwContents, Message message);
private native void nativeGenerateMHTML(
private native void nativeAddVisitedLinks(long nativeAwContents, String[] visitedLinks);
private native boolean nativeOnDraw(long nativeAwContents, Canvas canvas,
boolean isHardwareAccelerated, int scrollX, int scrollY,
- int clipLeft, int clipTop, int clipRight, int clipBottom);
- private native void nativeSetGlobalVisibleRect(long nativeAwContents, int visibleLeft,
- int visibleTop, int visibleRight, int visibleBottom);
+ 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 nativeOnAttachedToWindow(long nativeAwContents, int w, int h);
private static native void nativeOnDetachedFromWindow(long nativeAwContents);
private native void nativeSetDipScale(long nativeAwContents, float dipScale);
- private native void nativeSetFixedLayoutSize(long nativeAwContents,
- int widthDip, int heightDip);
// Returns null if save state fails.
private native byte[] nativeGetOpaqueState(long nativeAwContents);
// Returns false if restore state fails.
private native boolean nativeRestoreFromOpaqueState(long nativeAwContents, byte[] state);
- private native int nativeReleasePopupAwContents(long nativeAwContents);
+ private native long nativeReleasePopupAwContents(long nativeAwContents);
private native void nativeFocusFirstNode(long nativeAwContents);
private native void nativeSetBackgroundColor(long nativeAwContents, int color);
- private native int nativeGetAwDrawGLViewContext(long nativeAwContents);
+ 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 nativeSendCheckRenderThreadResponsiveness(long nativeAwContents);
private native void nativeInvokeGeolocationCallback(
long nativeAwContents, boolean value, String requestingFrame);
private native void nativeSetJsOnlineProperty(long nativeAwContents, boolean networkUp);
- private native void nativeTrimMemory(long nativeAwContents, int level);
+ private native void nativeTrimMemory(long nativeAwContents, int level, boolean visible);
private native void nativeCreatePdfExporter(long nativeAwContents, AwPdfExporter awPdfExporter);
+
+ private native void nativePreauthorizePermission(long nativeAwContents, String origin,
+ long resources);
}