| Index: content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
|
| diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
|
| index ba0c70ebeaa44f086df6ca89bf046cf7f4b47a4d..e9cdf106c14156f9153785c012c30a53ddf08f0e 100644
|
| --- a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
|
| +++ b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
|
| @@ -87,8 +87,10 @@ import java.lang.reflect.Field;
|
| import java.util.ArrayList;
|
| import java.util.HashMap;
|
| import java.util.HashSet;
|
| +import java.util.LinkedHashMap;
|
| import java.util.List;
|
| import java.util.Map;
|
| +import java.util.Map.Entry;
|
|
|
| /**
|
| * Provides a Java-side 'wrapper' around a WebContent (native) instance.
|
| @@ -143,6 +145,136 @@ public class ContentViewCore
|
| private final HashSet<Object> mRetainedJavaScriptObjects = new HashSet<Object>();
|
|
|
| /**
|
| + * A {@link ViewAndroidDelegate} that delegates to the current container view.
|
| + *
|
| + * <p>This delegate handles the replacement of container views transparently so
|
| + * that clients can safely hold to instances of this class.
|
| + */
|
| + private class ContentViewAndroidDelegate implements ViewAndroidDelegate {
|
| + /**
|
| + * Represents the position of an anchor view.
|
| + */
|
| + @VisibleForTesting
|
| + private class Position {
|
| + private final float mX;
|
| + private final float mY;
|
| + private final float mWidth;
|
| + private final float mHeight;
|
| +
|
| + public Position(float x, float y, float width, float height) {
|
| + mX = x;
|
| + mY = y;
|
| + mWidth = width;
|
| + mHeight = height;
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * The current container view. This view can be updated with
|
| + * {@link #updateCurrentContainerView()}.
|
| + */
|
| + private ViewGroup mCurrentContainerView;
|
| +
|
| + /**
|
| + * List of anchor views stored in the order in which they were acquired mapped
|
| + * to their position.
|
| + */
|
| + private Map<View, Position> mAnchorViews = new LinkedHashMap<View, Position>();
|
| +
|
| + @Override
|
| + public View acquireAnchorView() {
|
| + View anchorView = new View(mContext);
|
| + mAnchorViews.put(anchorView, null);
|
| + mCurrentContainerView.addView(anchorView);
|
| + return anchorView;
|
| + }
|
| +
|
| + @Override
|
| + @SuppressWarnings("deprecation") // AbsoluteLayout
|
| + public void setAnchorViewPosition(
|
| + View view, float x, float y, float width, float height) {
|
| + mAnchorViews.put(view, new Position(x, y, width, height));
|
| + doSetAnchorViewPosition(view, x, y, width, height);
|
| + }
|
| +
|
| + private void doSetAnchorViewPosition(
|
| + View view, float x, float y, float width, float height) {
|
| + if (view.getParent() == null) {
|
| + // Ignore. setAnchorViewPosition has been called after the anchor view has
|
| + // already been released.
|
| + return;
|
| + }
|
| + assert view.getParent() == mCurrentContainerView;
|
| +
|
| + float scale = (float) DeviceDisplayInfo.create(mContext).getDIPScale();
|
| +
|
| + // The anchor view should not go outside the bounds of the ContainerView.
|
| + int leftMargin = Math.round(x * scale);
|
| + int topMargin = Math.round(mRenderCoordinates.getContentOffsetYPix() + y * scale);
|
| + int scaledWidth = Math.round(width * scale);
|
| + // ContentViewCore currently only supports these two container view types.
|
| + if (mCurrentContainerView instanceof FrameLayout) {
|
| + int startMargin;
|
| + if (ApiCompatibilityUtils.isLayoutRtl(mCurrentContainerView)) {
|
| + startMargin = mCurrentContainerView.getMeasuredWidth()
|
| + - Math.round((width + x) * scale);
|
| + } else {
|
| + startMargin = leftMargin;
|
| + }
|
| + if (scaledWidth + startMargin > mCurrentContainerView.getWidth()) {
|
| + scaledWidth = mCurrentContainerView.getWidth() - startMargin;
|
| + }
|
| + FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
|
| + scaledWidth, Math.round(height * scale));
|
| + ApiCompatibilityUtils.setMarginStart(lp, startMargin);
|
| + lp.topMargin = topMargin;
|
| + view.setLayoutParams(lp);
|
| + } else if (mCurrentContainerView instanceof android.widget.AbsoluteLayout) {
|
| + // 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();
|
| +
|
| + android.widget.AbsoluteLayout.LayoutParams lp =
|
| + new android.widget.AbsoluteLayout.LayoutParams(
|
| + scaledWidth, (int) (height * scale), leftMargin, topMargin);
|
| + view.setLayoutParams(lp);
|
| + } else {
|
| + Log.e(TAG, "Unknown layout " + mCurrentContainerView.getClass().getName());
|
| + }
|
| + }
|
| +
|
| + @Override
|
| + public void releaseAnchorView(View anchorView) {
|
| + mAnchorViews.remove(anchorView);
|
| + mCurrentContainerView.removeView(anchorView);
|
| + }
|
| +
|
| + /**
|
| + * Updates (or sets for the first time) the current container view to which
|
| + * this class delegates. Existing anchor views are transferred from the old to
|
| + * the new container view.
|
| + */
|
| + void updateCurrentContainerView() {
|
| + ViewGroup oldContainerView = mCurrentContainerView;
|
| + mCurrentContainerView = mContainerView;
|
| + for (Entry<View, Position> entry : mAnchorViews.entrySet()) {
|
| + View anchorView = entry.getKey();
|
| + Position position = entry.getValue();
|
| + oldContainerView.removeView(anchorView);
|
| + mCurrentContainerView.addView(anchorView);
|
| + if (position != null) {
|
| + doSetAnchorViewPosition(anchorView,
|
| + position.mX, position.mY, position.mWidth, position.mHeight);
|
| + }
|
| + }
|
| + }
|
| + }
|
| +
|
| + /**
|
| * Interface that consumers of {@link ContentViewCore} must implement to allow the proper
|
| * dispatching of view methods through the containing view.
|
| *
|
| @@ -361,6 +493,9 @@ public class ContentViewCore
|
| // screen orientation.
|
| private boolean mFullscreenRequiredForOrientationLock = true;
|
|
|
| + // A ViewAndroidDelegate that delegates to the current container view.
|
| + private ContentViewAndroidDelegate mViewAndroidDelegate;
|
| +
|
| /**
|
| * Constructs a new ContentViewCore. Embedders must call initialize() after constructing
|
| * a ContentViewCore and before using it.
|
| @@ -429,9 +564,11 @@ public class ContentViewCore
|
| }
|
|
|
| /**
|
| - * Returns a delegate that can be used to add and remove views from the ContainerView.
|
| + * Returns a delegate that can be used to add and remove views from the current
|
| + * container view. Clients can safely hold to instances of this class as it handles the
|
| + * replacement of container views transparently.
|
| *
|
| - * NOTE: Use with care, as not all ContentViewCore users setup their ContainerView in the same
|
| + * NOTE: Use with care, as not all ContentViewCore users setup their container view in the same
|
| * way. In particular, the Android WebView has limitations on what implementation details can
|
| * be provided via a child view, as they are visible in the API and could introduce
|
| * compatibility breaks with existing applications. If in doubt, contact the
|
| @@ -439,77 +576,8 @@ public class ContentViewCore
|
| *
|
| * @return A ViewAndroidDelegate that can be used to add and remove views.
|
| */
|
| - @VisibleForTesting
|
| public ViewAndroidDelegate getViewAndroidDelegate() {
|
| - return new ViewAndroidDelegate() {
|
| - // mContainerView can change, but this ViewAndroidDelegate can only be used to
|
| - // add and remove views from the mContainerViewAtCreation.
|
| - private final ViewGroup mContainerViewAtCreation = mContainerView;
|
| -
|
| - @Override
|
| - public View acquireAnchorView() {
|
| - View anchorView = new View(mContext);
|
| - mContainerViewAtCreation.addView(anchorView);
|
| - return anchorView;
|
| - }
|
| -
|
| - @Override
|
| - @SuppressWarnings("deprecation") // AbsoluteLayout
|
| - public void setAnchorViewPosition(
|
| - View view, float x, float y, float width, float height) {
|
| - if (view.getParent() == null) {
|
| - // Ignore. setAnchorViewPosition has been called after the anchor view has
|
| - // already been released.
|
| - return;
|
| - }
|
| - assert view.getParent() == mContainerViewAtCreation;
|
| -
|
| - float scale = (float) DeviceDisplayInfo.create(mContext).getDIPScale();
|
| -
|
| - // The anchor view should not go outside the bounds of the ContainerView.
|
| - int leftMargin = Math.round(x * scale);
|
| - int topMargin = Math.round(mRenderCoordinates.getContentOffsetYPix() + y * scale);
|
| - int scaledWidth = Math.round(width * scale);
|
| - // ContentViewCore currently only supports these two container view types.
|
| - if (mContainerViewAtCreation instanceof FrameLayout) {
|
| - int startMargin;
|
| - if (ApiCompatibilityUtils.isLayoutRtl(mContainerViewAtCreation)) {
|
| - startMargin = mContainerViewAtCreation.getMeasuredWidth()
|
| - - Math.round((width + x) * scale);
|
| - } else {
|
| - startMargin = leftMargin;
|
| - }
|
| - if (scaledWidth + startMargin > mContainerViewAtCreation.getWidth()) {
|
| - scaledWidth = mContainerViewAtCreation.getWidth() - startMargin;
|
| - }
|
| - FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
|
| - scaledWidth, Math.round(height * scale));
|
| - ApiCompatibilityUtils.setMarginStart(lp, startMargin);
|
| - lp.topMargin = topMargin;
|
| - view.setLayoutParams(lp);
|
| - } else if (mContainerViewAtCreation instanceof android.widget.AbsoluteLayout) {
|
| - // 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();
|
| -
|
| - android.widget.AbsoluteLayout.LayoutParams lp =
|
| - new android.widget.AbsoluteLayout.LayoutParams(
|
| - scaledWidth, (int) (height * scale), leftMargin, topMargin);
|
| - view.setLayoutParams(lp);
|
| - } else {
|
| - Log.e(TAG, "Unknown layout " + mContainerViewAtCreation.getClass().getName());
|
| - }
|
| - }
|
| -
|
| - @Override
|
| - public void releaseAnchorView(View anchorView) {
|
| - mContainerViewAtCreation.removeView(anchorView);
|
| - }
|
| - };
|
| + return mViewAndroidDelegate;
|
| }
|
|
|
| @VisibleForTesting
|
| @@ -537,6 +605,11 @@ public class ContentViewCore
|
| return mInputConnection;
|
| }
|
|
|
| + @VisibleForTesting
|
| + ViewAndroid getViewAndroid() {
|
| + return mViewAndroid;
|
| + }
|
| +
|
| private ImeAdapter createImeAdapter(Context context) {
|
| return new ImeAdapter(mInputMethodManagerWrapper,
|
| new ImeAdapter.ImeAdapterDelegate() {
|
| @@ -605,11 +678,12 @@ public class ContentViewCore
|
| // deleting it after destroying the ContentViewCore.
|
| public void initialize(ViewGroup containerView, InternalAccessDelegate internalDispatcher,
|
| long nativeWebContents, WindowAndroid windowAndroid) {
|
| + createContentViewAndroidDelegate();
|
| setContainerView(containerView);
|
| -
|
| long windowNativePointer = windowAndroid.getNativePointer();
|
| assert windowNativePointer != 0;
|
| - mViewAndroid = new ViewAndroid(windowAndroid, getViewAndroidDelegate());
|
| + createViewAndroid(windowAndroid);
|
| +
|
| long viewAndroidNativePointer = mViewAndroid.getNativePointer();
|
| assert viewAndroidNativePointer != 0;
|
|
|
| @@ -648,13 +722,23 @@ public class ContentViewCore
|
| };
|
| }
|
|
|
| + @VisibleForTesting
|
| + void createContentViewAndroidDelegate() {
|
| + mViewAndroidDelegate = new ContentViewAndroidDelegate();
|
| + }
|
| +
|
| + @VisibleForTesting
|
| + void createViewAndroid(WindowAndroid windowAndroid) {
|
| + mViewAndroid = new ViewAndroid(windowAndroid, mViewAndroidDelegate);
|
| + }
|
| +
|
| /**
|
| * Sets a new container view for this {@link ContentViewCore}.
|
| *
|
| - * <p>WARNING: This is not a general purpose method and has been designed with WebView
|
| - * fullscreen in mind. Please be aware that it might not be appropriate for other use cases
|
| - * and that it has a number of limitations. For example the PopupZoomer only works with the
|
| - * container view with which this ContentViewCore has been initialized.
|
| + * <p>WARNING: This method can also be used to replace the existing container view,
|
| + * but you should only do it if you have a very good reason to. Replacing the
|
| + * container view has been designed to support fullscreen in the Webview so it
|
| + * might not be appropriate for other use cases.
|
| *
|
| * <p>This method only performs a small part of replacing the container view and
|
| * embedders are responsible for:
|
| @@ -678,6 +762,7 @@ public class ContentViewCore
|
| mPositionObserver = new ViewPositionObserver(mContainerView);
|
| mContainerView.setWillNotDraw(false);
|
| mContainerView.setClickable(true);
|
| + mViewAndroidDelegate.updateCurrentContainerView();
|
| TraceEvent.end();
|
| }
|
|
|
| @@ -696,7 +781,8 @@ public class ContentViewCore
|
| mContainerViewInternals = internalDispatcher;
|
| }
|
|
|
| - private void initPopupZoomer(Context context) {
|
| + @VisibleForTesting
|
| + void initPopupZoomer(Context context) {
|
| mPopupZoomer = new PopupZoomer(context);
|
| mPopupZoomer.setOnVisibilityChangedListener(new PopupZoomer.OnVisibilityChangedListener() {
|
| // mContainerView can change, but this OnVisibilityChangedListener can only be used
|
|
|