Commit 56a06fd5 authored by Mathias Carlen's avatar Mathias Carlen Committed by Commit Bot

[Autofill Assistant] Integrate Payment Request.

This patch is the first step to integrate the payment request UI into
the autofill assistant sheet.

The patch has and leaves a few rough edges but we'll deal with that
piece by piece. In particular, the dismiss logic needs to be handled
differently, so does the error view logic.

Note: The DimmingDialog is reverted to package default visibility since
the dependency from autofill assistant is removed here.

Bug: 806868
Change-Id: I25b83b804e13bbdec5d2a1688dd01cd085615b38
Reviewed-on: https://chromium-review.googlesource.com/c/1324451
Commit-Queue: Mathias Carlen <mcarlen@chromium.org>
Reviewed-by: default avatarGanggui Tang <gogerald@chromium.org>
Reviewed-by: default avatarTheresa <twellington@chromium.org>
Cr-Commit-Position: refs/heads/master@{#606870}
parent ec464d0a
......@@ -16,7 +16,7 @@
app:maxWidthPortrait="@dimen/payments_ui_max_dialog_width"
android:background="@android:color/white" >
<include layout="@layout/payment_request_header" />
<!-- TODO(crbug.com/806868): Spinny is probably also obsolete. -->
<include layout="@layout/payment_request_spinny" />
<org.chromium.chrome.browser.widget.FadingEdgeScrollView
......
......@@ -23,7 +23,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minHeight="36dp"
android:text="@string/payments_edit_button"
android:text="@string/cancel"
style="@style/TextButton" />
<org.chromium.ui.widget.ButtonCompat
......@@ -31,6 +31,6 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minHeight="36dp"
android:text="@string/payments_pay_button"
android:text="@string/next"
style="@style/FilledButton.Flat" />
</org.chromium.chrome.browser.autofill_assistant.ui.PaymentRequestBottomBar>
......@@ -8,6 +8,7 @@ import android.content.Context;
import android.os.Handler;
import android.support.v4.util.ArrayMap;
import android.text.TextUtils;
import android.view.ViewGroup;
import org.chromium.base.Callback;
import org.chromium.chrome.R;
......@@ -141,9 +142,13 @@ public class AutofillAssistantPaymentRequest {
/**
* Show payment request UI to ask for payment information.
*
* Replace |container| with the payment request UI and restore it when the payment request UI is
* closed.
*
* @param container View to replace with the payment request.
* @param callback The callback to return payment information.
*/
/* package */ void show(Callback<SelectedPaymentInformation> callback) {
/* package */ void show(ViewGroup container, Callback<SelectedPaymentInformation> callback) {
// Do not expect calling show multiple times.
assert mCallback == null;
assert mUI == null;
......@@ -151,7 +156,7 @@ public class AutofillAssistantPaymentRequest {
mCallback = callback;
buildUI(ChromeActivity.fromWebContents(mWebContents));
mUI.show();
mUI.show(container);
}
private void buildUI(ChromeActivity activity) {
......
......@@ -73,8 +73,6 @@ public class AutofillAssistantUiController implements AutofillAssistantUiDelegat
*/
private final long mUiControllerAndroid;
private AutofillAssistantPaymentRequest mAutofillAssistantPaymentRequest;
/**
* Indicates whether {@link mAccount} has been initialized.
*/
......@@ -312,29 +310,25 @@ public class AutofillAssistantUiController implements AutofillAssistantUiDelegat
private void onRequestPaymentInformation(boolean requestShipping, boolean requestPayerName,
boolean requestPayerPhone, boolean requestPayerEmail, int shippingType, String title,
String[] supportedBasicCardNetworks) {
PaymentOptions paymentOtions = new PaymentOptions();
paymentOtions.requestShipping = requestShipping;
paymentOtions.requestPayerName = requestPayerName;
paymentOtions.requestPayerPhone = requestPayerPhone;
paymentOtions.requestPayerEmail = requestPayerEmail;
paymentOtions.shippingType = shippingType;
mAutofillAssistantPaymentRequest = new AutofillAssistantPaymentRequest(
mWebContents, paymentOtions, title, supportedBasicCardNetworks);
PaymentOptions paymentOptions = new PaymentOptions();
paymentOptions.requestShipping = requestShipping;
paymentOptions.requestPayerName = requestPayerName;
paymentOptions.requestPayerPhone = requestPayerPhone;
paymentOptions.requestPayerEmail = requestPayerEmail;
paymentOptions.shippingType = shippingType;
mUiDelegateHolder.performUiOperation(uiDelegate -> {
boolean overlayVisible = uiDelegate.isOverlayVisible();
if (overlayVisible) uiDelegate.hideOverlay();
mAutofillAssistantPaymentRequest.show(selectedPaymentInformation -> {
if (overlayVisible) uiDelegate.showOverlay();
uiDelegate.showPaymentRequest(mWebContents, paymentOptions, title,
supportedBasicCardNetworks, (selectedPaymentInformation -> {
nativeOnGetPaymentInformation(mUiControllerAndroid,
selectedPaymentInformation.succeed, selectedPaymentInformation.card,
selectedPaymentInformation.address, selectedPaymentInformation.payerName,
selectedPaymentInformation.address,
selectedPaymentInformation.payerName,
selectedPaymentInformation.payerPhone,
selectedPaymentInformation.payerEmail,
selectedPaymentInformation.isTermsAndConditionsAccepted);
mAutofillAssistantPaymentRequest.close();
mAutofillAssistantPaymentRequest = null;
});
uiDelegate.closePaymentRequest();
}));
});
}
......
......@@ -34,6 +34,7 @@ import android.widget.TextView;
import org.json.JSONObject;
import org.chromium.base.Callback;
import org.chromium.chrome.autofill_assistant.R;
import org.chromium.chrome.browser.ChromeActivity;
import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
......@@ -47,6 +48,8 @@ import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.snackbar.Snackbar;
import org.chromium.chrome.browser.snackbar.SnackbarManager;
import org.chromium.components.variations.VariationsAssociatedData;
import org.chromium.content_public.browser.WebContents;
import org.chromium.payments.mojom.PaymentOptions;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
......@@ -96,6 +99,7 @@ class AutofillAssistantUiDelegate {
@Nullable
private Details mDetails;
private String mStatusMessage;
private AutofillAssistantPaymentRequest mPaymentRequest;
/**
* This is a client interface that relays interactions from the UI.
......@@ -706,4 +710,33 @@ class AutofillAssistantUiDelegate {
controller.onInitFinished(initOk, checkBox.isChecked());
mCoordinatorView.removeView(initView);
}
/**
* Show the payment request UI.
*
* Show the UI and return the selected information via |callback| when done.
*
* @param webContents The webContents.
* @param paymentOptions Options to request payment information.
* @param title Unused title.
* @param supportedBasicCardNetworks Optional array of supported basic card networks.
* @param callback Callback to return selected info.
*/
public void showPaymentRequest(WebContents webContents, PaymentOptions paymentOptions,
String unusedTitle, String[] supportedBasicCardNetworks,
Callback<AutofillAssistantPaymentRequest.SelectedPaymentInformation> callback) {
assert mPaymentRequest == null;
mPaymentRequest = new AutofillAssistantPaymentRequest(
webContents, paymentOptions, unusedTitle, supportedBasicCardNetworks);
// Make sure we wrap content in the container.
mBottomBarAnimations.setBottomBarHeightToWrapContent();
mPaymentRequest.show(mCarouselScroll, callback);
}
/** Close and destroy the payment request UI. */
public void closePaymentRequest() {
mPaymentRequest.close();
mPaymentRequest = null;
mBottomBarAnimations.setBottomBarHeightToFixed();
}
}
......@@ -131,6 +131,20 @@ public class BottomBarAnimations {
setCarouselPaddings();
}
/** Update the bottom bar height to wrap when the details are shown.. */
public void setBottomBarHeightToWrapContent() {
if (mDetailsView.getVisibility() == View.VISIBLE) {
setBottomBarHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
}
}
/** Update the bottom bar height to fixed when the details are shown. */
public void setBottomBarHeightToFixed() {
if (mDetailsView.getVisibility() == View.VISIBLE) {
setBottomBarHeight(mBottomBarWithDetailsHeight);
}
}
/**
* Show the details. This method does nothing if the details are already hidden.
*/
......
......@@ -20,6 +20,7 @@ import android.support.v4.view.animation.LinearOutSlowInInterpolator;
import android.text.SpannableString;
import android.text.TextUtils;
import android.text.method.LinkMovementMethod;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnLayoutChangeListener;
......@@ -38,9 +39,7 @@ import org.chromium.chrome.browser.ChromeFeatureList;
import org.chromium.chrome.browser.ChromeVersionInfo;
import org.chromium.chrome.browser.autofill_assistant.AutofillAssistantPaymentRequest;
import org.chromium.chrome.browser.payments.ShippingStrings;
import org.chromium.chrome.browser.payments.ui.DimmingDialog;
import org.chromium.chrome.browser.payments.ui.PaymentInformation;
import org.chromium.chrome.browser.payments.ui.PaymentRequestHeader;
import org.chromium.chrome.browser.payments.ui.PaymentRequestSection;
import org.chromium.chrome.browser.payments.ui.PaymentRequestSection.LineItemBreakdownSection;
import org.chromium.chrome.browser.payments.ui.PaymentRequestSection.OptionSection;
......@@ -107,7 +106,6 @@ public class PaymentRequestUI implements DialogInterface.OnDismissListener, View
private final boolean mRequestContactDetails;
private final boolean mShowDataSource;
private final DimmingDialog mDialog;
private final EditorDialog mEditorDialog;
private final EditorDialog mCardEditorDialog;
private final ViewGroup mRequestView;
......@@ -120,9 +118,10 @@ public class PaymentRequestUI implements DialogInterface.OnDismissListener, View
private ViewGroup mBottomBar;
private Button mEditButton;
private Button mPayButton;
private View mCloseButton;
private View mSpinnyLayout;
private CheckBox mTermsCheckBox;
// View used to store a view to be replaced with the current payment request UI.
private ViewGroup mBackupView;
private LineItemBreakdownSection mOrderSummarySection;
private OptionSection mShippingAddressSection;
......@@ -153,7 +152,7 @@ public class PaymentRequestUI implements DialogInterface.OnDismissListener, View
* Builds the UI for PaymentRequest.
*
* @param activity The activity on top of which the UI should be displayed.
* @param client The consumer of the PaymentRequest UI.
* @param client The AutofillAssistantPaymentRequest.
* @param requestShipping Whether the UI should show the shipping address selection.
* @param requestShippingOption Whether the UI should show the shipping option selection.
* @param requestContact Whether the UI should show the payer name, email address and
......@@ -223,26 +222,42 @@ public class PaymentRequestUI implements DialogInterface.OnDismissListener, View
mEditorDialog = new EditorDialog(activity, null,
/*deleteRunnable =*/null);
DimmingDialog.setVisibleStatusBarIconColor(mEditorDialog.getWindow());
mCardEditorDialog = new EditorDialog(activity, null,
/*deleteRunnable =*/null);
DimmingDialog.setVisibleStatusBarIconColor(mCardEditorDialog.getWindow());
// Allow screenshots of the credit card number in Canary, Dev, and developer builds.
if (ChromeVersionInfo.isBetaBuild() || ChromeVersionInfo.isStableBuild()) {
mCardEditorDialog.disableScreenshots();
}
mDialog = new DimmingDialog(activity, this);
}
/**
* Shows the PaymentRequest UI. This will dim the background behind the PaymentRequest UI.
*
* The show replaces the |container| view with the payment request view. The original content of
* |container| is saved and restored when the payment request UI is closed.
* restore it when the payment request UI is closed.
*
* TODO(crbug.com/806868): Move the mBackupView handling to the AutofillAssistantUiDelegate.
*
* @param container View to replace with the payment request UI.
*/
public void show() {
mDialog.addBottomSheetView(mRequestView);
mDialog.show();
public void show(ViewGroup container) {
// Clear the current Autofill Assistant sheet and show the request view.
LinearLayout.LayoutParams sheetParams =
new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
sheetParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
// Swap the horizontal scroll view |container| with the payment request view and save the
// original.
ViewGroup parent = (ViewGroup) container.getParent();
assert parent != null;
final int index = parent.indexOfChild(container);
mBackupView = container;
parent.removeView(container);
parent.addView(mRequestView, index, sheetParams);
mClient.getDefaultPaymentInformation(new Callback<PaymentInformation>() {
@Override
public void onResult(PaymentInformation result) {
......@@ -295,12 +310,7 @@ public class PaymentRequestUI implements DialogInterface.OnDismissListener, View
TextView messageView = (TextView) mRequestView.findViewById(R.id.message);
messageView.setText(R.string.payments_loading_message);
((PaymentRequestHeader) mRequestView.findViewById(R.id.header))
.setTitleAndOrigin(title, origin, securityLevel);
// Set up the buttons.
mCloseButton = mRequestView.findViewById(R.id.close_button);
mCloseButton.setOnClickListener(this);
mBottomBar = (ViewGroup) mRequestView.findViewById(R.id.bottom_bar);
mPayButton = (Button) mBottomBar.findViewById(R.id.button_primary);
mPayButton.setOnClickListener(this);
......@@ -401,6 +411,14 @@ public class PaymentRequestUI implements DialogInterface.OnDismissListener, View
public void close(boolean shouldCloseImmediately, final Runnable callback) {
mIsClientClosing = true;
// Restore the UI before we showed the payment request.
ViewGroup parent = (ViewGroup) mRequestView.getParent();
assert parent != null;
final int index = parent.indexOfChild(mRequestView);
parent.removeView(mRequestView);
parent.addView(mBackupView, index);
mBackupView = null;
Runnable dismissRunnable = new Runnable() {
@Override
public void run() {
......@@ -415,8 +433,7 @@ public class PaymentRequestUI implements DialogInterface.OnDismissListener, View
// in JavaScript.
dismissRunnable.run();
} else {
// Show the error dialog.
mDialog.showOverlay(mErrorView);
// TODO(crbug.com/806868): Show the mErrorView error dialog.
mErrorView.setDismissRunnable(dismissRunnable);
}
}
......@@ -598,11 +615,6 @@ public class PaymentRequestUI implements DialogInterface.OnDismissListener, View
public void onClick(View v) {
if (!isAcceptingCloseButton()) return;
if (v == mCloseButton) {
dismissDialog(true);
return;
}
if (!isAcceptingUserInput()) return;
// Users can only expand incomplete sections by clicking on their edit buttons.
......@@ -641,7 +653,6 @@ public class PaymentRequestUI implements DialogInterface.OnDismissListener, View
*/
private void dismissDialog(boolean isAnimated) {
mIsClosing = true;
mDialog.dismiss(isAnimated);
}
private void processPayButton() {
......@@ -658,8 +669,6 @@ public class PaymentRequestUI implements DialogInterface.OnDismissListener, View
if (shouldShowSpinner) {
changeSpinnerVisibility(true);
} else {
mDialog.hide();
}
}
......@@ -670,7 +679,6 @@ public class PaymentRequestUI implements DialogInterface.OnDismissListener, View
assert mIsProcessingPayClicked;
mIsProcessingPayClicked = false;
changeSpinnerVisibility(false);
mDialog.show();
updatePayButtonEnabled();
}
......@@ -692,7 +700,6 @@ public class PaymentRequestUI implements DialogInterface.OnDismissListener, View
assert mIsProcessingPayClicked;
changeSpinnerVisibility(true);
mDialog.show();
}
private void changeSpinnerVisibility(boolean showSpinner) {
......@@ -702,7 +709,6 @@ public class PaymentRequestUI implements DialogInterface.OnDismissListener, View
if (showSpinner) {
mPaymentContainer.setVisibility(View.GONE);
mBottomBar.setVisibility(View.GONE);
mCloseButton.setVisibility(View.GONE);
mSpinnyLayout.setVisibility(View.VISIBLE);
// Turn the bottom sheet back into a collapsed bottom sheet showing only the spinner.
......@@ -713,7 +719,6 @@ public class PaymentRequestUI implements DialogInterface.OnDismissListener, View
} else {
mPaymentContainer.setVisibility(View.VISIBLE);
mBottomBar.setVisibility(View.VISIBLE);
mCloseButton.setVisibility(View.VISIBLE);
mSpinnyLayout.setVisibility(View.GONE);
if (mIsExpandedToFullHeight) {
......@@ -742,9 +747,8 @@ public class PaymentRequestUI implements DialogInterface.OnDismissListener, View
/** @return Whether or not the dialog can be closed via the X close button. */
private boolean isAcceptingCloseButton() {
return !mDialog.isAnimatingDisappearance() && mSheetAnimator == null
&& mSectionAnimator == null && !mIsProcessingPayClicked && !mIsEditingPaymentItem
&& !mIsClosing;
return mSheetAnimator == null && mSectionAnimator == null && !mIsProcessingPayClicked
&& !mIsEditingPaymentItem && !mIsClosing;
}
/** @return Whether or not the dialog is accepting user input. */
......
......@@ -41,7 +41,7 @@ import org.chromium.chrome.browser.widget.animation.AnimatorProperties;
* TODO(crbug.com/806868): Revert the visibility to package default again when it is no longer used
* by Autofill Assistant.
*/
public class DimmingDialog {
/* package */ class DimmingDialog {
/**
* Length of the animation to either show the UI or expand it to full height. Note that click of
* 'Pay' button in PaymentRequestUI is not accepted until the animation is done, so this
......@@ -64,7 +64,8 @@ public class DimmingDialog {
* @param activity The activity on top of which the dialog should be displayed.
* @param dismissListener The listener for the dismissal of this dialog.
*/
public DimmingDialog(Activity activity, DialogInterface.OnDismissListener dismissListener) {
/* package */ DimmingDialog(
Activity activity, DialogInterface.OnDismissListener dismissListener) {
// To handle the specced animations, the dialog is entirely contained within a translucent
// FrameLayout. This could eventually be converted to a real BottomSheetDialog, but that
// requires exploration of how interactions would work when the dialog can be sent back and
......@@ -90,14 +91,14 @@ public class DimmingDialog {
* Makes sure that the color of the icons in the status bar makes the icons visible.
* @param window The window whose status bar icon color is being set.
*/
public static void setVisibleStatusBarIconColor(Window window) {
/* package */ static void setVisibleStatusBarIconColor(Window window) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return;
ApiCompatibilityUtils.setStatusBarIconColor(window.getDecorView().getRootView(),
!ColorUtils.shouldUseLightForegroundOnBackground(window.getStatusBarColor()));
}
/** @param bottomSheetView The view to show in the bottom sheet. */
public void addBottomSheetView(View bottomSheetView) {
/* package */ void addBottomSheetView(View bottomSheetView) {
FrameLayout.LayoutParams bottomSheetParams =
new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
bottomSheetParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
......@@ -106,12 +107,12 @@ public class DimmingDialog {
}
/** Show the dialog. */
public void show() {
/* package */ void show() {
mDialog.show();
}
/** Hide the dialog without dismissing it. */
public void hide() {
/* package */ void hide() {
mDialog.hide();
}
......@@ -120,7 +121,7 @@ public class DimmingDialog {
*
* @param isAnimated If true, the dialog dismissal is animated.
*/
public void dismiss(boolean isAnimated) {
/* package */ void dismiss(boolean isAnimated) {
if (!mDialog.isShowing()) return;
if (isAnimated) {
new DisappearingAnimator(true);
......@@ -130,7 +131,7 @@ public class DimmingDialog {
}
/** @param overlay The overlay to show. This can be an error dialog, for example. */
public void showOverlay(View overlay) {
/* package */ void showOverlay(View overlay) {
// Animate the bottom sheet going away.
new DisappearingAnimator(false);
......@@ -143,7 +144,7 @@ public class DimmingDialog {
}
/** @return Whether the dialog is currently animating disappearance. */
public boolean isAnimatingDisappearance() {
/* package */ boolean isAnimatingDisappearance() {
return mIsAnimatingDisappearance;
}
......
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