Commit 140aa0cb authored by Bo Liu's avatar Bo Liu Committed by Commit Bot

weblayer: Use 0 deadline for resize except rotation

Weblayer resize may be caused by client in which case keeping the page
interactive is more important than showing gutters. This CL adds a
heuristic to detect surface resize due to a rotation. Then add plumbing
for a surface resize to supply a deadline override, and override the
deadline to 0 for non-rotation resizes.

There are two resize heuristics:

If activity is recreated, we already have code to detect this case in
BrowserImpl, and just pass it into ContentViewRenderView when it's
recreated.

If activity handles rotation, it's detected by the
DisplayAndroidObserver which appears to always happens before the
resize.

This CL does not change non-weblayer products.

Bug: 1126706
Change-Id: Iac6cd90f159765fc8a56a9a766130851bd6177b0
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2402289
Auto-Submit: Bo <boliu@chromium.org>
Commit-Queue: Timothy Dresser <tdresser@chromium.org>
Reviewed-by: default avatarTimothy Dresser <tdresser@chromium.org>
Reviewed-by: default avatarScott Violet <sky@chromium.org>
Reviewed-by: default avatarKhushal <khushalsagar@chromium.org>
Cr-Commit-Position: refs/heads/master@{#806630}
parent ed7a9bd7
......@@ -2080,13 +2080,17 @@ bool RenderWidgetHostViewAndroid::RequiresDoubleTapGestureEvents() const {
return true;
}
void RenderWidgetHostViewAndroid::OnPhysicalBackingSizeChanged() {
void RenderWidgetHostViewAndroid::OnPhysicalBackingSizeChanged(
base::Optional<base::TimeDelta> deadline_override) {
// We may need to update the background color to match pre-surface-sync
// behavior of EvictFrameIfNecessary.
UpdateWebViewBackgroundColorIfNecessary();
int64_t deadline_in_frames =
deadline_override ? ui::DelegatedFrameHostAndroid::TimeDeltaToFrames(
deadline_override.value())
: ui::DelegatedFrameHostAndroid::ResizeTimeoutFrames();
SynchronizeVisualProperties(
cc::DeadlinePolicy::UseSpecifiedDeadline(
ui::DelegatedFrameHostAndroid::ResizeTimeoutFrames()),
cc::DeadlinePolicy::UseSpecifiedDeadline(deadline_in_frames),
base::nullopt);
}
......
......@@ -187,7 +187,8 @@ class CONTENT_EXPORT RenderWidgetHostViewAndroid
bool OnMouseEvent(const ui::MotionEventAndroid& m) override;
bool OnMouseWheelEvent(const ui::MotionEventAndroid& event) override;
bool OnGestureEvent(const ui::GestureEventAndroid& event) override;
void OnPhysicalBackingSizeChanged() override;
void OnPhysicalBackingSizeChanged(
base::Optional<base::TimeDelta> deadline_override) override;
// ui::ViewAndroidObserver implementation:
void OnAttachedToWindow() override;
......
......@@ -584,7 +584,8 @@ void WebContentsViewAndroid::OnSizeChanged() {
}
}
void WebContentsViewAndroid::OnPhysicalBackingSizeChanged() {
void WebContentsViewAndroid::OnPhysicalBackingSizeChanged(
base::Optional<base::TimeDelta> deadline_override) {
if (web_contents_->GetRenderWidgetHostView())
web_contents_->SendScreenRects();
}
......
......@@ -121,7 +121,8 @@ class WebContentsViewAndroid : public WebContentsView,
bool ScrollBy(float delta_x, float delta_y) override;
bool ScrollTo(float x, float y) override;
void OnSizeChanged() override;
void OnPhysicalBackingSizeChanged() override;
void OnPhysicalBackingSizeChanged(
base::Optional<base::TimeDelta> deadline_override) override;
void OnBrowserControlsHeightChanged() override;
void OnControlsResizeViewChanged() override;
......
......@@ -49,6 +49,11 @@ class UI_ANDROID_EXPORT DelegatedFrameHostAndroid
~DelegatedFrameHostAndroid() override;
static int64_t TimeDeltaToFrames(base::TimeDelta delta) {
return base::ClampRound<int64_t>(delta /
viz::BeginFrameArgs::DefaultInterval());
}
// Wait up to 5 seconds for the first frame to be produced. Having Android
// display a placeholder for a longer period of time is preferable to drawing
// nothing, and the first frame can take a while on low-end systems.
......@@ -56,8 +61,7 @@ class UI_ANDROID_EXPORT DelegatedFrameHostAndroid
return base::TimeDelta::FromSeconds(5);
}
static int64_t FirstFrameTimeoutFrames() {
return base::ClampRound<int64_t>(FirstFrameTimeout() /
viz::BeginFrameArgs::DefaultInterval());
return TimeDeltaToFrames(FirstFrameTimeout());
}
// Wait up to 1 second for a frame of the correct size to be produced. Android
......@@ -67,8 +71,7 @@ class UI_ANDROID_EXPORT DelegatedFrameHostAndroid
return base::TimeDelta::FromSeconds(1);
}
static int64_t ResizeTimeoutFrames() {
return base::ClampRound<int64_t>(ResizeTimeout() /
viz::BeginFrameArgs::DefaultInterval());
return TimeDeltaToFrames(ResizeTimeout());
}
// Advances the fallback surface to the first surface after navigation. This
......
......@@ -511,15 +511,17 @@ void ViewAndroid::DispatchOnSizeChanged() {
}
}
void ViewAndroid::OnPhysicalBackingSizeChanged(const gfx::Size& size) {
void ViewAndroid::OnPhysicalBackingSizeChanged(
const gfx::Size& size,
base::Optional<base::TimeDelta> deadline_override) {
if (physical_size_ == size)
return;
physical_size_ = size;
if (event_handler_)
event_handler_->OnPhysicalBackingSizeChanged();
event_handler_->OnPhysicalBackingSizeChanged(deadline_override);
for (auto* child : children_)
child->OnPhysicalBackingSizeChanged(size);
child->OnPhysicalBackingSizeChanged(size, deadline_override);
}
void ViewAndroid::OnControlsResizeViewChanged(bool controls_resize_view) {
......
......@@ -14,6 +14,8 @@
#include "base/callback.h"
#include "base/memory/ref_counted.h"
#include "base/observer_list.h"
#include "base/optional.h"
#include "base/time/time.h"
#include "ui/android/ui_android_export.h"
#include "ui/android/view_android_observer.h"
#include "ui/gfx/geometry/rect_f.h"
......@@ -152,7 +154,11 @@ class UI_ANDROID_EXPORT ViewAndroid {
gfx::Rect bounds() const { return bounds_; }
void OnSizeChanged(int width, int height);
void OnPhysicalBackingSizeChanged(const gfx::Size& size);
// |deadline_override| if not nullopt will be used as the cc::DeadlinePolicy
// timeout for this resize.
void OnPhysicalBackingSizeChanged(
const gfx::Size& size,
base::Optional<base::TimeDelta> deadline_override = base::nullopt);
void OnCursorChanged(const Cursor& cursor);
void OnBackgroundColorChanged(unsigned int color);
void OnTopControlsChanged(float top_controls_offset,
......
......@@ -49,7 +49,8 @@ bool EventHandlerAndroid::ScrollTo(float x, float y) {
void EventHandlerAndroid::OnSizeChanged() {}
void EventHandlerAndroid::OnPhysicalBackingSizeChanged() {}
void EventHandlerAndroid::OnPhysicalBackingSizeChanged(
base::Optional<base::TimeDelta> deadline_override) {}
void EventHandlerAndroid::OnBrowserControlsHeightChanged() {}
......
......@@ -5,6 +5,8 @@
#ifndef UI_EVENTS_ANDROID_EVENT_HANDLER_ANDROID_H_
#define UI_EVENTS_ANDROID_EVENT_HANDLER_ANDROID_H_
#include "base/optional.h"
#include "base/time/time.h"
#include "ui/events/events_export.h"
namespace ui {
......@@ -28,7 +30,8 @@ class EVENTS_EXPORT EventHandlerAndroid {
virtual bool OnMouseWheelEvent(const MotionEventAndroid& event);
virtual bool OnGestureEvent(const GestureEventAndroid& event);
virtual void OnSizeChanged();
virtual void OnPhysicalBackingSizeChanged();
virtual void OnPhysicalBackingSizeChanged(
base::Optional<base::TimeDelta> deadline_override);
virtual void OnBrowserControlsHeightChanged();
virtual void OnControlsResizeViewChanged();
......
......@@ -83,13 +83,26 @@ void ContentViewRenderView::OnPhysicalBackingSizeChanged(
JNIEnv* env,
const JavaParamRef<jobject>& jweb_contents,
jint width,
jint height) {
jint height,
jboolean for_config_change) {
bool height_changed = height_ != height;
height_ = height;
content::WebContents* web_contents =
content::WebContents::FromJavaWebContents(jweb_contents);
gfx::Size size(width, height);
web_contents->GetNativeView()->OnPhysicalBackingSizeChanged(size);
// The default resize timeout on Android is 1s. It was chosen with browser
// use case in mind where resize is rare (eg orientation change, fullscreen)
// and users are generally willing to wait for those cases instead of seeing
// a frame at the wrong size. Weblayer currently can be resized while user
// is interacting with the page, in which case the timeout is too long.
// For now, use the default long timeout only for rotation (ie config change)
// and just use a zero timeout for all other cases.
base::Optional<base::TimeDelta> override_deadline;
if (!for_config_change)
override_deadline = base::TimeDelta();
web_contents->GetNativeView()->OnPhysicalBackingSizeChanged(
size, override_deadline);
if (height_changed && !height_changed_listener_.is_null())
height_changed_listener_.Run();
......
......@@ -49,7 +49,8 @@ class ContentViewRenderView : public content::CompositorClient {
JNIEnv* env,
const base::android::JavaParamRef<jobject>& jweb_contents,
jint width,
jint height);
jint height,
jboolean for_config_change);
void SurfaceCreated(JNIEnv* env);
void SurfaceDestroyed(JNIEnv* env, jboolean cache_back_buffer);
void SurfaceChanged(JNIEnv* env,
......
......@@ -140,7 +140,8 @@ public class BrowserImpl extends IBrowser.Stub implements View.OnAttachStateChan
assert mEmbedderActivityContext == null;
mWindowAndroid = windowAndroid;
mEmbedderActivityContext = embedderAppContext;
mViewController = new BrowserViewController(windowAndroid, this, mViewControllerState);
mViewController = new BrowserViewController(
windowAndroid, this, mViewControllerState, mFragmentStoppedForConfigurationChange);
mLocaleReceiver = new LocaleChangedBroadcastReceiver(windowAndroid.getContext().get());
mPasswordEchoEnabled = null;
}
......
......@@ -87,11 +87,12 @@ public final class BrowserViewController
private boolean mCachedDoBrowserControlsShrinkRendererSize;
public BrowserViewController(FragmentWindowAndroid windowAndroid,
View.OnAttachStateChangeListener listener, @Nullable State savedState) {
View.OnAttachStateChangeListener listener, @Nullable State savedState,
boolean recreateForConfigurationChange) {
mWindowAndroid = windowAndroid;
mOnAttachedStateChangeListener = listener;
Context context = mWindowAndroid.getContext().get();
mContentViewRenderView = new ContentViewRenderView(context);
mContentViewRenderView = new ContentViewRenderView(context, recreateForConfigurationChange);
mContentViewRenderView.addOnAttachStateChangeListener(listener);
mContentViewRenderView.onNativeLibraryLoaded(
......
......@@ -9,6 +9,7 @@ import android.graphics.Color;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.SurfaceTexture;
import android.os.SystemClock;
import android.util.Size;
import android.view.Surface;
import android.view.SurfaceHolder;
......@@ -31,6 +32,7 @@ import org.chromium.components.browser_ui.widget.InsetObserverView;
import org.chromium.content_public.browser.UiThreadTaskTraits;
import org.chromium.content_public.browser.WebContents;
import org.chromium.ui.base.WindowAndroid;
import org.chromium.ui.display.DisplayAndroid;
import org.chromium.ui.resources.ResourceManager;
import java.lang.annotation.Retention;
......@@ -52,6 +54,8 @@ public class ContentViewRenderView extends RelativeLayout {
public static final int MODE_SURFACE_VIEW = 0;
public static final int MODE_TEXTURE_VIEW = 1;
private static final int CONFIG_TIMEOUT_MS = 1000;
// 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;
......@@ -85,6 +89,13 @@ public class ContentViewRenderView extends RelativeLayout {
private boolean mCompositorHasSurface;
private DisplayAndroid.DisplayAndroidObserver mDisplayAndroidObserver;
// The time stamp when a configuration was detected (if any).
// This is used along with a timeout to determine if a resize surface resize
// is due to screen rotation.
private long mConfigurationChangedTimestamp;
// Common interface to listen to surface related events.
private interface SurfaceEventListener {
void surfaceCreated();
......@@ -153,10 +164,7 @@ public class ContentViewRenderView extends RelativeLayout {
ContentViewRenderViewJni.get().surfaceChanged(mNativeContentViewRenderView,
canBeUsedWithSurfaceControl, format, width, height, surface);
mCompositorHasSurface = surface != null;
if (mWebContents != null) {
ContentViewRenderViewJni.get().onPhysicalBackingSizeChanged(
mNativeContentViewRenderView, mWebContents, width, height);
}
maybeUpdatePhysicalBackingSize(width, height);
}
@Override
......@@ -616,8 +624,11 @@ public class ContentViewRenderView extends RelativeLayout {
* hierarchy before the first draw to avoid a black flash that is seen every time a
* {@link SurfaceView} is added.
* @param context The context used to create this.
* @param recreateForConfigurationChange indicates that views are recreated after BrowserImpl
* is retained, but Activity is recreated, for a
* configuration change.
*/
public ContentViewRenderView(Context context) {
public ContentViewRenderView(Context context, boolean recreateForConfigurationChange) {
super(context);
mSurfaceParent = new SurfaceParent(context);
addView(mSurfaceParent,
......@@ -637,6 +648,7 @@ public class ContentViewRenderView extends RelativeLayout {
@Override
public void onSafeAreaChanged(Rect area) {}
});
if (recreateForConfigurationChange) updateConfigChangeTimeStamp();
}
/**
......@@ -651,6 +663,13 @@ public class ContentViewRenderView extends RelativeLayout {
assert mNativeContentViewRenderView != 0;
mWindowAndroid = rootWindow;
requestMode(mode, (Boolean result) -> {});
mDisplayAndroidObserver = new DisplayAndroid.DisplayAndroidObserver() {
@Override
public void onRotationChanged(int rotation) {
updateConfigChangeTimeStamp();
}
};
mWindowAndroid.getDisplay().addObserver(mDisplayAndroidObserver);
}
public void requestMode(@Mode int mode, ValueCallback<Boolean> callback) {
......@@ -761,6 +780,10 @@ public class ContentViewRenderView extends RelativeLayout {
mRequested = null;
mCurrent = null;
if (mDisplayAndroidObserver != null) {
mWindowAndroid.getDisplay().removeObserver(mDisplayAndroidObserver);
mDisplayAndroidObserver = null;
}
mWindowAndroid = null;
while (!mPendingRunnables.isEmpty()) {
......@@ -777,12 +800,9 @@ public class ContentViewRenderView extends RelativeLayout {
assert mNativeContentViewRenderView != 0;
mWebContents = webContents;
if (webContents != null) {
if (getWidth() != 0 && getHeight() != 0) {
updateWebContentsSize();
}
ContentViewRenderViewJni.get().onPhysicalBackingSizeChanged(
mNativeContentViewRenderView, webContents, mPhysicalWidth, mPhysicalHeight);
if (webContents != null && getWidth() != 0 && getHeight() != 0) {
updateWebContentsSize();
maybeUpdatePhysicalBackingSize(mPhysicalWidth, mPhysicalHeight);
}
ContentViewRenderViewJni.get().setCurrentWebContents(
mNativeContentViewRenderView, webContents);
......@@ -831,13 +851,25 @@ public class ContentViewRenderView extends RelativeLayout {
return inputMethodManager.isActive();
}
private void updateConfigChangeTimeStamp() {
mConfigurationChangedTimestamp = SystemClock.uptimeMillis();
}
private void maybeUpdatePhysicalBackingSize(int width, int height) {
if (mWebContents == null) return;
boolean forConfigChange =
SystemClock.uptimeMillis() - mConfigurationChangedTimestamp < CONFIG_TIMEOUT_MS;
ContentViewRenderViewJni.get().onPhysicalBackingSizeChanged(
mNativeContentViewRenderView, mWebContents, width, height, forConfigChange);
}
@NativeMethods
interface Natives {
long init(ContentViewRenderView caller, WindowAndroid rootWindow);
void destroy(long nativeContentViewRenderView);
void setCurrentWebContents(long nativeContentViewRenderView, WebContents webContents);
void onPhysicalBackingSizeChanged(
long nativeContentViewRenderView, WebContents webContents, int width, int height);
void onPhysicalBackingSizeChanged(long nativeContentViewRenderView, WebContents webContents,
int width, int height, boolean forConfigChange);
void surfaceCreated(long nativeContentViewRenderView);
void surfaceDestroyed(long nativeContentViewRenderView, boolean cacheBackBuffer);
void surfaceChanged(long nativeContentViewRenderView, boolean canBeUsedWithSurfaceControl,
......
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