Commit 38c0159b authored by Bo Liu's avatar Bo Liu Committed by Commit Bot

weblayer: Do not resize surface for soft keyboard

Resizing a Surface is really destroying and reallocating a Surface, and
then sending it to the GPU process and have it re-composite and
re-raster everything. This is a bit expensive and can cause visual
glitches when keyboard gets hidden and the view grows in size instead.
So follow chrome's behavior in weblayer and avoid resizing the Surface.

Note that resizing the web content may also be expensive and can cause
similar glitches. Chrome does not address this, neither does this CL.

The main code change is keep calling WebContents.setSize, but no longer
resize the SurfaceView or call onPhysicalBackingSizeChanged. Do this by
introducing SurfaceParent which is a FrameLayout that sits between
ContentViewRenderView and the SurfaceView in the view hierarchy.
ContentViewRenderView will keep resizing for soft keyboard, and its size
controls WebContents.setSize. The SurfaceParent will attempt to detect
cases where it is being resized for soft keyboard, and not resize in
that case. SurfaceView inherits the size from SurfaceParent, and thus
not recreate the Surface if it's not resized.

Conditions for when to apply this heuristic:
* Only use this for SurfaceView. TextureView is more likely being used
  in embedded use cases where this does not apply.
* ContentViewRenderView is the full width of the window. Again a
  heuristic to check for embedded use cases.
* Soft keyboard is showing.

Bug: 1050415
Change-Id: I9702f9ba06a4ab6c3d72355178bf47abf0d2240b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2087972Reviewed-by: default avatarScott Violet <sky@chromium.org>
Commit-Queue: Bo <boliu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#747372}
parent 4db10076
...@@ -14,6 +14,7 @@ import android.view.SurfaceView; ...@@ -14,6 +14,7 @@ import android.view.SurfaceView;
import android.view.TextureView; import android.view.TextureView;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.webkit.ValueCallback; import android.webkit.ValueCallback;
import android.widget.FrameLayout; import android.widget.FrameLayout;
...@@ -47,6 +48,10 @@ public class ContentViewRenderView extends FrameLayout { ...@@ -47,6 +48,10 @@ public class ContentViewRenderView extends FrameLayout {
public static final int MODE_SURFACE_VIEW = 0; public static final int MODE_SURFACE_VIEW = 0;
public static final int MODE_TEXTURE_VIEW = 1; public static final int MODE_TEXTURE_VIEW = 1;
// A child view of this class. Parent of SurfaceView/TextureView.
// Needed to support not resizing the surface when soft keyboard is showing.
private final SurfaceParent mSurfaceParent;
// This is mode that is requested by client. // This is mode that is requested by client.
private SurfaceData mRequested; private SurfaceData mRequested;
// This is the mode that last supplied the Surface to the compositor. // This is the mode that last supplied the Surface to the compositor.
...@@ -60,8 +65,14 @@ public class ContentViewRenderView extends FrameLayout { ...@@ -60,8 +65,14 @@ public class ContentViewRenderView extends FrameLayout {
private WebContents mWebContents; private WebContents mWebContents;
private int mBackgroundColor; private int mBackgroundColor;
private int mWidth;
private int mHeight; // This is the size of the surfaces, so the "physical" size for the compositor.
// This is the size of the |mSurfaceParent| view, which is the immediate parent
// of the SurfaceView/TextureView. Note this does not always match the size of
// this ContentViewRenderView; when the soft keyboard is displayed,
// ContentViewRenderView will shrink in height, but |mSurfaceParent| will not.
private int mPhysicalWidth;
private int mPhysicalHeight;
private int mWebContentsHeightDelta; private int mWebContentsHeightDelta;
...@@ -516,6 +527,35 @@ public class ContentViewRenderView extends FrameLayout { ...@@ -516,6 +527,35 @@ public class ContentViewRenderView extends FrameLayout {
public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {} public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {}
} }
// This is a child of ContentViewRenderView and parent of SurfaceView/TextureView.
// This exists to avoid resizing SurfaceView/TextureView when the soft keyboard is displayed.
private class SurfaceParent extends FrameLayout {
public SurfaceParent(Context context) {
super(context);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int existingHeight = getMeasuredHeight();
// If width is the same and height shrinks, then check if we should
// avoid this resize for displaying the soft keyboard.
if (getMeasuredWidth() == MeasureSpec.getSize(widthMeasureSpec)
&& existingHeight > MeasureSpec.getSize(heightMeasureSpec)
&& shouldAvoidSurfaceResizeForSoftKeyboard()) {
// Just set the height to the current height.
heightMeasureSpec =
MeasureSpec.makeMeasureSpec(existingHeight, MeasureSpec.EXACTLY);
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
mPhysicalWidth = w;
mPhysicalHeight = h;
}
}
/** /**
* Constructs a new ContentViewRenderView. * Constructs a new ContentViewRenderView.
* This should be called and the {@link ContentViewRenderView} should be added to the view * This should be called and the {@link ContentViewRenderView} should be added to the view
...@@ -525,6 +565,9 @@ public class ContentViewRenderView extends FrameLayout { ...@@ -525,6 +565,9 @@ public class ContentViewRenderView extends FrameLayout {
*/ */
public ContentViewRenderView(Context context) { public ContentViewRenderView(Context context) {
super(context); super(context);
mSurfaceParent = new SurfaceParent(context);
addView(mSurfaceParent,
new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
setBackgroundColor(Color.WHITE); setBackgroundColor(Color.WHITE);
} }
...@@ -556,7 +599,7 @@ public class ContentViewRenderView extends FrameLayout { ...@@ -556,7 +599,7 @@ public class ContentViewRenderView extends FrameLayout {
if (mRequested == null) { if (mRequested == null) {
SurfaceEventListenerImpl listener = new SurfaceEventListenerImpl(); SurfaceEventListenerImpl listener = new SurfaceEventListenerImpl();
mRequested = new SurfaceData( mRequested = new SurfaceData(
mode, this, listener, mBackgroundColor, this::evictCachedSurface); mode, mSurfaceParent, listener, mBackgroundColor, this::evictCachedSurface);
listener.setRequestData(mRequested); listener.setRequestData(mRequested);
} }
assert mRequested.getMode() == mode; assert mRequested.getMode() == mode;
...@@ -574,13 +617,11 @@ public class ContentViewRenderView extends FrameLayout { ...@@ -574,13 +617,11 @@ public class ContentViewRenderView extends FrameLayout {
private void updateWebContentsSize() { private void updateWebContentsSize() {
if (mWebContents == null) return; if (mWebContents == null) return;
mWebContents.setSize(mWidth, mHeight - mWebContentsHeightDelta); mWebContents.setSize(getWidth(), getHeight() - mWebContentsHeightDelta);
} }
@Override @Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) { protected void onSizeChanged(int w, int h, int oldw, int oldh) {
mWidth = w;
mHeight = h;
updateWebContentsSize(); updateWebContentsSize();
} }
...@@ -653,7 +694,7 @@ public class ContentViewRenderView extends FrameLayout { ...@@ -653,7 +694,7 @@ public class ContentViewRenderView extends FrameLayout {
if (webContents != null) { if (webContents != null) {
updateWebContentsSize(); updateWebContentsSize();
ContentViewRenderViewJni.get().onPhysicalBackingSizeChanged( ContentViewRenderViewJni.get().onPhysicalBackingSizeChanged(
mNativeContentViewRenderView, webContents, mWidth, mHeight); mNativeContentViewRenderView, webContents, mPhysicalWidth, mPhysicalHeight);
} }
ContentViewRenderViewJni.get().setCurrentWebContents( ContentViewRenderViewJni.get().setCurrentWebContents(
mNativeContentViewRenderView, webContents); mNativeContentViewRenderView, webContents);
...@@ -678,6 +719,19 @@ public class ContentViewRenderView extends FrameLayout { ...@@ -678,6 +719,19 @@ public class ContentViewRenderView extends FrameLayout {
return mNativeContentViewRenderView; return mNativeContentViewRenderView;
} }
private boolean shouldAvoidSurfaceResizeForSoftKeyboard() {
// TextureView is more common with embedding use cases that should lead to resize.
boolean usingSurfaceView = mCurrent != null && mCurrent.getMode() == MODE_SURFACE_VIEW;
if (!usingSurfaceView) return false;
boolean isFullWidth = isAttachedToWindow() && getWidth() == getRootView().getWidth();
if (!isFullWidth) return false;
InputMethodManager inputMethodManager =
(InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
return inputMethodManager.isActive();
}
@NativeMethods @NativeMethods
interface Natives { interface Natives {
long init(ContentViewRenderView caller, WindowAndroid rootWindow); long init(ContentViewRenderView caller, WindowAndroid rootWindow);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment