Index: android_webview/java/src/org/chromium/android_webview/AwContents.java |
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContents.java b/android_webview/java/src/org/chromium/android_webview/AwContents.java |
index 65d815924c7e950517e8fcde222ed5a0bdff2aad..aabcc3bd8ac8fdd8dbbc71bb5fbe5ce7a5a72613 100644 |
--- a/android_webview/java/src/org/chromium/android_webview/AwContents.java |
+++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java |
@@ -42,6 +42,7 @@ import android.view.inputmethod.EditorInfo; |
import android.view.inputmethod.InputConnection; |
import android.webkit.JavascriptInterface; |
import android.webkit.ValueCallback; |
+import android.widget.FrameLayout; |
import org.chromium.android_webview.permission.AwGeolocationCallback; |
import org.chromium.android_webview.permission.AwPermissionRequest; |
@@ -55,9 +56,11 @@ import org.chromium.base.annotations.JNINamespace; |
import org.chromium.base.annotations.SuppressFBWarnings; |
import org.chromium.components.navigation_interception.InterceptNavigationDelegate; |
import org.chromium.components.navigation_interception.NavigationParams; |
+import org.chromium.content.browser.ContentViewAndroidDelegate; |
import org.chromium.content.browser.ContentViewClient; |
import org.chromium.content.browser.ContentViewCore; |
import org.chromium.content.browser.ContentViewStatics; |
+import org.chromium.content.browser.RenderCoordinates; |
import org.chromium.content.browser.SmartClipProvider; |
import org.chromium.content.common.CleanupReference; |
import org.chromium.content_public.browser.GestureStateListener; |
@@ -78,11 +81,14 @@ import org.chromium.ui.gfx.DeviceDisplayInfo; |
import java.io.File; |
import java.lang.annotation.Annotation; |
+import java.lang.ref.WeakReference; |
import java.net.MalformedURLException; |
import java.net.URL; |
import java.util.HashMap; |
+import java.util.LinkedHashMap; |
import java.util.Locale; |
import java.util.Map; |
+import java.util.Map.Entry; |
import java.util.WeakHashMap; |
import java.util.concurrent.Callable; |
@@ -92,7 +98,7 @@ import java.util.concurrent.Callable; |
* primary entry point for the WebViewProvider implementation; it holds a 1:1 object |
* relationship with application WebView instances. |
* (We define this class independent of the hidden WebViewProvider interfaces, to allow |
- * continuous build & test in the open source SDK-based tree). |
+ * continuous build & test in the open source SDK-based tree). |
*/ |
@JNINamespace("android_webview") |
public class AwContents implements SmartClipProvider, |
@@ -264,6 +270,7 @@ public class AwContents implements SmartClipProvider, |
private final Context mContext; |
private final int mAppTargetSdkVersion; |
private ContentViewCore mContentViewCore; |
+ private AwContentViewAndroidDelegate mViewAndroidDelegate; |
private WindowAndroidWrapper mWindowAndroid; |
private WebContents mWebContents; |
private NavigationController mNavigationController; |
@@ -810,7 +817,9 @@ public class AwContents implements SmartClipProvider, |
ContentViewCore.ZoomControlsDelegate zoomControlsDelegate, |
WindowAndroid windowAndroid) { |
ContentViewCore contentViewCore = new ContentViewCore(context); |
- contentViewCore.initialize(containerView, internalDispatcher, webContents, |
+ AwContentViewAndroidDelegate viewDelegate = new AwContentViewAndroidDelegate( |
+ containerView, contentViewCore.getRenderCoordinates()); |
+ contentViewCore.initialize(containerView, viewDelegate, internalDispatcher, webContents, |
windowAndroid); |
contentViewCore.addGestureStateListener(gestureStateListener); |
contentViewCore.setContentViewClient(contentViewClient); |
@@ -818,6 +827,133 @@ public class AwContents implements SmartClipProvider, |
return contentViewCore; |
} |
+ /** |
+ * Implementation of the interface {@link org.chromium.ui.base.ViewAndroidDelegate} |
+ * for WebView. |
+ */ |
+ public static class AwContentViewAndroidDelegate extends ContentViewAndroidDelegate { |
+ /** |
+ * The current container view. This view can be updated with |
+ * {@link #updateCurrentContainerView()}. This needs to be a WeakReference |
+ * because ViewAndroidDelegate is held strongly native side, which otherwise |
+ * indefinitely prevents Android WebView from being garbage collected. |
+ */ |
+ private WeakReference<ViewGroup> mContainerView; |
+ |
+ /** |
+ * List of anchor views stored in the order in which they were acquired mapped |
+ * to their position. |
+ */ |
+ private final Map<View, Position> mAnchorViews = new LinkedHashMap<>(); |
+ |
+ private final RenderCoordinates mRenderCoordinates; |
+ |
+ /** |
+ * Represents the position of an anchor view. |
+ */ |
+ @VisibleForTesting |
+ private static class Position { |
+ public final float mX; |
+ public final float mY; |
+ public final float mWidth; |
+ public final float mHeight; |
+ public final int mLeftMargin; |
+ public final int mTopMargin; |
+ |
+ public Position(float x, float y, float width, float height, int leftMargin, |
+ int topMargin) { |
+ mX = x; |
+ mY = y; |
+ mWidth = width; |
+ mHeight = height; |
+ mLeftMargin = leftMargin; |
+ mTopMargin = topMargin; |
+ } |
+ } |
+ |
+ AwContentViewAndroidDelegate(ViewGroup containerView, RenderCoordinates renderCoordinates) { |
+ super(null); |
+ mContainerView = new WeakReference<>(containerView); |
+ mRenderCoordinates = renderCoordinates; |
+ } |
+ |
+ @Override |
+ public void addView(View anchorView) { |
+ ViewGroup containerView = mContainerView.get(); |
+ if (containerView == null) return; |
+ containerView.addView(anchorView); |
+ // |mAnchorViews| will be updated with the right view position in |setViewPosition|. |
+ mAnchorViews.put(anchorView, null); |
+ } |
+ |
+ @Override |
+ public void removeView(View anchorView) { |
+ mAnchorViews.remove(anchorView); |
+ ViewGroup containerView = mContainerView.get(); |
+ if (containerView != null) { |
+ containerView.removeView(anchorView); |
+ } |
+ } |
+ |
+ /** |
+ * Updates the current container view to which this class delegates. Existing anchor views |
+ * are transferred from the old to the new container view. |
+ */ |
+ public void updateCurrentContainerView(ViewGroup containerView) { |
+ ViewGroup oldContainerView = mContainerView.get(); |
+ mContainerView = new WeakReference<>(containerView); |
+ for (Entry<View, Position> entry : mAnchorViews.entrySet()) { |
+ View anchorView = entry.getKey(); |
+ Position position = entry.getValue(); |
+ if (oldContainerView != null) { |
+ oldContainerView.removeView(anchorView); |
+ } |
+ containerView.addView(anchorView); |
+ if (position != null) { |
+ float scale = (float) DeviceDisplayInfo.create(containerView.getContext()) |
+ .getDIPScale(); |
+ setViewPosition(anchorView, position.mX, position.mY, |
+ position.mWidth, position.mHeight, scale, |
+ position.mLeftMargin, position.mTopMargin); |
+ } |
+ } |
+ } |
+ |
+ @SuppressWarnings("deprecation") // AbsoluteLayout |
+ @Override |
+ public void setViewPosition(View anchorView, float x, float y, float width, float height, |
+ float scale, int leftMargin, int topMargin) { |
+ if (!mAnchorViews.containsKey(anchorView)) return; |
+ mAnchorViews.put(anchorView, new Position(x, y, width, height, leftMargin, topMargin)); |
+ |
+ ViewGroup containerView = getContainerView(); |
+ if (containerView instanceof FrameLayout) { |
+ super.setViewPosition(anchorView, x, y, width, height, scale, leftMargin, |
+ topMargin); |
+ return; |
+ } |
+ // This fixes the offset due to a difference in |
+ // scrolling model of WebView vs. Chrome. |
+ // TODO(sgurun) fix this to use mContainerViewAtCreation.getScroll[X/Y]() |
+ // as it naturally accounts for scroll differences between |
+ // these models. |
+ leftMargin += mRenderCoordinates.getScrollXPixInt(); |
+ topMargin += mRenderCoordinates.getScrollYPixInt(); |
+ |
+ int scaledWidth = Math.round(width * scale); |
+ int scaledHeight = Math.round(height * scale); |
+ android.widget.AbsoluteLayout.LayoutParams lp = |
+ new android.widget.AbsoluteLayout.LayoutParams( |
+ scaledWidth, scaledHeight, leftMargin, topMargin); |
+ anchorView.setLayoutParams(lp); |
+ } |
+ |
+ @Override |
+ protected ViewGroup getContainerView() { |
+ return mContainerView.get(); |
+ } |
+ } |
+ |
boolean isFullScreen() { |
return mFullScreenTransitionsState.isFullScreen(); |
} |
@@ -917,6 +1053,7 @@ public class AwContents implements SmartClipProvider, |
updateNativeAwGLFunctor(); |
mContainerView.setWillNotDraw(false); |
+ mViewAndroidDelegate.updateCurrentContainerView(mContainerView); |
mContentViewCore.setContainerView(mContainerView); |
if (mAwPdfExporter != null) { |
mAwPdfExporter.setContainerView(mContainerView); |
@@ -1040,6 +1177,8 @@ public class AwContents implements SmartClipProvider, |
mContentViewCore = createAndInitializeContentViewCore(mContainerView, mContext, |
mInternalAccessAdapter, webContents, new AwGestureStateListener(), |
mContentViewClient, mZoomControls, mWindowAndroid.getWindowAndroid()); |
+ mViewAndroidDelegate = (AwContentViewAndroidDelegate) |
+ mContentViewCore.getViewAndroidDelegate(); |
nativeSetJavaPeers(mNativeAwContents, this, mWebContentsDelegate, mContentsClientBridge, |
mIoThreadClient, mInterceptNavigationDelegate); |
mWebContents = mContentViewCore.getWebContents(); |