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

[PaymentHandler] Add web-content to bottom-sheet

As part of the Scroll-to-expand payment handler project, this patch
will embed the web-content of the payment handler web-app into the
payment-handler bottom-sheet.

This patch also adds the CustomTabToolbar view (without the coordinator
yet) as the payment-handler's toolbar.

Bug: 999196

Change-Id: I403de9c01c3598bb120f0fb51dc7872adda8c8a7
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1872167
Commit-Queue: Liquan (Max) Gu <maxlg@chromium.org>
Reviewed-by: default avatarDanyao Wang <danyao@chromium.org>
Reviewed-by: default avatarMatthew Jones <mdjones@chromium.org>
Reviewed-by: default avatarRouslan Solomakhin <rouslan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#709082}
parent 15d575f9
...@@ -2,9 +2,13 @@ ...@@ -2,9 +2,13 @@
<!-- Copyright 2019 The Chromium Authors. All rights reserved. <!-- Copyright 2019 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file. --> found in the LICENSE file. -->
<RelativeLayout <FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:background="@color/sheet_bg_color" android:background="@color/sheet_bg_color"
android:layout_height="match_parent" android:layout_width="match_parent"
android:layout_width="match_parent"> android:layout_height="match_parent">
</RelativeLayout> <org.chromium.chrome.browser.ui.widget.FadingShadowView
android:id="@+id/shadow"
android:layout_width="match_parent"
android:layout_height="@dimen/action_bar_shadow_height"/>
</FrameLayout>
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2019 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file. -->
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</RelativeLayout>
...@@ -1189,7 +1189,8 @@ public class PaymentRequestImpl ...@@ -1189,7 +1189,8 @@ public class PaymentRequestImpl
mPaymentHandlerUi = new PaymentHandlerCoordinator(); mPaymentHandlerUi = new PaymentHandlerCoordinator();
ChromeActivity chromeActivity = ChromeActivity.fromWebContents(mWebContents); ChromeActivity chromeActivity = ChromeActivity.fromWebContents(mWebContents);
if (chromeActivity == null) return false; if (chromeActivity == null) return false;
return mPaymentHandlerUi.show(chromeActivity, this::onPaymentHandlerUiDismissed); return mPaymentHandlerUi.show(
chromeActivity, this::onPaymentHandlerUiDismissed, url, mIsIncognito);
} }
private void onPaymentHandlerUiDismissed() { private void onPaymentHandlerUiDismissed() {
......
...@@ -6,10 +6,18 @@ package org.chromium.chrome.browser.payments.handler; ...@@ -6,10 +6,18 @@ package org.chromium.chrome.browser.payments.handler;
import org.chromium.chrome.browser.ChromeActivity; import org.chromium.chrome.browser.ChromeActivity;
import org.chromium.chrome.browser.ChromeFeatureList; import org.chromium.chrome.browser.ChromeFeatureList;
import org.chromium.chrome.browser.ChromeVersionInfo;
import org.chromium.chrome.browser.WebContentsFactory;
import org.chromium.chrome.browser.widget.bottomsheet.BottomSheetController; import org.chromium.chrome.browser.widget.bottomsheet.BottomSheetController;
import org.chromium.components.embedder_support.view.ContentView;
import org.chromium.content_public.browser.LoadUrlParams;
import org.chromium.content_public.browser.WebContents;
import org.chromium.ui.base.ViewAndroidDelegate;
import org.chromium.ui.modelutil.PropertyModel; import org.chromium.ui.modelutil.PropertyModel;
import org.chromium.ui.modelutil.PropertyModelChangeProcessor; import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
import java.net.URI;
/** /**
* PaymentHandler coordinator, which owns the component overall, i.e., creates other objects in the * PaymentHandler coordinator, which owns the component overall, i.e., creates other objects in the
* component and connects them. It decouples the implementation of this component from other * component and connects them. It decouples the implementation of this component from other
...@@ -18,6 +26,7 @@ import org.chromium.ui.modelutil.PropertyModelChangeProcessor; ...@@ -18,6 +26,7 @@ import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
*/ */
public class PaymentHandlerCoordinator { public class PaymentHandlerCoordinator {
private Runnable mHider; private Runnable mHider;
private WebContents mWebContents;
/** Observer for the dismissal of the payment-handler UI. */ /** Observer for the dismissal of the payment-handler UI. */
public interface DismissObserver { public interface DismissObserver {
...@@ -36,23 +45,38 @@ public class PaymentHandlerCoordinator { ...@@ -36,23 +45,38 @@ public class PaymentHandlerCoordinator {
/** /**
* Shows the payment-handler UI. * Shows the payment-handler UI.
* *
* @param chromeActivity The activity where the UI should be shown. * @param chromeActivity The activity where the UI should be shown.
* @param dismissObserver The observer to be notified when the user has dismissed the UI. * @param dismissObserver The observer to be notified when the user has dismissed the UI.
* @param url The url of the payment handler app, i.e., that of
* "PaymentRequestEvent.openWindow(url)".
* @param isIncognito Whether the tab is in incognito mode.
* @return Whether the payment-handler UI was shown. Can be false if the UI was suppressed. * @return Whether the payment-handler UI was shown. Can be false if the UI was suppressed.
*/ */
public boolean show(ChromeActivity activity, DismissObserver dismissObserver) { public boolean show(ChromeActivity activity, DismissObserver dismissObserver, URI url,
boolean isIncognito) {
assert mHider == null : "Already showing payment-handler UI"; assert mHider == null : "Already showing payment-handler UI";
PaymentHandlerMediator mediator = new PaymentHandlerMediator(this::hide, dismissObserver); PropertyModel model = new PropertyModel.Builder(PaymentHandlerProperties.ALL_KEYS).build();
PaymentHandlerMediator mediator =
new PaymentHandlerMediator(model, this::hide, dismissObserver);
BottomSheetController bottomSheetController = activity.getBottomSheetController(); BottomSheetController bottomSheetController = activity.getBottomSheetController();
bottomSheetController.getBottomSheet().addObserver(mediator); bottomSheetController.getBottomSheet().addObserver(mediator);
PropertyModel model = new PropertyModel.Builder(PaymentHandlerProperties.ALL_KEYS).build();
PaymentHandlerView view = new PaymentHandlerView(activity); mWebContents = WebContentsFactory.createWebContents(isIncognito, /*initiallyHidden=*/false);
ContentView webContentView = ContentView.createContentView(activity, mWebContents);
mWebContents.initialize(ChromeVersionInfo.getProductVersion(),
ViewAndroidDelegate.createBasicDelegate(webContentView), webContentView,
activity.getWindowAndroid(), WebContents.createDefaultInternalsHolder());
mWebContents.getNavigationController().loadUrl(new LoadUrlParams(url.toString()));
PaymentHandlerView view = new PaymentHandlerView(
activity, bottomSheetController.getBottomSheet(), mWebContents, webContentView);
PropertyModelChangeProcessor changeProcessor = PropertyModelChangeProcessor changeProcessor =
PropertyModelChangeProcessor.create(model, view, PaymentHandlerViewBinder::bind); PropertyModelChangeProcessor.create(model, view, PaymentHandlerViewBinder::bind);
mHider = () -> { mHider = () -> {
changeProcessor.destroy(); changeProcessor.destroy();
bottomSheetController.getBottomSheet().removeObserver(mediator); bottomSheetController.getBottomSheet().removeObserver(mediator);
bottomSheetController.hideContent(/*content=*/view, /*animate=*/true); bottomSheetController.hideContent(/*content=*/view, /*animate=*/true);
mWebContents.destroy();
}; };
boolean result = bottomSheetController.requestShowContent(view, /*animate=*/true); boolean result = bottomSheetController.requestShowContent(view, /*animate=*/true);
if (result) bottomSheetController.expandSheet(); if (result) bottomSheetController.expandSheet();
......
...@@ -7,16 +7,20 @@ package org.chromium.chrome.browser.payments.handler; ...@@ -7,16 +7,20 @@ package org.chromium.chrome.browser.payments.handler;
import org.chromium.chrome.browser.payments.handler.PaymentHandlerCoordinator.DismissObserver; import org.chromium.chrome.browser.payments.handler.PaymentHandlerCoordinator.DismissObserver;
import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet.SheetState; import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet.SheetState;
import org.chromium.chrome.browser.widget.bottomsheet.EmptyBottomSheetObserver; import org.chromium.chrome.browser.widget.bottomsheet.EmptyBottomSheetObserver;
import org.chromium.ui.modelutil.PropertyModel;
/** /**
* PaymentHandler mediator, which is responsible for receiving events from the view and notifies the * PaymentHandler mediator, which is responsible for receiving events from the view and notifies the
* backend (the coordinator). * backend (the coordinator).
*/ */
/* package */ class PaymentHandlerMediator extends EmptyBottomSheetObserver { /* package */ class PaymentHandlerMediator extends EmptyBottomSheetObserver {
private final PropertyModel mModel;
private final Runnable mHider; private final Runnable mHider;
private final DismissObserver mDismissObserver; private final DismissObserver mDismissObserver;
/* package */ PaymentHandlerMediator(Runnable hider, DismissObserver dismissObserver) { /* package */ PaymentHandlerMediator(
PropertyModel model, Runnable hider, DismissObserver dismissObserver) {
mModel = model;
mHider = hider; mHider = hider;
mDismissObserver = dismissObserver; mDismissObserver = dismissObserver;
} }
...@@ -31,4 +35,9 @@ import org.chromium.chrome.browser.widget.bottomsheet.EmptyBottomSheetObserver; ...@@ -31,4 +35,9 @@ import org.chromium.chrome.browser.widget.bottomsheet.EmptyBottomSheetObserver;
break; break;
} }
} }
@Override
public void onSheetOffsetChanged(float heightFraction, float offsetPx) {
mModel.set(PaymentHandlerProperties.BOTTOM_SHEET_HEIGHT_FRACTION, heightFraction);
}
} }
...@@ -5,11 +5,16 @@ ...@@ -5,11 +5,16 @@
package org.chromium.chrome.browser.payments.handler; package org.chromium.chrome.browser.payments.handler;
import org.chromium.ui.modelutil.PropertyKey; import org.chromium.ui.modelutil.PropertyKey;
import org.chromium.ui.modelutil.PropertyModel.WritableFloatPropertyKey;
/** PaymentHandler UI properties, which fully describe the state of the UI. */ /** PaymentHandler UI properties, which fully describe the state of the UI. */
/* package */ class PaymentHandlerProperties { /* package */ class PaymentHandlerProperties {
// TODO(maxlg): Should add more keys after we add more states to the widget . /** The height fraction defined in {@link BottomSHeetObserver#onSheetOffsetChanged} */
/* package */ static final PropertyKey[] ALL_KEYS = new PropertyKey[] {}; /* package */ static final WritableFloatPropertyKey BOTTOM_SHEET_HEIGHT_FRACTION =
new WritableFloatPropertyKey();
/* package */ static final PropertyKey[] ALL_KEYS =
new PropertyKey[] {BOTTOM_SHEET_HEIGHT_FRACTION};
// Prevent instantiation. // Prevent instantiation.
private PaymentHandlerProperties() {} private PaymentHandlerProperties() {}
......
...@@ -4,23 +4,91 @@ ...@@ -4,23 +4,91 @@
package org.chromium.chrome.browser.payments.handler; package org.chromium.chrome.browser.payments.handler;
import android.content.Context; 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;
import android.view.ViewGroup.LayoutParams;
import android.widget.FrameLayout;
import org.chromium.base.ApiCompatibilityUtils;
import org.chromium.chrome.R; import org.chromium.chrome.R;
import org.chromium.chrome.browser.ChromeActivity;
import org.chromium.chrome.browser.thinwebview.ThinWebView;
import org.chromium.chrome.browser.thinwebview.ThinWebViewFactory;
import org.chromium.chrome.browser.ui.widget.FadingShadow;
import org.chromium.chrome.browser.ui.widget.FadingShadowView;
import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet; import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet;
import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet.BottomSheetContent; import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet.BottomSheetContent;
import org.chromium.components.embedder_support.view.ContentView;
import org.chromium.content_public.browser.WebContents;
import org.chromium.ui.base.ActivityWindowAndroid;
/** PaymentHandler UI. */ /** PaymentHandler UI. */
/* package */ class PaymentHandlerView implements BottomSheetContent { /* package */ class PaymentHandlerView implements BottomSheetContent {
private final int mToolbarHeightPx;
private final View mToolbarView; private final View mToolbarView;
private final View mContentView; private final FrameLayout mContentView;
private final ThinWebView mThinWebView;
private final Handler mReflowHandler = new Handler();
private final int mTabHeight;
/**
* Construct the PaymentHandlerView.
*
* @param activity The activity where the bottome-sheet should be shown.
* @param bottomSheet The bottom-sheet where the web-content should be shown.
* @param webContents The web-content of the payment-handler web-app.
* @param webContentView The {@link ContentView} that has been contructed with the web-content.
*/
/* package */ PaymentHandlerView(ChromeActivity activity, BottomSheet bottomSheet,
WebContents webContents, ContentView webContentView) {
mToolbarHeightPx = activity.getResources().getDimensionPixelSize(
R.dimen.custom_tabs_control_container_height);
mTabHeight = activity.getActivityTab().getHeight();
mToolbarView = LayoutInflater.from(activity).inflate(R.layout.custom_tabs_toolbar, null);
mContentView = (FrameLayout) LayoutInflater.from(activity).inflate(
R.layout.payment_handler_content, null);
mThinWebView = ThinWebViewFactory.create(activity, new ActivityWindowAndroid(activity));
initContentView(activity, mThinWebView, webContents, webContentView);
}
/**
* Initialize the content view.
*
* @param activity The activity where the bottome-sheet should be shown.
* @param thinWebView The {@link ThinWebView} that was created with the activity.
* @param webContents The web-content of the payment-handler web-app.
* @param webContentView The {@link ContentView} that has been contructed with the web-content.
*/
private void initContentView(ChromeActivity activity, ThinWebView thinWebView,
WebContents webContents, ContentView webContentView) {
FadingShadowView shadow = mContentView.findViewById(R.id.shadow);
shadow.init(ApiCompatibilityUtils.getColor(
activity.getResources(), R.color.toolbar_shadow_color),
FadingShadow.POSITION_TOP);
assert webContentView.getParent() == null;
thinWebView.attachWebContents(webContents, webContentView);
mContentView.setPadding(/*left=*/0, /*top=*/mToolbarHeightPx, /*right=*/0, /*bottom=*/0);
mContentView.addView(thinWebView.getView(), /*index=*/0);
}
/* package */ PaymentHandlerView(Context context) { /* A callback when the heightFraction property changed.*/
mToolbarView = LayoutInflater.from(context).inflate(R.layout.payment_handler_toolbar, null); /* package */ void onHeightFractionChanged(float heightFraction) {
mContentView = LayoutInflater.from(context).inflate(R.layout.payment_handler_content, null); // Reflow the web-content when the bottom-sheet size stops changing.
mReflowHandler.removeCallbacksAndMessages(null);
mReflowHandler.postDelayed(() -> reflowWebContents(heightFraction), /*delayMillis=*/100);
}
/* Resize ThinWebView to reflow the web-contents. */
private void reflowWebContents(float heightFraction) {
// Scale mThinWebView to make the web-content fit into the visible area of the bottom-sheet.
if (mThinWebView.getView() == null) return;
LayoutParams params = (LayoutParams) mThinWebView.getView().getLayoutParams();
params.height = Math.max(0, (int) (mTabHeight * heightFraction) - mToolbarHeightPx);
mThinWebView.getView().setLayoutParams(params);
} }
// BottomSheetContent: // BottomSheetContent:
...@@ -41,7 +109,10 @@ import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet.BottomSheetCon ...@@ -41,7 +109,10 @@ import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet.BottomSheetCon
} }
@Override @Override
public void destroy() {} public void destroy() {
mReflowHandler.removeCallbacksAndMessages(null);
mThinWebView.destroy();
}
@Override @Override
@BottomSheet.ContentPriority @BottomSheet.ContentPriority
...@@ -63,22 +134,22 @@ import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet.BottomSheetCon ...@@ -63,22 +134,22 @@ import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet.BottomSheetCon
@Override @Override
public int getSheetContentDescriptionStringId() { public int getSheetContentDescriptionStringId() {
return R.string.payment_request_payment_method_section_name; return R.string.payment_handler_sheet_description;
} }
@Override @Override
public int getSheetHalfHeightAccessibilityStringId() { public int getSheetHalfHeightAccessibilityStringId() {
return R.string.payment_request_payment_method_section_name; return R.string.payment_handler_sheet_opened_half;
} }
@Override @Override
public int getSheetFullHeightAccessibilityStringId() { public int getSheetFullHeightAccessibilityStringId() {
return R.string.payment_request_payment_method_section_name; return R.string.payment_handler_sheet_opened_full;
} }
@Override @Override
public int getSheetClosedAccessibilityStringId() { public int getSheetClosedAccessibilityStringId() {
return R.string.payment_request_payment_method_section_name; return R.string.payment_handler_sheet_closed;
} }
@Override @Override
......
...@@ -14,6 +14,9 @@ import org.chromium.ui.modelutil.PropertyModel; ...@@ -14,6 +14,9 @@ import org.chromium.ui.modelutil.PropertyModel;
/* package */ class PaymentHandlerViewBinder { /* package */ class PaymentHandlerViewBinder {
/* package */ static void bind( /* package */ static void bind(
PropertyModel model, PaymentHandlerView view, PropertyKey propertyKey) { PropertyModel model, PaymentHandlerView view, PropertyKey propertyKey) {
// TODO(maxlg): bind model properties to view after adding view widgets. if (PaymentHandlerProperties.BOTTOM_SHEET_HEIGHT_FRACTION == propertyKey) {
view.onHeightFractionChanged(
model.get(PaymentHandlerProperties.BOTTOM_SHEET_HEIGHT_FRACTION));
}
} }
} }
gogerald@chromium.org gogerald@chromium.org
rouslan@chromium.org rouslan@chromium.org
danyao@chromium.org danyao@chromium.org
maxlg@chromium.org
# COMPONENT: UI>Browser>Payments # COMPONENT: UI>Browser>Payments
...@@ -652,4 +652,18 @@ ...@@ -652,4 +652,18 @@
<message name="IDS_PAYMENTS_ORDER_SUMMARY_ACCESSIBLE_LABEL" desc="The string used to format what the screenreader reads out for the order summary section of the Payment Sheet."> <message name="IDS_PAYMENTS_ORDER_SUMMARY_ACCESSIBLE_LABEL" desc="The string used to format what the screenreader reads out for the order summary section of the Payment Sheet.">
Order Summary, <ph name="TOTAL_LABEL">$1<ex>Total, USD $10.00</ex></ph>, More Details Order Summary, <ph name="TOTAL_LABEL">$1<ex>Total, USD $10.00</ex></ph>, More Details
</message> </message>
<!-- Payment Handler strings -->
<message name="IDS_PAYMENT_HANDLER_SHEET_DESCRIPTION" desc="Accessibility string read when the payment-handler bottom sheet is opened. It describes the payment-handler where users can fill in the payment info." formatter_data="android_java">
Payment handler sheet
</message>
<message name="IDS_PAYMENT_HANDLER_SHEET_OPENED_HALF" desc="Accessibility string read when the payment-handler bottom sheet is opened at half height. The sheet will occupy up to the half screen." formatter_data="android_java">
Payment handler sheet is half-opened
</message>
<message name="IDS_PAYMENT_HANDLER_SHEET_OPENED_FULL" desc="Accessibility string read when the payment-handler bottom sheet is opened at full height. The sheet will occupy up to the full screen." formatter_data="android_java">
Payment handler sheet is opened
</message>
<message name="IDS_PAYMENT_HANDLER_SHEET_CLOSED" desc="Accessibility string read when the payment-handler bottom sheet is closed." formatter_data="android_java">
Payment handler sheet is closed
</message>
</grit-part> </grit-part>
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