Commit 561f6a86 authored by Sahel Sharify's avatar Sahel Sharify Committed by Commit Bot

[Web Payments][Android] Delegation support for intent based apps [2/3]

This cl introduces IPaymentDetailsUpdateService.aidl and
IPaymentDetailsUpdateServiceCallback.aidl interfaces so that the invoked
native app can call changePaymentMethod, changeShippingOption, and
changeShippingAddress methods to notify the browser about the user
choosing a different payment method, shipping address, or shipping
option.

This cl implements the plumbing for sending the change events to the
merchant, but the plumbing for sending the updated payment details from
the merchant to the invoked app will be landed in a follow up cl.

To test the feature enable "Experimental Web Payments API features" from
chrome:/flags or use the following commandline flag:
enable-features=AndroidAppPaymentUpdateEvents

Bug: 1026667
Change-Id: I799c9dfced15fe2fa916b8ca3634b91366cfc32f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2168009
Commit-Queue: Sahel Sharify <sahel@chromium.org>
Reviewed-by: default avatarRobert Sesek <rsesek@chromium.org>
Reviewed-by: default avatarLiquan (Max) Gu <maxlg@chromium.org>
Reviewed-by: default avatarMichael Thiessen <mthiesse@chromium.org>
Reviewed-by: default avatarRouslan Solomakhin <rouslan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#773401}
parent c89a98c9
......@@ -331,6 +331,7 @@ chrome_test_java_sources = [
"javatests/src/org/chromium/chrome/browser/payments/IsReadyToPayServiceHelperTest.java",
"javatests/src/org/chromium/chrome/browser/payments/MockPackageManagerDelegate.java",
"javatests/src/org/chromium/chrome/browser/payments/MockTwaPackageManagerDelegate.java",
"javatests/src/org/chromium/chrome/browser/payments/PaymentDetailsUpdateServiceHelperTest.java",
"javatests/src/org/chromium/chrome/browser/payments/PaymentErrorStringsTest.java",
"javatests/src/org/chromium/chrome/browser/payments/PaymentHandlerChangePaymentMethodTest.java",
"javatests/src/org/chromium/chrome/browser/payments/PaymentHandlerEnableDelegationsTest.java",
......
......@@ -1086,6 +1086,12 @@ by a child template that "extends" this file.
<service android:name="org.chromium.chrome.browser.incognito.IncognitoNotificationService"
android:exported="false"/>
<!-- service used by payment apps to notify the browser about changes in user selected
payment method, shipping address, or shipping option -->
<service
android:name="org.chromium.components.payments.PaymentDetailsUpdateService"
android:exported="true"/>
<!-- The following service entries exist in order to allow us to
start more than one sandboxed process. -->
......
......@@ -1164,6 +1164,9 @@
<action android:name="com.google.android.gms.gcm.ACTION_TASK_READY"/>
</intent-filter>
</service>
<service
android:exported="true"
android:name="org.chromium.components.payments.PaymentDetailsUpdateService"/>
<service android:name="androidx.browser.customtabs.PostMessageService"/>
<service
android:exported="true"
......
......@@ -407,4 +407,11 @@ public class AndroidPaymentApp
public @PaymentAppType int getPaymentAppType() {
return PaymentAppType.NATIVE_MOBILE_APP;
}
/**
* @return The package name of the invoked native app.
*/
public String packageName() {
return mPackageName;
}
}
......@@ -57,10 +57,12 @@ import org.chromium.components.payments.ErrorMessageUtil;
import org.chromium.components.payments.ErrorStrings;
import org.chromium.components.payments.MethodStrings;
import org.chromium.components.payments.OriginSecurityChecker;
import org.chromium.components.payments.PackageManagerDelegate;
import org.chromium.components.payments.PayerData;
import org.chromium.components.payments.PaymentApp;
import org.chromium.components.payments.PaymentAppType;
import org.chromium.components.payments.PaymentDetailsConverter;
import org.chromium.components.payments.PaymentDetailsUpdateServiceHelper;
import org.chromium.components.payments.PaymentFeatureList;
import org.chromium.components.payments.PaymentHandlerHost;
import org.chromium.components.payments.PaymentRequestSpec;
......@@ -2120,6 +2122,12 @@ public class PaymentRequestImpl
}
mInvokedPaymentApp.setPaymentHandlerHost(getPaymentHandlerHost());
// Only native apps can use PaymentDetailsUpdateService.
if (mInvokedPaymentApp.getPaymentAppType() == PaymentAppType.NATIVE_MOBILE_APP) {
PaymentDetailsUpdateServiceHelper.getInstance().initialize(new PackageManagerDelegate(),
((AndroidPaymentApp) mInvokedPaymentApp).packageName(),
this /* PaymentApp.PaymentRequestUpdateEventListener */);
}
// Create payment options for the invoked payment app.
PaymentOptions paymentOptions = new PaymentOptions();
......@@ -2276,6 +2284,7 @@ public class PaymentRequestImpl
// Go back to the payment sheet
mUI.onPayButtonProcessingCancelled();
PaymentDetailsUpdateServiceHelper.getInstance().reset();
if (!TextUtils.isEmpty(errors.error)) {
mUI.setRetryErrorMessage(errors.error);
} else {
......@@ -2880,6 +2889,7 @@ public class PaymentRequestImpl
disconnectFromClientWithDebugMessage(errorMessage);
} else {
mUI.onPayButtonProcessingCancelled();
PaymentDetailsUpdateServiceHelper.getInstance().reset();
}
}
......@@ -3016,6 +3026,7 @@ public class PaymentRequestImpl
mSpec.destroy();
mSpec = null;
}
PaymentDetailsUpdateServiceHelper.getInstance().reset();
}
private void closeClient() {
......
......@@ -1321,6 +1321,9 @@
<action android:name="com.google.android.gms.gcm.ACTION_TASK_READY"/>
</intent-filter>
</service>
<service
android:exported="true"
android:name="org.chromium.components.payments.PaymentDetailsUpdateService"/>
<service android:name="androidx.browser.customtabs.PostMessageService"/>
<service
android:exported="true"
......
......@@ -36,6 +36,8 @@ class MockPackageManagerDelegate extends PackageManagerDelegate {
private final List<ResolveInfo> mServices = new ArrayList<>();
private final Map<ApplicationInfo, List<String[]>> mResources = new HashMap<>();
private String mInvokedAppPackageName;
/**
* Simulates an installed payment app with no supported delegations.
*
......@@ -96,6 +98,7 @@ class MockPackageManagerDelegate extends PackageManagerDelegate {
if (signature != null) {
PackageInfo packageInfo = new PackageInfo();
packageInfo.packageName = packageName;
packageInfo.versionCode = 10;
if (signature.isEmpty()) {
packageInfo.signatures = new Signature[0];
......@@ -177,6 +180,11 @@ class MockPackageManagerDelegate extends PackageManagerDelegate {
return mPackages.get(packageName);
}
@Override
public PackageInfo getPackageInfoWithSignatures(int uid) {
return mPackages.get(mInvokedAppPackageName);
}
@Override
public CharSequence getAppLabel(ResolveInfo resolveInfo) {
return mLabels.get(resolveInfo);
......@@ -194,4 +202,13 @@ class MockPackageManagerDelegate extends PackageManagerDelegate {
assert resourceId > 0 && resourceId <= RESOURCES_SIZE;
return mResources.get(applicationInfo).get(resourceId - 1);
}
/**
* Sets the package name of the invoked payment app.
* @param packageName The package name of the invoked payment app.
*/
public void setInvokedAppPackageName(String packageName) {
assert mPackages.containsKey(packageName);
mInvokedAppPackageName = packageName;
}
}
......@@ -73,6 +73,8 @@ android_library("java") {
"java/src/org/chromium/components/payments/PaymentAddressTypeConverter.java",
"java/src/org/chromium/components/payments/PaymentApp.java",
"java/src/org/chromium/components/payments/PaymentDetailsConverter.java",
"java/src/org/chromium/components/payments/PaymentDetailsUpdateService.java",
"java/src/org/chromium/components/payments/PaymentDetailsUpdateServiceHelper.java",
"java/src/org/chromium/components/payments/PaymentFeatureList.java",
"java/src/org/chromium/components/payments/PaymentHandlerHost.java",
"java/src/org/chromium/components/payments/PaymentManifestDownloader.java",
......@@ -100,6 +102,15 @@ android_library("java") {
srcjar_deps = [
":error_strings_generated_srcjar",
":payment_app_type_generated_enum",
":payment_details_update_service_aidl",
]
}
android_aidl("payment_details_update_service_aidl") {
interface_file = "java/src/org/chromium/components/payments/payment_details_update_service.aidl"
sources = [
"java/src/org/chromium/components/payments/IPaymentDetailsUpdateService.aidl",
"java/src/org/chromium/components/payments/IPaymentDetailsUpdateServiceCallback.aidl",
]
}
......
// Copyright 2020 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.
package org.chromium.components.payments;
import android.os.Bundle;
import IPaymentDetailsUpdateServiceCallback;
/**
* Helper interface used by the invoked native payment app to notify the
* browser that the user has selected a different payment method, shipping
* option, or shipping address.
*/
interface IPaymentDetailsUpdateService {
/**
* Called to notify the browser that the user has selected a different
* payment method.
*
* @param paymentHandlerMethodData The data containing the selected payment
* method's name and optional stringified details.
*/
oneway void changePaymentMethod(in Bundle paymentHandlerMethodData,
IPaymentDetailsUpdateServiceCallback callback);
/**
* Called to notify the browser that the user has selected a different
* shipping option.
*
* @param shippingOptionId The identifier of the selected shipping option.
*/
oneway void changeShippingOption(in String shippingOptionId,
IPaymentDetailsUpdateServiceCallback callback);
/**
* Called to notify the browser that the user has selected a different
* shipping address.
*
* @param shippingAddress The selected shipping address.
*/
oneway void changeShippingAddress(in Bundle shippingAddress,
IPaymentDetailsUpdateServiceCallback callback);
}
// Copyright 2020 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.
package org.chromium.components.payments;
import android.os.Bundle;
/**
* Helper interface used by the browser to notify the invoked native app about
* merchant's response to one of the paymentmethodchange, shippingoptionchange,
* or shippingaddresschange events.
*/
interface IPaymentDetailsUpdateServiceCallback {
/**
* Called to notify the invoked payment app about updated payment details
* received from the merchant.
*
* @param updatedPaymentDetails The updated payment details received from
* the merchant.
*/
oneway void updateWith(in Bundle updatedPaymentDetails);
/**
* Called to notify the invoked payment app that the merchant has not
* modified the payment details.
*/
oneway void paymentDetailsNotUpdated();
}
......@@ -5,3 +5,6 @@ file://components/payments/OWNERS
per-file *TypeConverter*.*=set noparent
per-file *TypeConverter*.*=file://ipc/SECURITY_OWNERS
per-file *.aidl=set noparent
per-file *.aidl=file://ipc/SECURITY_OWNERS
......@@ -50,6 +50,20 @@ public class PackageManagerDelegate {
}
}
/**
* Retrieves package information of an installed application.
*
* @param uid The uid of an installed application.
* @return The package information of the installed application.
*/
@SuppressLint("PackageManagerGetSignatures")
public PackageInfo getPackageInfoWithSignatures(int uid) {
String packageName =
ContextUtils.getApplicationContext().getPackageManager().getNameForUid(uid);
if (packageName == null) return null;
return getPackageInfoWithSignatures(packageName);
}
/**
* Retrieves the list of activities that can respond to the given intent.
* @param intent The intent to query.
......
// Copyright 2020 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.
package org.chromium.components.payments;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
/**
* A bound service responsible for receiving change payment method, shipping option, and shipping
* address calls from an inoked native payment app.
*/
public class PaymentDetailsUpdateService extends Service {
private final IPaymentDetailsUpdateService.Stub mBinder =
new IPaymentDetailsUpdateService.Stub() {
@Override
public void changePaymentMethod(Bundle paymentHandlerMethodData,
IPaymentDetailsUpdateServiceCallback callback) {
if (!PaymentDetailsUpdateServiceHelper.getInstance().isCallerAuthorized(
Binder.getCallingUid())) {
return;
}
PaymentDetailsUpdateServiceHelper.getInstance().changePaymentMethod(
paymentHandlerMethodData, callback);
}
@Override
public void changeShippingOption(
String shippingOptionId, IPaymentDetailsUpdateServiceCallback callback) {
if (!PaymentDetailsUpdateServiceHelper.getInstance().isCallerAuthorized(
Binder.getCallingUid())) {
return;
}
PaymentDetailsUpdateServiceHelper.getInstance().changeShippingOption(
shippingOptionId, callback);
}
@Override
public void changeShippingAddress(
Bundle shippingAddress, IPaymentDetailsUpdateServiceCallback callback) {
if (!PaymentDetailsUpdateServiceHelper.getInstance().isCallerAuthorized(
Binder.getCallingUid())) {
return;
}
PaymentDetailsUpdateServiceHelper.getInstance().changeShippingAddress(
shippingAddress, callback);
}
};
@Override
public IBinder onBind(Intent intent) {
if (!PaymentFeatureList.isEnabledOrExperimentalFeaturesEnabled(
PaymentFeatureList.ANDROID_APP_PAYMENT_UPDATE_EVENTS)) {
return null;
}
return mBinder;
}
}
// Copyright 2020 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.
package org.chromium.components.payments;
import android.content.pm.PackageInfo;
import android.content.pm.Signature;
import android.os.Bundle;
import android.text.TextUtils;
import androidx.annotation.Nullable;
import org.chromium.base.Log;
import java.util.Arrays;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import javax.annotation.concurrent.GuardedBy;
/**
* Helper class used by android payment app to notify the browser that the user has selected a
* different payment instrument, shipping option, or shipping address inside native app.
*/
public class PaymentDetailsUpdateServiceHelper {
private static final String TAG = "PaymentDetailsUpdate";
// Bundle keys used to send data to this service.
public static final String KEY_METHOD_NAME = "methodName";
public static final String KEY_STRINGIFIED_DETAILS = "details";
private final Object mStateLock = new Object();
@Nullable
@GuardedBy("mStateLock")
private IPaymentDetailsUpdateServiceCallback mCallback;
@Nullable
@GuardedBy("mStateLock")
private PaymentRequestUpdateEventListener mListener;
private final ReadWriteLock mPackageInfoRwLock = new ReentrantReadWriteLock();
@Nullable
@GuardedBy("mPackageInfoRwLock")
private PackageInfo mInvokedAppPackageInfo;
@GuardedBy("mPackageInfoRwLock")
private PackageManagerDelegate mPackageManagerDelegate;
// Singleton instance.
private static final Object sInstanceLock = new Object();
private static volatile PaymentDetailsUpdateServiceHelper sInstance;
private PaymentDetailsUpdateServiceHelper(){};
/**
* Returns the thread safe singleton instance, lazily creating one if needed.
* The instance is only useful after its listener is set which happens when a native android app
* gets invoked.
* @return The singleton instance.
*/
public static PaymentDetailsUpdateServiceHelper getInstance() {
if (sInstance == null) {
synchronized (sInstanceLock) {
if (sInstance == null) sInstance = new PaymentDetailsUpdateServiceHelper();
}
}
return sInstance;
}
/**
* Initializes the service helper, called when an AndroidPaymentApp is invoked.
* @param packageManagerDelegate The package manager used used to authorize the connecting app.
* @param invokedAppPackageName The package name of the invoked payment app, used to authorize
* the connecting app.
* @param listener The listener for payment method, shipping address, and shipping option
* changes.
*/
public void initialize(PackageManagerDelegate packageManagerDelegate,
String invokedAppPackageName, PaymentRequestUpdateEventListener listener) {
synchronized (mStateLock) {
assert mListener == null;
mListener = listener;
}
mPackageInfoRwLock.writeLock().lock();
try {
mPackageManagerDelegate = packageManagerDelegate;
mInvokedAppPackageInfo =
mPackageManagerDelegate.getPackageInfoWithSignatures(invokedAppPackageName);
} finally {
mPackageInfoRwLock.writeLock().unlock();
}
}
/**
* Called to notify the merchant that the user has selected a different payment method.
* @param paymentHandlerMethodData The data containing the selected payment method's name and
* optional stringified details.
* @param callback The callback used to notify the invoked app about updated payment details.
*/
public void changePaymentMethod(
Bundle paymentHandlerMethodData, IPaymentDetailsUpdateServiceCallback callback) {
if (paymentHandlerMethodData == null) {
runCallbackWithError(ErrorStrings.METHOD_DATA_REQUIRED, callback);
return;
}
String methodName = paymentHandlerMethodData.getString(KEY_METHOD_NAME);
if (TextUtils.isEmpty(methodName)) {
runCallbackWithError(ErrorStrings.METHOD_NAME_REQUIRED, callback);
return;
}
@Nullable
String stringifiedDetails = paymentHandlerMethodData.getString(KEY_STRINGIFIED_DETAILS);
synchronized (mStateLock) {
if (isWaitingForPaymentDetailsUpdate() || mListener == null
|| !mListener.changePaymentMethodFromInvokedApp(
methodName, stringifiedDetails)) {
runCallbackWithError(ErrorStrings.INVALID_STATE, callback);
return;
}
mCallback = callback;
}
}
/**
* Called to notify the merchant that the user has selected a different shipping option.
* @param shippingOptionId The identifier of the selected shipping option.
* @param callback The callback used to notify the invoked app about updated payment details.
*/
public void changeShippingOption(
String shippingOptionId, IPaymentDetailsUpdateServiceCallback callback) {
if (TextUtils.isEmpty(shippingOptionId)) {
runCallbackWithError(ErrorStrings.SHIPPING_OPTION_ID_REQUIRED, callback);
return;
}
synchronized (mStateLock) {
if (isWaitingForPaymentDetailsUpdate() || mListener == null
|| !mListener.changeShippingOptionFromInvokedApp(shippingOptionId)) {
runCallbackWithError(ErrorStrings.INVALID_STATE, callback);
return;
}
mCallback = callback;
}
}
/**
* Called to notify the merchant that the user has selected a different shipping address.
* @param shippingAddress The selected shipping address
* @param callback The callback used to notify the invoked app about updated payment details.
*/
public void changeShippingAddress(
Bundle shippingAddress, IPaymentDetailsUpdateServiceCallback callback) {
if (shippingAddress == null || shippingAddress.isEmpty()) {
runCallbackWithError(ErrorStrings.SHIPPING_ADDRESS_INVALID, callback);
return;
}
synchronized (mStateLock) {
if (isWaitingForPaymentDetailsUpdate() || mListener == null
|| !mListener.changeShippingAddressFromInvokedApp(
PaymentAddressTypeConverter.convertAddressToMojoPaymentAddress(
Address.createFromBundle(shippingAddress)))) {
runCallbackWithError(ErrorStrings.INVALID_STATE, callback);
return;
}
mCallback = callback;
}
}
/**
* Resets the singleton instance's state.
*/
public void reset() {
synchronized (mStateLock) {
mCallback = null;
mListener = null;
}
mPackageInfoRwLock.writeLock().lock();
try {
mPackageManagerDelegate = null;
mInvokedAppPackageInfo = null;
} finally {
mPackageInfoRwLock.writeLock().unlock();
}
}
/**
* Checks whether any payment method, shipping address or shipping option change event is
* ongoing.
* @return True after invoked payment app has bound PaymentDetaialsUpdateService and called
* changePaymentMethod, changeShippingAddress, or changeShippingOption and before the
* merchant replies with either updateWith() or onPaymentDetailsNotUpdated().
*/
public boolean isWaitingForPaymentDetailsUpdate() {
synchronized (mStateLock) {
return mCallback != null;
}
}
/**
* @param callerUid The Uid of the service requester.
* @return True when the service requester's package name and signature are the same as the
* invoked payment app's.
*/
public boolean isCallerAuthorized(int callerUid) {
mPackageInfoRwLock.readLock().lock();
try {
if (mPackageManagerDelegate == null) {
Log.e(TAG, ErrorStrings.UNATHORIZED_SERVICE_REQUEST);
return false;
}
PackageInfo callerPackageInfo =
mPackageManagerDelegate.getPackageInfoWithSignatures(callerUid);
if (mInvokedAppPackageInfo == null || callerPackageInfo == null
|| !mInvokedAppPackageInfo.packageName.equals(callerPackageInfo.packageName)) {
Log.e(TAG, ErrorStrings.UNATHORIZED_SERVICE_REQUEST);
return false;
}
// TODO(https://crbug.com/1086485): signatures field is deprecated in API level 28.
Signature[] callerSignatures = callerPackageInfo.signatures;
Signature[] invokedAppSignatures = mInvokedAppPackageInfo.signatures;
boolean result = Arrays.equals(callerSignatures, invokedAppSignatures);
if (!result) Log.e(TAG, ErrorStrings.UNATHORIZED_SERVICE_REQUEST);
return result;
} finally {
mPackageInfoRwLock.readLock().unlock();
}
}
private void runCallbackWithError(String error, IPaymentDetailsUpdateServiceCallback callback) {
// TODO(https://crbug.com/1026667): Call Callback.updateWith with a
// updatedPaymentDetails bundle including the error message only.
}
}
......@@ -16,6 +16,7 @@ import org.chromium.base.annotations.NativeMethods;
@JNINamespace("payments::android")
public class PaymentFeatureList {
/** Alphabetical: */
public static final String ANDROID_APP_PAYMENT_UPDATE_EVENTS = "AndroidAppPaymentUpdateEvents";
public static final String PAYMENT_REQUEST_SKIP_TO_GPAY = "PaymentRequestSkipToGPay";
public static final String PAYMENT_REQUEST_SKIP_TO_GPAY_IF_NO_CARD =
"PaymentRequestSkipToGPayIfNoCard";
......
// Copyright 2020 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.
interface org.chromium.components.payments.IPaymentDetailsUpdateService;
interface org.chromium.components.payments.IPaymentDetailsUpdateServiceCallback;
......@@ -52,6 +52,9 @@ public abstract class ErrorStrings {{
public static final String MINIMAL_UI_SUPPRESSED = "Payment minimal UI suppressed.";
public static final String UNATHORIZED_SERVICE_REQUEST =
"Caller's signuature or package name does not match invoked app's.";
// Prevent instantiation.
private ErrorStrings() {{}}
}}
......@@ -33,6 +33,7 @@ const base::Feature* kFeaturesExposedToJava[] = {
&features::kWebPaymentsModifiers,
&features::kWebPaymentsRedactShippingAddress,
&features::kWebPaymentsSingleAppUiSkip,
&kAndroidAppPaymentUpdateEvents,
&kScrollToExpandPaymentHandler,
};
......@@ -49,6 +50,8 @@ const base::Feature* FindFeatureExposedToJava(const std::string& feature_name) {
} // namespace
// Android only features.
const base::Feature kAndroidAppPaymentUpdateEvents{
"AndroidAppPaymentUpdateEvents", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kScrollToExpandPaymentHandler{
"ScrollToExpandPaymentHandler", base::FEATURE_DISABLED_BY_DEFAULT};
......
......@@ -12,6 +12,7 @@ namespace payments {
namespace android {
// Android only payment features in alphabetical order:
extern const base::Feature kAndroidAppPaymentUpdateEvents;
extern const base::Feature kScrollToExpandPaymentHandler;
} // namespace android
......
......@@ -18,6 +18,8 @@ const char kCannotShowWithoutInit[] = "Attempted show without initialization.";
const char kCannotUpdateWithoutInit[] = "Attempted updateWith without initialization.";
const char kCannotUpdateWithoutShow[] = "Attempted updateWith without show.";
const char kInvalidState[] = "Invalid state.";
const char kMethodDataRequired[] = "Method data required.";
const char kMethodNameRequired[] = "Method name required.";
const char kMissingDetailsFromPaymentApp[] = "Payment app returned invalid response. Missing field \"details\".";
const char kMissingMethodNameFromPaymentApp[] = "Payment app returned invalid response. Missing field \"methodName\".";
const char kNotInASecureOrigin[] = "Not in a secure origin.";
......@@ -28,6 +30,7 @@ const char kProhibitedOrigin[] = "Only localhost, file://, and cryptographic sch
const char kProhibitedOriginOrInvalidSslExplanation[] = "No UI will be shown. CanMakePayment and hasEnrolledInstrument will always return false. Show will be rejected with NotSupportedError.";
const char kShippingAddressInvalid[] = "Payment app returned invalid shipping address in response.";
const char kShippingOptionEmpty[] = "Payment app returned invalid response. Missing field \"shipping option\".";
const char kShippingOptionIdRequired[] = "Shipping option identifier required.";
const char kStrictBasicCardShowReject[] = "User does not have valid information on file.";
const char kTotalRequired[] = "Total required.";
const char kUserCancelled[] = "User closed the Payment Request UI.";
......
......@@ -38,6 +38,13 @@ extern const char kCannotUpdateWithoutShow[];
// Used when an invalid state is encountered generically.
extern const char kInvalidState[];
// Used when the {"supportedMethods": "", data: {}} is required, but not
// provided.
extern const char kMethodDataRequired[];
// Used when non-empty "supportedMethods": "" is required, but not provided.
extern const char kMethodNameRequired[];
// The payment handler responded with an empty "details" field.
extern const char kMissingDetailsFromPaymentApp[];
......@@ -69,6 +76,9 @@ extern const char kShippingAddressInvalid[];
// The payment handler responded with an empty "shipping option" field.
extern const char kShippingOptionEmpty[];
// Used when non-empty "shippingOptionId": "" is required, but not provided.
extern const char kShippingOptionIdRequired[];
// Used when rejecting show() with NotSupportedError, because the user did not
// have all valid autofill data.
extern const char kStrictBasicCardShowReject[];
......
......@@ -80,10 +80,6 @@ const char kInvalidWebAppIcon[] =
"Failed to download or decode a non-empty icon for payment app with \"$1\" "
"manifest.";
const char kMethodDataRequired[] = "Method data required.";
const char kMethodNameRequired[] = "Method name required.";
const char kMultiplePaymentMethodsNotSupportedFormat[] =
"The payment methods $ are not supported.";
......@@ -141,8 +137,6 @@ const char kPaymentHandlerInsecureNavigation[] =
const char kSinglePaymentMethodNotSupportedFormat[] =
"The payment method $ is not supported.";
const char kShippingOptionIdRequired[] = "Shipping option identifier required.";
const char kCanMakePaymentEventRejected[] =
"Payment handler rejected the promise passed into "
"CanMakePaymentEvent.respondWith().";
......
......@@ -103,13 +103,6 @@ extern const char kInvalidSslCertificate[];
// work.
extern const char kInvalidWebAppIcon[];
// Used when the {"supportedMethods": "", data: {}} is required, but not
// provided.
extern const char kMethodDataRequired[];
// Used when non-empty "supportedMethods": "" is required, but not provided.
extern const char kMethodNameRequired[];
// The format for the message about multiple payment methods that are not
// supported. This format should be used with base::ReplaceChars() function,
// where "$" is the character to replace.
......@@ -171,9 +164,6 @@ extern const char kReachedMaximumNumberOfRedirects[];
// where "$" is the character to replace.
extern const char kSinglePaymentMethodNotSupportedFormat[];
// Used when non-empty "shippingOptionId": "" is required, but not provided.
extern const char kShippingOptionIdRequired[];
// The payment handler rejected the promise passed into
// CanMakePaymentEvent.respondWith().
extern const char kCanMakePaymentEventRejected[];
......
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