Commit 7259523e authored by Jinho Bang's avatar Jinho Bang Committed by Commit Bot

PaymentRequest: Implement error message for retry() on Android

In current implementation, retry() ignores |error| member. So, before
this patch, nothing was displayed on the payment sheet UI even if
retry() is invoked with custom error message.
After this patch, JS authors can display a custom message on the payment
sheet UI via |error| member when invoking retry(). If the |error| member
is empty, UA displays default error message.

This feature is behind a flag:
  chrome://flags/#enable-experimental-web-platform-features

Manual Test:
  wpt/payment-request/payment-response/retry-method-manual.https.html
  wpt/payment-request/PaymentValidationErrors/retry-shows-error-member-manual.https.html

Bug: 861704, 942204
Change-Id: Id23a2924ca1d5c2f32416c7de6210357bf4e6296
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1575307
Commit-Queue: Jinho Bang <jinho.bang@samsung.com>
Reviewed-by: default avatarTed Choc <tedchoc@chromium.org>
Reviewed-by: default avatarRouslan Solomakhin <rouslan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#657665}
parent 900c708a
......@@ -2,7 +2,6 @@
<!-- Copyright 2016 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. -->
<!-- Header containing information about the site.
Java code inflating this layout manages the hiding and adjustment of elements in the layout.
Request dialog: Displays an X in the top right corner, allowing the user to close it.
......@@ -10,66 +9,73 @@
-->
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<org.chromium.chrome.browser.payments.ui.PaymentRequestHeader
android:id="@+id/header"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:minHeight="64dp">
<ImageView
android:id="@+id/icon_view"
android:layout_height="24dp"
android:layout_width="24dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_gravity="start|center_vertical"
android:importantForAccessibility="no"
android:scaleType="centerInside" />
<LinearLayout
android:id="@+id/page_info"
android:layout_gravity="center_vertical"
android:orientation="vertical">
<FrameLayout
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_marginStart="50dp"
android:layout_marginEnd="50dp"
android:layout_marginBottom="@dimen/payments_section_vertical_spacing"
android:layout_marginTop="@dimen/payments_section_vertical_spacing"
android:layout_gravity="center_vertical"
android:orientation="vertical">
<TextView
android:id="@+id/page_title"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:paddingStart="6dp"
android:ellipsize="end"
android:maxLines="1"
android:singleLine="true"
android:textAppearance="@style/TextAppearance.PaymentRequestHeaderTitle" />
<TextView
android:id="@+id/hostname"
android:layout_width="match_parent"
android:minHeight="64dp">
<ImageView
android:id="@+id/icon_view"
android:layout_height="24dp"
android:layout_width="24dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_gravity="start|center_vertical"
android:importantForAccessibility="no"
android:scaleType="centerInside" />
<LinearLayout
android:id="@+id/page_info"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:paddingStart="6dp"
android:gravity="center_vertical"
android:ellipsize="start"
android:maxLines="1"
android:singleLine="true"
android:textAppearance="@style/TextAppearance.BlackBody" />
</LinearLayout>
<ImageView
android:id="@+id/close_button"
android:layout_gravity="end|center_vertical"
android:layout_height="56dp"
android:layout_width="56dp"
android:src="@drawable/btn_close"
android:contentDescription="@string/close"
android:background="?attr/selectableItemBackground"
android:scaleType="center"
app:tint="@color/standard_mode_tint" />
android:layout_marginStart="50dp"
android:layout_marginEnd="50dp"
android:layout_marginBottom="@dimen/payments_section_vertical_spacing"
android:layout_marginTop="@dimen/payments_section_vertical_spacing"
android:layout_gravity="center_vertical"
android:orientation="vertical">
<TextView
android:id="@+id/page_title"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:paddingStart="6dp"
android:ellipsize="end"
android:maxLines="1"
android:singleLine="true"
android:textAppearance="@style/TextAppearance.PaymentRequestHeaderTitle" />
<TextView
android:id="@+id/hostname"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:paddingStart="6dp"
android:gravity="center_vertical"
android:ellipsize="start"
android:maxLines="1"
android:singleLine="true"
android:textAppearance="@style/TextAppearance.BlackBody" />
</LinearLayout>
<ImageView
android:id="@+id/close_button"
android:layout_gravity="end|center_vertical"
android:layout_height="56dp"
android:layout_width="56dp"
android:src="@drawable/btn_close"
android:contentDescription="@string/close"
android:background="?attr/selectableItemBackground"
android:scaleType="center"
app:tint="@color/standard_mode_tint" />
</FrameLayout>
<TextView
android:id="@+id/retry_error"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:visibility="gone"
android:textAppearance="@style/TextAppearance.PaymentsUiSectionWarningText" />
</org.chromium.chrome.browser.payments.ui.PaymentRequestHeader>
</merge>
\ No newline at end of file
</merge>
......@@ -1627,6 +1627,13 @@ public class PaymentRequestImpl
// Go back to the payment sheet
mUI.onPayButtonProcessingCancelled();
if (!TextUtils.isEmpty(errors.error)) {
mUI.setRetryErrorMessage(errors.error);
} else {
ChromeActivity activity = ChromeActivity.fromWebContents(mWebContents);
mUI.setRetryErrorMessage(
activity.getResources().getString(R.string.payments_error_message));
}
if (mRequestShipping && hasShippingAddressError(errors.shippingAddress)) {
mRetryQueue.add(() -> {
......
......@@ -9,9 +9,11 @@ import android.graphics.Bitmap;
import android.support.annotation.ColorInt;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.widget.FrameLayout;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import org.chromium.base.ApiCompatibilityUtils;
......@@ -23,7 +25,7 @@ import org.chromium.chrome.browser.util.ColorUtils;
import org.chromium.chrome.browser.widget.TintedDrawable;
/** This class represents a bar to display at the top of the payment request UI. */
public class PaymentRequestHeader extends FrameLayout {
public class PaymentRequestHeader extends LinearLayout {
private final @ColorInt int mBackgroundColor;
private Context mContext;
......@@ -81,4 +83,19 @@ public class PaymentRequestHeader extends FrameLayout {
hostName.setPaddingRelative(0, 0, 0, 0);
}
}
}
\ No newline at end of file
/**
* Sets the retry error message on the header.
*
* @param error The error message to display on the header.
*/
public void setRetryErrorMessage(String error) {
TextView errorMessageView = (TextView) findViewById(R.id.retry_error);
errorMessageView.setText(error);
if (TextUtils.isEmpty(error)) {
errorMessageView.setVisibility(View.GONE);
} else {
errorMessageView.setVisibility(View.VISIBLE);
}
}
}
......@@ -617,6 +617,17 @@ public class PaymentRequestUI implements DialogInterface.OnDismissListener, View
mErrorView.setBitmap(bitmap);
}
/**
* Sets the retry error message. This is used to display error message on the header UI when
* retry() is called on merchant side. The error message may be reset when users click 'Pay'
* button or expand any section.
*
* @param error The error message to display on the header.
*/
public void setRetryErrorMessage(String error) {
((PaymentRequestHeader) mRequestView.findViewById(R.id.header)).setRetryErrorMessage(error);
}
/**
* Updates the line items in response to a changed shipping address or option.
*
......@@ -822,6 +833,8 @@ public class PaymentRequestUI implements DialogInterface.OnDismissListener, View
}
}
setRetryErrorMessage(null);
updatePayButtonEnabled();
}
......
......@@ -9,6 +9,7 @@ import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.IMMEDI
import android.support.test.filters.MediumTest;
import org.junit.Assert;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
......@@ -62,6 +63,55 @@ public class PaymentRequestRetryTest implements MainActivityStartCallback {
mPaymentRequestTestRule.installPaymentApp(HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE);
}
/**
* Test for retry() with default error message
*/
@Test
@MediumTest
@Feature({"Payments"})
public void testRetryWithDefaultError()
throws InterruptedException, ExecutionException, TimeoutException {
mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyForInput());
mPaymentRequestTestRule.clickAndWait(
R.id.button_primary, mPaymentRequestTestRule.getReadyForUnmaskInput());
mPaymentRequestTestRule.setTextInCardUnmaskDialogAndWait(
R.id.card_unmask_input, "123", mPaymentRequestTestRule.getReadyToUnmask());
mPaymentRequestTestRule.clickCardUnmaskButtonAndWait(
ModalDialogProperties.ButtonType.POSITIVE,
mPaymentRequestTestRule.getPaymentResponseReady());
mPaymentRequestTestRule.retryPaymentRequest("{}", mPaymentRequestTestRule.getReadyToPay());
Assert.assertEquals(
mPaymentRequestTestRule.getActivity().getString(R.string.payments_error_message),
mPaymentRequestTestRule.getRetryErrorMessage());
}
/**
* Test for retry() with custom error message.
*/
@Test
@MediumTest
@Feature({"Payments"})
public void testRetryWithCustomError()
throws InterruptedException, ExecutionException, TimeoutException {
mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyForInput());
mPaymentRequestTestRule.clickAndWait(
R.id.button_primary, mPaymentRequestTestRule.getReadyForUnmaskInput());
mPaymentRequestTestRule.setTextInCardUnmaskDialogAndWait(
R.id.card_unmask_input, "123", mPaymentRequestTestRule.getReadyToUnmask());
mPaymentRequestTestRule.clickCardUnmaskButtonAndWait(
ModalDialogProperties.ButtonType.POSITIVE,
mPaymentRequestTestRule.getPaymentResponseReady());
mPaymentRequestTestRule.retryPaymentRequest("{"
+ " error: 'ERROR'"
+ "}",
mPaymentRequestTestRule.getReadyToPay());
Assert.assertEquals("ERROR", mPaymentRequestTestRule.getRetryErrorMessage());
}
/**
* Test for retry() with shipping address errors.
*/
......
......@@ -394,6 +394,14 @@ public class PaymentRequestTestRule extends ChromeTabbedActivityTestRule
helper.waitForCallback(callCount);
}
/** Gets the retry error message. */
protected String getRetryErrorMessage() {
return ThreadUtils.runOnUiThreadBlockingNoException(
() -> ((TextView) mUI.getDialogForTest().findViewById(R.id.retry_error))
.getText()
.toString());
}
/** Gets the button state for the shipping summary section. */
protected int getShippingAddressSectionButtonState() throws ExecutionException {
return ThreadUtils.runOnUiThreadBlocking(
......
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