Commit 432677d1 authored by Liquan (Max) Gu's avatar Liquan (Max) Gu Committed by Commit Bot

[ExpandablePaymentHandler] Remove resizing

Context:
PH UI = Expandable Payment Handler UI

Before change:
* As users drag the PH UI, the WebContents resize after users stop
dragging for 100ms.
* As the PH UI opens, the WebContents flashes. It's because the sheet's
offset keeps changing as during the opening animation. Each offset
call WebContents to resize.

After change:
* The WebContents is set to its full height all the time
(aka non-resizable).
* As the PH UI opens, the WebContents no longer flashes.

Change:
* Set ThinWebView a height only when the toolbar has been laid out or
the Tab view layout has changed.
* Remove resizing logic

Note that:
* The WebContents' full height is different from FILL_PARENT, because
at bottom-sheet's full height, the content area still have a part
extending below the screen. This is why a delicate computation for the
the height of the content visible area is still needed.

Bug: 1054562, 1037646, 999196, 1058317

Change-Id: I04bab360f65109968a240c095d9c54133ecd9566
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2083305
Commit-Queue: Liquan (Max) Gu <maxlg@chromium.org>
Reviewed-by: default avatarRouslan Solomakhin <rouslan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#747102}
parent c9a993ad
...@@ -85,7 +85,7 @@ public class PaymentHandlerCoordinator { ...@@ -85,7 +85,7 @@ public class PaymentHandlerCoordinator {
PaymentHandlerMediator mediator = new PaymentHandlerMediator(model, this::hide, PaymentHandlerMediator mediator = new PaymentHandlerMediator(model, this::hide,
mWebContents, uiObserver, activity.getActivityTab().getView(), mWebContents, uiObserver, activity.getActivityTab().getView(),
mToolbarCoordinator.getView(), mToolbarCoordinator.getShadowHeightPx()); mToolbarCoordinator.getView(), mToolbarCoordinator.getShadowHeightPx());
activity.getActivityTab().getView().addOnLayoutChangeListener(mediator); activity.getWindow().getDecorView().addOnLayoutChangeListener(mediator);
BottomSheetController bottomSheetController = activity.getBottomSheetController(); BottomSheetController bottomSheetController = activity.getBottomSheetController();
bottomSheetController.addObserver(mediator); bottomSheetController.addObserver(mediator);
mWebContents.addObserver(mediator); mWebContents.addObserver(mediator);
...@@ -104,7 +104,9 @@ public class PaymentHandlerCoordinator { ...@@ -104,7 +104,9 @@ public class PaymentHandlerCoordinator {
bottomSheetController.hideContent(/*content=*/view, /*animate=*/true); bottomSheetController.hideContent(/*content=*/view, /*animate=*/true);
mWebContents.destroy(); mWebContents.destroy();
uiObserver.onPaymentHandlerUiClosed(); uiObserver.onPaymentHandlerUiClosed();
activity.getActivityTab().getView().removeOnLayoutChangeListener(mediator); assert activity.getWindow() != null;
assert activity.getWindow().getDecorView() != null;
activity.getWindow().getDecorView().removeOnLayoutChangeListener(mediator);
mediator.destroy(); mediator.destroy();
}; };
return bottomSheetController.requestShowContent(view, /*animate=*/true); return bottomSheetController.requestShowContent(view, /*animate=*/true);
......
...@@ -27,6 +27,9 @@ import org.chromium.ui.modelutil.PropertyModel; ...@@ -27,6 +27,9 @@ import org.chromium.ui.modelutil.PropertyModel;
*/ */
/* package */ class PaymentHandlerMediator extends WebContentsObserver /* package */ class PaymentHandlerMediator extends WebContentsObserver
implements BottomSheetObserver, PaymentHandlerToolbarObserver, View.OnLayoutChangeListener { implements BottomSheetObserver, PaymentHandlerToolbarObserver, View.OnLayoutChangeListener {
// The value is picked in order to allow users to see the tab behind this UI.
private static final float FULL_HEIGHT_RATIO = 0.9f;
private final PropertyModel mModel; private final PropertyModel mModel;
// Whenever invoked, invoked outside of the WebContentsObserver callbacks. // Whenever invoked, invoked outside of the WebContentsObserver callbacks.
private final Runnable mHider; private final Runnable mHider;
...@@ -42,6 +45,7 @@ import org.chromium.ui.modelutil.PropertyModel; ...@@ -42,6 +45,7 @@ import org.chromium.ui.modelutil.PropertyModel;
private final int mShadowHeightPx; private final int mShadowHeightPx;
private final View mToolbarView; private final View mToolbarView;
private final View mTabView; private final View mTabView;
private boolean mHasToolbarLaidOut;
/** /**
* Build a new mediator that handle events from outside the payment handler component. * Build a new mediator that handle events from outside the payment handler component.
...@@ -60,6 +64,7 @@ import org.chromium.ui.modelutil.PropertyModel; ...@@ -60,6 +64,7 @@ import org.chromium.ui.modelutil.PropertyModel;
View toolbarView, int shadowHeightPx) { View toolbarView, int shadowHeightPx) {
super(webContents); super(webContents);
assert webContents != null; assert webContents != null;
mHasToolbarLaidOut = false;
mTabView = tabView; mTabView = tabView;
mShadowHeightPx = shadowHeightPx; mShadowHeightPx = shadowHeightPx;
mWebContentsRef = webContents; mWebContentsRef = webContents;
...@@ -76,9 +81,15 @@ import org.chromium.ui.modelutil.PropertyModel; ...@@ -76,9 +81,15 @@ import org.chromium.ui.modelutil.PropertyModel;
} }
// View.OnLayoutChangeListener: // View.OnLayoutChangeListener:
// This is the Tab View's layout change listener, invoked in response to phone rotation.
// TODO(crbug.com/1057825): It should listen to the BottomSheet container's layout change
// instead of the Tab View layout change for better encapsulation.
@Override @Override
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
int oldTop, int oldRight, int oldBottom) { int oldTop, int oldRight, int oldBottom) {
// Early return because this callback can be invoked before the toolbar has been laid out.
if (!mHasToolbarLaidOut) return;
mModel.set(PaymentHandlerProperties.CONTENT_VISIBLE_HEIGHT_PX, contentVisibleHeight()); mModel.set(PaymentHandlerProperties.CONTENT_VISIBLE_HEIGHT_PX, contentVisibleHeight());
} }
...@@ -99,17 +110,14 @@ import org.chromium.ui.modelutil.PropertyModel; ...@@ -99,17 +110,14 @@ import org.chromium.ui.modelutil.PropertyModel;
return point[1]; return point[1];
} }
/** @return The height of the content visible area of PaymentHandlerView.*/ /** @return The height of visible area of the bottom sheet's content part. */
private int contentVisibleHeight() { private int contentVisibleHeight() {
int tabViewBottom = getYLocationOnScreen(mTabView) + mTabView.getHeight(); return (int) (mTabView.getHeight() * FULL_HEIGHT_RATIO) - mToolbarView.getHeight()
int toolbarBottom = getYLocationOnScreen(mToolbarView) + mToolbarView.getHeight(); + mShadowHeightPx;
// Exclude the shadow height because the toolbar view height includes it.
return tabViewBottom - toolbarBottom + mShadowHeightPx;
} }
@Override @Override
public void onSheetOffsetChanged(float heightFraction, float offsetPx) { public void onSheetOffsetChanged(float heightFraction, float offsetPx) {
mModel.set(PaymentHandlerProperties.CONTENT_VISIBLE_HEIGHT_PX, contentVisibleHeight());
} }
@Override @Override
...@@ -182,4 +190,10 @@ import org.chromium.ui.modelutil.PropertyModel; ...@@ -182,4 +190,10 @@ import org.chromium.ui.modelutil.PropertyModel;
ServiceWorkerPaymentAppBridge.onClosingPaymentAppWindow(mWebContentsRef); ServiceWorkerPaymentAppBridge.onClosingPaymentAppWindow(mWebContentsRef);
mHandler.post(mHider); mHandler.post(mHider);
} }
@Override
public void onToolbarLaidOut() {
mHasToolbarLaidOut = true;
mModel.set(PaymentHandlerProperties.CONTENT_VISIBLE_HEIGHT_PX, contentVisibleHeight());
}
} }
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
package org.chromium.chrome.browser.payments.handler; package org.chromium.chrome.browser.payments.handler;
import android.os.Handler;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
...@@ -33,7 +32,6 @@ import org.chromium.ui.base.ActivityWindowAndroid; ...@@ -33,7 +32,6 @@ import org.chromium.ui.base.ActivityWindowAndroid;
private final FrameLayout mContentView; private final FrameLayout mContentView;
private final ThinWebView mThinWebView; private final ThinWebView mThinWebView;
private final WebContents mWebContents; private final WebContents mWebContents;
private final Handler mReflowHandler = new Handler();
private final int mTabHeight; private final int mTabHeight;
private final int mToolbarHeightPx; private final int mToolbarHeightPx;
private final ChromeActivity mActivity; private final ChromeActivity mActivity;
...@@ -85,13 +83,6 @@ import org.chromium.ui.base.ActivityWindowAndroid; ...@@ -85,13 +83,6 @@ import org.chromium.ui.base.ActivityWindowAndroid;
* in pixels. * in pixels.
*/ */
/* package */ void onContentVisibleHeightChanged(int heightPx) { /* package */ void onContentVisibleHeightChanged(int heightPx) {
// Reflow the web-content when the bottom-sheet size stops changing.
mReflowHandler.removeCallbacksAndMessages(null);
mReflowHandler.postDelayed(() -> reflowWebContents(heightPx), /*delayMillis=*/100);
}
/* Resize ThinWebView to reflow the web-contents. */
private void reflowWebContents(int heightPx) {
// Scale mThinWebView to make the web-content fit into the visible content area of the // Scale mThinWebView to make the web-content fit into the visible content area of the
// PaymentHandler UI. // PaymentHandler UI.
if (mThinWebView.getView() == null || mWebContents.isDestroyed()) return; if (mThinWebView.getView() == null || mWebContents.isDestroyed()) return;
...@@ -118,7 +109,7 @@ import org.chromium.ui.base.ActivityWindowAndroid; ...@@ -118,7 +109,7 @@ import org.chromium.ui.base.ActivityWindowAndroid;
@Override @Override
public float getFullHeightRatio() { public float getFullHeightRatio() {
return 0.9f; return BottomSheetContent.HeightMode.WRAP_CONTENT;
} }
@Override @Override
...@@ -135,7 +126,6 @@ import org.chromium.ui.base.ActivityWindowAndroid; ...@@ -135,7 +126,6 @@ import org.chromium.ui.base.ActivityWindowAndroid;
@Override @Override
public void destroy() { public void destroy() {
mReflowHandler.removeCallbacksAndMessages(null);
mThinWebView.destroy(); mThinWebView.destroy();
} }
......
...@@ -5,13 +5,10 @@ ...@@ -5,13 +5,10 @@
package org.chromium.chrome.browser.payments.handler.toolbar; package org.chromium.chrome.browser.payments.handler.toolbar;
import android.view.View; import android.view.View;
import android.view.View.OnClickListener;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import org.chromium.chrome.browser.ChromeActivity; import org.chromium.chrome.browser.ChromeActivity;
import org.chromium.chrome.browser.offlinepages.OfflinePageUtils;
import org.chromium.chrome.browser.page_info.PageInfoController;
import org.chromium.components.security_state.ConnectionSecurityLevel; import org.chromium.components.security_state.ConnectionSecurityLevel;
import org.chromium.content_public.browser.WebContents; import org.chromium.content_public.browser.WebContents;
import org.chromium.ui.base.DeviceFormFactor; import org.chromium.ui.base.DeviceFormFactor;
...@@ -40,6 +37,12 @@ public class PaymentHandlerToolbarCoordinator { ...@@ -40,6 +37,12 @@ public class PaymentHandlerToolbarCoordinator {
/** Called when the close button is clicked. */ /** Called when the close button is clicked. */
void onToolbarCloseButtonClicked(); void onToolbarCloseButtonClicked();
/**
* Called when the toolbar has just laid out, called exactly once, because it's used only
* for calculating the height, which does not change in the toolbar after the first layout.
*/
void onToolbarLaidOut();
} }
/** /**
...@@ -53,14 +56,6 @@ public class PaymentHandlerToolbarCoordinator { ...@@ -53,14 +56,6 @@ public class PaymentHandlerToolbarCoordinator {
public PaymentHandlerToolbarCoordinator( public PaymentHandlerToolbarCoordinator(
ChromeActivity context, WebContents webContents, URI url) { ChromeActivity context, WebContents webContents, URI url) {
mWebContents = webContents; mWebContents = webContents;
OnClickListener securityIconOnClickListener = v -> {
if (context == null) return;
PageInfoController.show(context, webContents, null,
PageInfoController.OpenedFromSource.TOOLBAR,
/*offlinePageLoadUrlDelegate=*/
new OfflinePageUtils.WebContentsOfflinePageLoadUrlDelegate(webContents));
};
mToolbarView = new PaymentHandlerToolbarView(context, securityIconOnClickListener);
PropertyModel model = new PropertyModel.Builder(PaymentHandlerToolbarProperties.ALL_KEYS) PropertyModel model = new PropertyModel.Builder(PaymentHandlerToolbarProperties.ALL_KEYS)
.with(PaymentHandlerToolbarProperties.PROGRESS_VISIBLE, true) .with(PaymentHandlerToolbarProperties.PROGRESS_VISIBLE, true)
.with(PaymentHandlerToolbarProperties.LOAD_PROGRESS, .with(PaymentHandlerToolbarProperties.LOAD_PROGRESS,
...@@ -70,7 +65,9 @@ public class PaymentHandlerToolbarCoordinator { ...@@ -70,7 +65,9 @@ public class PaymentHandlerToolbarCoordinator {
.with(PaymentHandlerToolbarProperties.URL, url) .with(PaymentHandlerToolbarProperties.URL, url)
.build(); .build();
boolean isSmallDevice = !DeviceFormFactor.isNonMultiDisplayContextOnTablet(context); boolean isSmallDevice = !DeviceFormFactor.isNonMultiDisplayContextOnTablet(context);
mMediator = new PaymentHandlerToolbarMediator(model, webContents, isSmallDevice); mMediator = new PaymentHandlerToolbarMediator(model, context, webContents, isSmallDevice);
mToolbarView =
new PaymentHandlerToolbarView(context, /*securityIconOnClickListener=*/mMediator);
webContents.addObserver(mMediator); webContents.addObserver(mMediator);
PropertyModelChangeProcessor changeProcessor = PropertyModelChangeProcessor.create( PropertyModelChangeProcessor changeProcessor = PropertyModelChangeProcessor.create(
model, mToolbarView, PaymentHandlerToolbarViewBinder::bind); model, mToolbarView, PaymentHandlerToolbarViewBinder::bind);
......
...@@ -6,8 +6,12 @@ package org.chromium.chrome.browser.payments.handler.toolbar; ...@@ -6,8 +6,12 @@ package org.chromium.chrome.browser.payments.handler.toolbar;
import android.os.Handler; import android.os.Handler;
import android.support.annotation.DrawableRes; import android.support.annotation.DrawableRes;
import android.view.View;
import org.chromium.base.Log; import org.chromium.base.Log;
import org.chromium.chrome.browser.ChromeActivity;
import org.chromium.chrome.browser.offlinepages.OfflinePageUtils;
import org.chromium.chrome.browser.page_info.PageInfoController;
import org.chromium.chrome.browser.payments.handler.toolbar.PaymentHandlerToolbarCoordinator.PaymentHandlerToolbarObserver; import org.chromium.chrome.browser.payments.handler.toolbar.PaymentHandlerToolbarCoordinator.PaymentHandlerToolbarObserver;
import org.chromium.chrome.browser.ssl.ChromeSecurityStateModelDelegate; import org.chromium.chrome.browser.ssl.ChromeSecurityStateModelDelegate;
import org.chromium.components.omnibox.SecurityStatusIcon; import org.chromium.components.omnibox.SecurityStatusIcon;
...@@ -25,7 +29,8 @@ import java.net.URISyntaxException; ...@@ -25,7 +29,8 @@ import java.net.URISyntaxException;
* PaymentHandlerToolbar mediator, which is responsible for receiving events from the view and * PaymentHandlerToolbar mediator, which is responsible for receiving events from the view and
* notifies the backend (the coordinator). * notifies the backend (the coordinator).
*/ */
/* package */ class PaymentHandlerToolbarMediator extends WebContentsObserver { /* package */ class PaymentHandlerToolbarMediator
extends WebContentsObserver implements View.OnClickListener {
// Abbreviated for the length limit. // Abbreviated for the length limit.
private static final String TAG = "PaymentHandlerTb"; private static final String TAG = "PaymentHandlerTb";
/** The delay (four video frames - for 60Hz) after which the hide progress will be hidden. */ /** The delay (four video frames - for 60Hz) after which the hide progress will be hidden. */
...@@ -43,20 +48,23 @@ import java.net.URISyntaxException; ...@@ -43,20 +48,23 @@ import java.net.URISyntaxException;
/** Postfixed with "Ref" to distinguish from mWebContent in WebContentsObserver. */ /** Postfixed with "Ref" to distinguish from mWebContent in WebContentsObserver. */
private final WebContents mWebContentsRef; private final WebContents mWebContentsRef;
private final boolean mIsSmallDevice; private final boolean mIsSmallDevice;
private final ChromeActivity mChromeActivity;
/** /**
* Build a new mediator that handle events from outside the payment handler toolbar component. * Build a new mediator that handle events from outside the payment handler toolbar component.
* @param model The {@link PaymentHandlerToolbarProperties} that holds all the view state for * @param model The {@link PaymentHandlerToolbarProperties} that holds all the view state for
* the payment handler toolbar component. * the payment handler toolbar component.
* @param chromeActivity The {@link ChromeActivity}.
* @param webContents The web-contents that loads the payment app. * @param webContents The web-contents that loads the payment app.
* @param isSmallDevice Whether the device screen is considered small. * @param isSmallDevice Whether the device screen is considered small.
*/ */
/* package */ PaymentHandlerToolbarMediator( /* package */ PaymentHandlerToolbarMediator(PropertyModel model, ChromeActivity chromeActivity,
PropertyModel model, WebContents webContents, boolean isSmallDevice) { WebContents webContents, boolean isSmallDevice) {
super(webContents); super(webContents);
mIsSmallDevice = isSmallDevice; mIsSmallDevice = isSmallDevice;
mWebContentsRef = webContents; mWebContentsRef = webContents;
mModel = model; mModel = model;
mChromeActivity = chromeActivity;
} }
/** Set an observer for this class. */ /** Set an observer for this class. */
...@@ -137,4 +145,14 @@ import java.net.URISyntaxException; ...@@ -137,4 +145,14 @@ import java.net.URISyntaxException;
mModel.set(PaymentHandlerToolbarProperties.SECURITY_ICON, mModel.set(PaymentHandlerToolbarProperties.SECURITY_ICON,
getSecurityIconResource(securityLevel)); getSecurityIconResource(securityLevel));
} }
// (PaymentHandlerToolbarView security icon's) OnClickListener:
@Override
public void onClick(View view) {
if (mChromeActivity == null) return;
PageInfoController.show(mChromeActivity, mWebContentsRef, null,
PageInfoController.OpenedFromSource.TOOLBAR,
/*offlinePageLoadUrlDelegate=*/
new OfflinePageUtils.WebContentsOfflinePageLoadUrlDelegate(mWebContentsRef));
};
} }
...@@ -8,6 +8,7 @@ import android.content.Context; ...@@ -8,6 +8,7 @@ import android.content.Context;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.View.OnClickListener; import android.view.View.OnClickListener;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.ProgressBar; import android.widget.ProgressBar;
import android.widget.TextView; import android.widget.TextView;
...@@ -19,7 +20,7 @@ import org.chromium.components.browser_ui.widget.FadingShadow; ...@@ -19,7 +20,7 @@ import org.chromium.components.browser_ui.widget.FadingShadow;
import org.chromium.components.browser_ui.widget.FadingShadowView; import org.chromium.components.browser_ui.widget.FadingShadowView;
/** PaymentHandlerToolbar UI. */ /** PaymentHandlerToolbar UI. */
/* package */ class PaymentHandlerToolbarView { /* package */ class PaymentHandlerToolbarView implements OnGlobalLayoutListener {
private final int mToolbarHeightPx; private final int mToolbarHeightPx;
private final int mShadowHeightPx; private final int mShadowHeightPx;
...@@ -45,6 +46,8 @@ import org.chromium.components.browser_ui.widget.FadingShadowView; ...@@ -45,6 +46,8 @@ import org.chromium.components.browser_ui.widget.FadingShadowView;
context.getResources().getDimensionPixelSize(R.dimen.action_bar_shadow_height); context.getResources().getDimensionPixelSize(R.dimen.action_bar_shadow_height);
mToolbarView = LayoutInflater.from(context).inflate(R.layout.sheet_tab_toolbar, null); mToolbarView = LayoutInflater.from(context).inflate(R.layout.sheet_tab_toolbar, null);
mToolbarView.getViewTreeObserver().addOnGlobalLayoutListener(this);
mOriginView = mToolbarView.findViewById(R.id.origin); mOriginView = mToolbarView.findViewById(R.id.origin);
mTitleView = mToolbarView.findViewById(R.id.title); mTitleView = mToolbarView.findViewById(R.id.title);
mProgressBar = mToolbarView.findViewById(R.id.progress_bar); mProgressBar = mToolbarView.findViewById(R.id.progress_bar);
...@@ -85,4 +88,11 @@ import org.chromium.components.browser_ui.widget.FadingShadowView; ...@@ -85,4 +88,11 @@ import org.chromium.components.browser_ui.widget.FadingShadowView;
/* package */ View getView() { /* package */ View getView() {
return mToolbarView; return mToolbarView;
} }
// OnGlobalLayoutListener:
@Override
public void onGlobalLayout() {
mObserver.onToolbarLaidOut();
mToolbarView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
} }
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