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 {
PaymentHandlerMediator mediator = new PaymentHandlerMediator(model, this::hide,
mWebContents, uiObserver, activity.getActivityTab().getView(),
mToolbarCoordinator.getView(), mToolbarCoordinator.getShadowHeightPx());
activity.getActivityTab().getView().addOnLayoutChangeListener(mediator);
activity.getWindow().getDecorView().addOnLayoutChangeListener(mediator);
BottomSheetController bottomSheetController = activity.getBottomSheetController();
bottomSheetController.addObserver(mediator);
mWebContents.addObserver(mediator);
......@@ -104,7 +104,9 @@ public class PaymentHandlerCoordinator {
bottomSheetController.hideContent(/*content=*/view, /*animate=*/true);
mWebContents.destroy();
uiObserver.onPaymentHandlerUiClosed();
activity.getActivityTab().getView().removeOnLayoutChangeListener(mediator);
assert activity.getWindow() != null;
assert activity.getWindow().getDecorView() != null;
activity.getWindow().getDecorView().removeOnLayoutChangeListener(mediator);
mediator.destroy();
};
return bottomSheetController.requestShowContent(view, /*animate=*/true);
......
......@@ -27,6 +27,9 @@ import org.chromium.ui.modelutil.PropertyModel;
*/
/* package */ class PaymentHandlerMediator extends WebContentsObserver
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;
// Whenever invoked, invoked outside of the WebContentsObserver callbacks.
private final Runnable mHider;
......@@ -42,6 +45,7 @@ import org.chromium.ui.modelutil.PropertyModel;
private final int mShadowHeightPx;
private final View mToolbarView;
private final View mTabView;
private boolean mHasToolbarLaidOut;
/**
* Build a new mediator that handle events from outside the payment handler component.
......@@ -60,6 +64,7 @@ import org.chromium.ui.modelutil.PropertyModel;
View toolbarView, int shadowHeightPx) {
super(webContents);
assert webContents != null;
mHasToolbarLaidOut = false;
mTabView = tabView;
mShadowHeightPx = shadowHeightPx;
mWebContentsRef = webContents;
......@@ -76,9 +81,15 @@ import org.chromium.ui.modelutil.PropertyModel;
}
// 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
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
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());
}
......@@ -99,17 +110,14 @@ import org.chromium.ui.modelutil.PropertyModel;
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() {
int tabViewBottom = getYLocationOnScreen(mTabView) + mTabView.getHeight();
int toolbarBottom = getYLocationOnScreen(mToolbarView) + mToolbarView.getHeight();
// Exclude the shadow height because the toolbar view height includes it.
return tabViewBottom - toolbarBottom + mShadowHeightPx;
return (int) (mTabView.getHeight() * FULL_HEIGHT_RATIO) - mToolbarView.getHeight()
+ mShadowHeightPx;
}
@Override
public void onSheetOffsetChanged(float heightFraction, float offsetPx) {
mModel.set(PaymentHandlerProperties.CONTENT_VISIBLE_HEIGHT_PX, contentVisibleHeight());
}
@Override
......@@ -182,4 +190,10 @@ import org.chromium.ui.modelutil.PropertyModel;
ServiceWorkerPaymentAppBridge.onClosingPaymentAppWindow(mWebContentsRef);
mHandler.post(mHider);
}
@Override
public void onToolbarLaidOut() {
mHasToolbarLaidOut = true;
mModel.set(PaymentHandlerProperties.CONTENT_VISIBLE_HEIGHT_PX, contentVisibleHeight());
}
}
......@@ -4,7 +4,6 @@
package org.chromium.chrome.browser.payments.handler;
import android.os.Handler;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
......@@ -33,7 +32,6 @@ import org.chromium.ui.base.ActivityWindowAndroid;
private final FrameLayout mContentView;
private final ThinWebView mThinWebView;
private final WebContents mWebContents;
private final Handler mReflowHandler = new Handler();
private final int mTabHeight;
private final int mToolbarHeightPx;
private final ChromeActivity mActivity;
......@@ -85,13 +83,6 @@ import org.chromium.ui.base.ActivityWindowAndroid;
* in pixels.
*/
/* 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
// PaymentHandler UI.
if (mThinWebView.getView() == null || mWebContents.isDestroyed()) return;
......@@ -118,7 +109,7 @@ import org.chromium.ui.base.ActivityWindowAndroid;
@Override
public float getFullHeightRatio() {
return 0.9f;
return BottomSheetContent.HeightMode.WRAP_CONTENT;
}
@Override
......@@ -135,7 +126,6 @@ import org.chromium.ui.base.ActivityWindowAndroid;
@Override
public void destroy() {
mReflowHandler.removeCallbacksAndMessages(null);
mThinWebView.destroy();
}
......
......@@ -5,13 +5,10 @@
package org.chromium.chrome.browser.payments.handler.toolbar;
import android.view.View;
import android.view.View.OnClickListener;
import androidx.annotation.VisibleForTesting;
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.content_public.browser.WebContents;
import org.chromium.ui.base.DeviceFormFactor;
......@@ -40,6 +37,12 @@ public class PaymentHandlerToolbarCoordinator {
/** Called when the close button is clicked. */
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 {
public PaymentHandlerToolbarCoordinator(
ChromeActivity context, WebContents webContents, URI url) {
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)
.with(PaymentHandlerToolbarProperties.PROGRESS_VISIBLE, true)
.with(PaymentHandlerToolbarProperties.LOAD_PROGRESS,
......@@ -70,7 +65,9 @@ public class PaymentHandlerToolbarCoordinator {
.with(PaymentHandlerToolbarProperties.URL, url)
.build();
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);
PropertyModelChangeProcessor changeProcessor = PropertyModelChangeProcessor.create(
model, mToolbarView, PaymentHandlerToolbarViewBinder::bind);
......
......@@ -6,8 +6,12 @@ package org.chromium.chrome.browser.payments.handler.toolbar;
import android.os.Handler;
import android.support.annotation.DrawableRes;
import android.view.View;
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.ssl.ChromeSecurityStateModelDelegate;
import org.chromium.components.omnibox.SecurityStatusIcon;
......@@ -25,7 +29,8 @@ import java.net.URISyntaxException;
* PaymentHandlerToolbar mediator, which is responsible for receiving events from the view and
* notifies the backend (the coordinator).
*/
/* package */ class PaymentHandlerToolbarMediator extends WebContentsObserver {
/* package */ class PaymentHandlerToolbarMediator
extends WebContentsObserver implements View.OnClickListener {
// Abbreviated for the length limit.
private static final String TAG = "PaymentHandlerTb";
/** The delay (four video frames - for 60Hz) after which the hide progress will be hidden. */
......@@ -43,20 +48,23 @@ import java.net.URISyntaxException;
/** Postfixed with "Ref" to distinguish from mWebContent in WebContentsObserver. */
private final WebContents mWebContentsRef;
private final boolean mIsSmallDevice;
private final ChromeActivity mChromeActivity;
/**
* 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
* the payment handler toolbar component.
* @param chromeActivity The {@link ChromeActivity}.
* @param webContents The web-contents that loads the payment app.
* @param isSmallDevice Whether the device screen is considered small.
*/
/* package */ PaymentHandlerToolbarMediator(
PropertyModel model, WebContents webContents, boolean isSmallDevice) {
/* package */ PaymentHandlerToolbarMediator(PropertyModel model, ChromeActivity chromeActivity,
WebContents webContents, boolean isSmallDevice) {
super(webContents);
mIsSmallDevice = isSmallDevice;
mWebContentsRef = webContents;
mModel = model;
mChromeActivity = chromeActivity;
}
/** Set an observer for this class. */
......@@ -137,4 +145,14 @@ import java.net.URISyntaxException;
mModel.set(PaymentHandlerToolbarProperties.SECURITY_ICON,
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;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
......@@ -19,7 +20,7 @@ import org.chromium.components.browser_ui.widget.FadingShadow;
import org.chromium.components.browser_ui.widget.FadingShadowView;
/** PaymentHandlerToolbar UI. */
/* package */ class PaymentHandlerToolbarView {
/* package */ class PaymentHandlerToolbarView implements OnGlobalLayoutListener {
private final int mToolbarHeightPx;
private final int mShadowHeightPx;
......@@ -45,6 +46,8 @@ import org.chromium.components.browser_ui.widget.FadingShadowView;
context.getResources().getDimensionPixelSize(R.dimen.action_bar_shadow_height);
mToolbarView = LayoutInflater.from(context).inflate(R.layout.sheet_tab_toolbar, null);
mToolbarView.getViewTreeObserver().addOnGlobalLayoutListener(this);
mOriginView = mToolbarView.findViewById(R.id.origin);
mTitleView = mToolbarView.findViewById(R.id.title);
mProgressBar = mToolbarView.findViewById(R.id.progress_bar);
......@@ -85,4 +88,11 @@ import org.chromium.components.browser_ui.widget.FadingShadowView;
/* package */ View getView() {
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