Commit 1604d0bb authored by Rouslan Solomakhin's avatar Rouslan Solomakhin Committed by Commit Bot

[Web Payment] Payment app types on Android.

Before this patch, C++ payment app implementations used an enum to
denote their type to be used for app-specific logic, while Java used
"instanceof". This prevented encapsulating multiple types of payment
apps in a single wrapper, e.g., service_worker_payment_app.cc and
android_payment_app.cc in a single JniPaymentApp.java wrapper.

This patch expands the number of payment apps, exposes the payment app
enum to Java, adds the type enum to PaymentApp.java class, and replaces
"instanceof" with enum comparison in PaymentRequestImpl.java, where it
makes sense.

After this patch, both C++ and Java payment app types are defined in an
enum, so JniPaymentApp.java can wrap multiple types of C++ payment apps
internally.

Design: https://bit.ly/cross-platform-pay-app-factory

Bug: 1022512
Change-Id: I3636f83cda85c29113ad6bd0671b430c70c67a1a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2213405
Commit-Queue: Rouslan Solomakhin <rouslan@chromium.org>
Reviewed-by: default avatarDanyao Wang <danyao@chromium.org>
Cr-Commit-Position: refs/heads/master@{#772173}
parent fe913145
...@@ -21,6 +21,7 @@ import org.chromium.chrome.browser.ChromeActivity; ...@@ -21,6 +21,7 @@ import org.chromium.chrome.browser.ChromeActivity;
import org.chromium.components.payments.ErrorStrings; import org.chromium.components.payments.ErrorStrings;
import org.chromium.components.payments.PayerData; import org.chromium.components.payments.PayerData;
import org.chromium.components.payments.PaymentApp; import org.chromium.components.payments.PaymentApp;
import org.chromium.components.payments.PaymentAppType;
import org.chromium.components.payments.intent.IsReadyToPayServiceHelper; import org.chromium.components.payments.intent.IsReadyToPayServiceHelper;
import org.chromium.components.payments.intent.WebPaymentIntentHelper; import org.chromium.components.payments.intent.WebPaymentIntentHelper;
import org.chromium.components.payments.intent.WebPaymentIntentHelperType; import org.chromium.components.payments.intent.WebPaymentIntentHelperType;
...@@ -401,4 +402,9 @@ public class AndroidPaymentApp ...@@ -401,4 +402,9 @@ public class AndroidPaymentApp
PostTask.runOrPostTask( PostTask.runOrPostTask(
UiThreadTaskTraits.DEFAULT, () -> respondToIsReadyToPayQuery(isReadyToPay)); UiThreadTaskTraits.DEFAULT, () -> respondToIsReadyToPayQuery(isReadyToPay));
} }
@Override
public @PaymentAppType int getPaymentAppType() {
return PaymentAppType.NATIVE_MOBILE_APP;
}
} }
...@@ -23,6 +23,7 @@ import org.chromium.components.payments.ErrorStrings; ...@@ -23,6 +23,7 @@ import org.chromium.components.payments.ErrorStrings;
import org.chromium.components.payments.PayerData; import org.chromium.components.payments.PayerData;
import org.chromium.components.payments.PaymentApp; import org.chromium.components.payments.PaymentApp;
import org.chromium.components.payments.PaymentApp.InstrumentDetailsCallback; import org.chromium.components.payments.PaymentApp.InstrumentDetailsCallback;
import org.chromium.components.payments.PaymentAppType;
import org.chromium.components.payments.PaymentFeatureList; import org.chromium.components.payments.PaymentFeatureList;
import org.chromium.content_public.browser.WebContents; import org.chromium.content_public.browser.WebContents;
import org.chromium.payments.mojom.PaymentDetailsModifier; import org.chromium.payments.mojom.PaymentDetailsModifier;
...@@ -460,4 +461,9 @@ public class AutofillPaymentInstrument ...@@ -460,4 +461,9 @@ public class AutofillPaymentInstrument
return missingFields; return missingFields;
} }
@Override
public @PaymentAppType int getPaymentAppType() {
return PaymentAppType.AUTOFILL;
}
} }
...@@ -59,6 +59,7 @@ import org.chromium.components.payments.MethodStrings; ...@@ -59,6 +59,7 @@ import org.chromium.components.payments.MethodStrings;
import org.chromium.components.payments.OriginSecurityChecker; import org.chromium.components.payments.OriginSecurityChecker;
import org.chromium.components.payments.PayerData; import org.chromium.components.payments.PayerData;
import org.chromium.components.payments.PaymentApp; import org.chromium.components.payments.PaymentApp;
import org.chromium.components.payments.PaymentAppType;
import org.chromium.components.payments.PaymentDetailsConverter; import org.chromium.components.payments.PaymentDetailsConverter;
import org.chromium.components.payments.PaymentFeatureList; import org.chromium.components.payments.PaymentFeatureList;
import org.chromium.components.payments.PaymentHandlerHost; import org.chromium.components.payments.PaymentHandlerHost;
...@@ -1046,13 +1047,14 @@ public class PaymentRequestImpl ...@@ -1046,13 +1047,14 @@ public class PaymentRequestImpl
private void dimBackgroundIfNotBottomSheetPaymentHandler(PaymentApp selectedApp) { private void dimBackgroundIfNotBottomSheetPaymentHandler(PaymentApp selectedApp) {
// Putting isEnabled() last is intentional. It's to ensure not to confused the unexecuted // Putting isEnabled() last is intentional. It's to ensure not to confused the unexecuted
// group and the disabled in A/B testing. // group and the disabled in A/B testing.
if ((selectedApp instanceof ServiceWorkerPaymentApp) if (selectedApp != null
&& selectedApp.getPaymentAppType() == PaymentAppType.SERVICE_WORKER_APP
&& PaymentHandlerCoordinator.isEnabled()) { && PaymentHandlerCoordinator.isEnabled()) {
// When the Payment Handler (PH) UI is based on Activity, dimming the Payment // When the Payment Handler (PH) UI is based on Activity, dimming the Payment
// Request (PR) UI does not dim the PH; when it's based on bottom-sheet, dimming // Request (PR) UI does not dim the PH; when it's based on bottom-sheet, dimming
// the PR dims both UIs. As bottom-sheet itself has dimming effect, dimming PR // the PR dims both UIs. As bottom-sheet itself has dimming effect, dimming PR
// is unnecessary for the bottom-sheet PH. For now, ServiceWorkerPaymentApp is the only // is unnecessary for the bottom-sheet PH. For now, service worker based payment apps
// payment app that can open the bottom-sheet. // are the only ones that can open the bottom-sheet.
return; return;
} }
mUI.dimBackground(); mUI.dimBackground();
...@@ -1332,7 +1334,7 @@ public class PaymentRequestImpl ...@@ -1332,7 +1334,7 @@ public class PaymentRequestImpl
private boolean openPaymentHandlerWindowInternal( private boolean openPaymentHandlerWindowInternal(
GURL url, PaymentHandlerWebContentsObserver paymentHandlerWebContentsObserver) { GURL url, PaymentHandlerWebContentsObserver paymentHandlerWebContentsObserver) {
assert mInvokedPaymentApp != null; assert mInvokedPaymentApp != null;
assert mInvokedPaymentApp instanceof ServiceWorkerPaymentApp; assert mInvokedPaymentApp.getPaymentAppType() == PaymentAppType.SERVICE_WORKER_APP;
assert org.chromium.components.embedder_support.util.Origin.create(url.getSpec()) assert org.chromium.components.embedder_support.util.Origin.create(url.getSpec())
.equals(org.chromium.components.embedder_support.util.Origin.create( .equals(org.chromium.components.embedder_support.util.Origin.create(
((ServiceWorkerPaymentApp) mInvokedPaymentApp).getScope().getSpec())); ((ServiceWorkerPaymentApp) mInvokedPaymentApp).getScope().getSpec()));
...@@ -1753,7 +1755,7 @@ public class PaymentRequestImpl ...@@ -1753,7 +1755,7 @@ public class PaymentRequestImpl
// Do not display service worker payment apps summary in single line so as to display its // Do not display service worker payment apps summary in single line so as to display its
// origin completely. // origin completely.
mPaymentMethodsSection.setDisplaySelectedItemSummaryInSingleLineInNormalMode( mPaymentMethodsSection.setDisplaySelectedItemSummaryInSingleLineInNormalMode(
!(mPaymentMethodsSection.getSelectedItem() instanceof ServiceWorkerPaymentApp)); getSelectedPaymentAppType() != PaymentAppType.SERVICE_WORKER_APP);
mPaymentInformationCallback.onResult( mPaymentInformationCallback.onResult(
new PaymentInformation(mUiShoppingCart, mShippingAddressesSection, new PaymentInformation(mUiShoppingCart, mShippingAddressesSection,
mUiShippingOptions, mContactSection, mPaymentMethodsSection)); mUiShippingOptions, mContactSection, mPaymentMethodsSection));
...@@ -2075,11 +2077,17 @@ public class PaymentRequestImpl ...@@ -2075,11 +2077,17 @@ public class PaymentRequestImpl
public void onInstrumentDetailsLoadingWithoutUI() { public void onInstrumentDetailsLoadingWithoutUI() {
if (mClient == null || mUI == null || mPaymentResponseHelper == null) return; if (mClient == null || mUI == null || mPaymentResponseHelper == null) return;
assert mPaymentMethodsSection.getSelectedItem() instanceof AutofillPaymentInstrument; assert getSelectedPaymentAppType() == PaymentAppType.AUTOFILL;
mUI.showProcessingMessage(); mUI.showProcessingMessage();
} }
private @PaymentAppType int getSelectedPaymentAppType() {
return mPaymentMethodsSection != null && mPaymentMethodsSection.getSelectedItem() != null
? ((PaymentApp) mPaymentMethodsSection.getSelectedItem()).getPaymentAppType()
: PaymentAppType.UNDEFINED;
}
@Override @Override
public boolean onPayClicked(EditableOption selectedShippingAddress, public boolean onPayClicked(EditableOption selectedShippingAddress,
EditableOption selectedShippingOption, EditableOption selectedPaymentMethod) { EditableOption selectedShippingOption, EditableOption selectedPaymentMethod) {
...@@ -2822,8 +2830,9 @@ public class PaymentRequestImpl ...@@ -2822,8 +2830,9 @@ public class PaymentRequestImpl
if (mClient == null || mPaymentResponseHelper == null) return; if (mClient == null || mPaymentResponseHelper == null) return;
// If the payment method was an Autofill credit card with an identifier, record its use. // If the payment method was an Autofill credit card with an identifier, record its use.
EditableOption selectedPaymentMethod = mPaymentMethodsSection.getSelectedItem(); PaymentApp selectedPaymentMethod = (PaymentApp) mPaymentMethodsSection.getSelectedItem();
if (selectedPaymentMethod instanceof AutofillPaymentInstrument if (selectedPaymentMethod != null
&& selectedPaymentMethod.getPaymentAppType() == PaymentAppType.AUTOFILL
&& !selectedPaymentMethod.getIdentifier().isEmpty()) { && !selectedPaymentMethod.getIdentifier().isEmpty()) {
PersonalDataManager.getInstance().recordAndLogCreditCardUse( PersonalDataManager.getInstance().recordAndLogCreditCardUse(
selectedPaymentMethod.getIdentifier()); selectedPaymentMethod.getIdentifier());
......
...@@ -12,6 +12,7 @@ import androidx.annotation.Nullable; ...@@ -12,6 +12,7 @@ import androidx.annotation.Nullable;
import org.chromium.components.payments.MethodStrings; import org.chromium.components.payments.MethodStrings;
import org.chromium.components.payments.PaymentApp; import org.chromium.components.payments.PaymentApp;
import org.chromium.components.payments.PaymentApp.InstrumentDetailsCallback; import org.chromium.components.payments.PaymentApp.InstrumentDetailsCallback;
import org.chromium.components.payments.PaymentAppType;
import org.chromium.components.payments.PaymentHandlerHost; import org.chromium.components.payments.PaymentHandlerHost;
import org.chromium.content_public.browser.WebContents; import org.chromium.content_public.browser.WebContents;
import org.chromium.payments.mojom.PaymentDetailsModifier; import org.chromium.payments.mojom.PaymentDetailsModifier;
...@@ -378,4 +379,9 @@ public class ServiceWorkerPaymentApp extends PaymentApp { ...@@ -378,4 +379,9 @@ public class ServiceWorkerPaymentApp extends PaymentApp {
} }
return mUkmSourceId; return mUkmSourceId;
} }
@Override
public @PaymentAppType int getPaymentAppType() {
return PaymentAppType.SERVICE_WORKER_APP;
}
} }
...@@ -90,9 +90,14 @@ class PaymentMethodListItem : public PaymentRequestItemList::Item { ...@@ -90,9 +90,14 @@ class PaymentMethodListItem : public PaymentRequestItemList::Item {
base::OnceCallback<void(const autofill::CreditCard&)>(), base::OnceCallback<void(const autofill::CreditCard&)>(),
static_cast<AutofillPaymentApp*>(app_)->credit_card()); static_cast<AutofillPaymentApp*>(app_)->credit_card());
return; return;
case PaymentApp::Type::UNDEFINED:
// Intentionally fall through.
case PaymentApp::Type::NATIVE_MOBILE_APP: case PaymentApp::Type::NATIVE_MOBILE_APP:
// Intentionally fall through.
case PaymentApp::Type::SERVICE_WORKER_APP: case PaymentApp::Type::SERVICE_WORKER_APP:
// We cannot edit a native mobile app and service worker app. // Intentionally fall through.
case PaymentApp::Type::INTERNAL:
// We cannot edit these types of payment apps.
return; return;
} }
NOTREACHED(); NOTREACHED();
......
...@@ -97,7 +97,10 @@ android_library("java") { ...@@ -97,7 +97,10 @@ android_library("java") {
"//url:gurl_java", "//url:gurl_java",
"//url:origin_java", "//url:origin_java",
] ]
srcjar_deps = [ ":error_strings_generated_srcjar" ] srcjar_deps = [
":error_strings_generated_srcjar",
":payment_app_type_generated_enum",
]
} }
java_cpp_strings("error_strings_generated_srcjar") { java_cpp_strings("error_strings_generated_srcjar") {
...@@ -111,3 +114,7 @@ java_cpp_strings("method_strings_generated_srcjar") { ...@@ -111,3 +114,7 @@ java_cpp_strings("method_strings_generated_srcjar") {
template = "java_templates/MethodStrings.java.tmpl" template = "java_templates/MethodStrings.java.tmpl"
} }
java_cpp_enum("payment_app_type_generated_enum") {
sources = [ "//components/payments/content/payment_app.h" ]
}
...@@ -312,4 +312,9 @@ public abstract class PaymentApp extends EditableOption { ...@@ -312,4 +312,9 @@ public abstract class PaymentApp extends EditableOption {
* @param host The endpoint for payment handler communication. Should not be null. * @param host The endpoint for payment handler communication. Should not be null.
*/ */
public void setPaymentHandlerHost(PaymentHandlerHost host) {} public void setPaymentHandlerHost(PaymentHandlerHost host) {}
/** @return The type of payment app. */
public @PaymentAppType int getPaymentAppType() {
return PaymentAppType.UNDEFINED;
}
} }
...@@ -17,12 +17,15 @@ namespace { ...@@ -17,12 +17,15 @@ namespace {
// Returns the sorting group of a payment app. This is used to order payment // Returns the sorting group of a payment app. This is used to order payment
// apps in the order of: // apps in the order of:
// 1. Installed 3rd-party payment handlers // 1. Built-in 1st-party payment handlers.
// 2. Complete autofill instruments // 2. Installed 3rd-party payment handlers
// 3. Just-in-time installable payment handlers that is not yet installed. // 3. Complete autofill instruments
// 4. Incomplete autofill instruments // 4. Just-in-time installable payment handlers that is not yet installed.
// 5. Incomplete autofill instruments
int GetSortingGroup(const PaymentApp& app) { int GetSortingGroup(const PaymentApp& app) {
switch (app.type()) { switch (app.type()) {
case PaymentApp::Type::INTERNAL:
return 1;
case PaymentApp::Type::SERVICE_WORKER_APP: case PaymentApp::Type::SERVICE_WORKER_APP:
case PaymentApp::Type::NATIVE_MOBILE_APP: case PaymentApp::Type::NATIVE_MOBILE_APP:
// If the experimental feature is enabled, sort 3rd-party payment handlers // If the experimental feature is enabled, sort 3rd-party payment handlers
...@@ -30,14 +33,17 @@ int GetSortingGroup(const PaymentApp& app) { ...@@ -30,14 +33,17 @@ int GetSortingGroup(const PaymentApp& app) {
if (app.NeedsInstallation() && if (app.NeedsInstallation() &&
PaymentsExperimentalFeatures::IsEnabled( PaymentsExperimentalFeatures::IsEnabled(
features::kDownRankJustInTimePaymentApp)) { features::kDownRankJustInTimePaymentApp)) {
return 3; return 4;
} }
return 1; return 2;
case PaymentApp::Type::AUTOFILL: case PaymentApp::Type::AUTOFILL:
if (app.IsCompleteForPayment()) { if (app.IsCompleteForPayment()) {
return 2; return 3;
} }
return 4; return 5;
case PaymentApp::Type::UNDEFINED:
NOTREACHED();
return 99;
} }
} }
} // namespace } // namespace
......
...@@ -28,7 +28,24 @@ class PaymentHandlerHost; ...@@ -28,7 +28,24 @@ class PaymentHandlerHost;
class PaymentApp { class PaymentApp {
public: public:
// The type of this app instance. // The type of this app instance.
enum class Type { AUTOFILL, NATIVE_MOBILE_APP, SERVICE_WORKER_APP }; // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.components.payments
// GENERATED_JAVA_CLASS_NAME_OVERRIDE: PaymentAppType
enum class Type {
// Undefined type of payment app. Can be used for setting the default return
// value of an abstract class or an interface.
UNDEFINED,
// The payment app built into the browser that uses the autofill data.
AUTOFILL,
// A 3rd-party platform-specific mobile app, such as an Android app
// integrated via
// https://developers.google.com/web/fundamentals/payments/payment-apps-developer-guide/android-payment-apps
NATIVE_MOBILE_APP,
// A 3rd-party cross-platform service worked based payment app.
SERVICE_WORKER_APP,
// An internal 1st-party payment app, e.g., Google Pay on Chrome or Samsung
// Pay on Samsung Internet.
INTERNAL,
};
class Delegate { class Delegate {
public: public:
......
...@@ -658,7 +658,11 @@ void PaymentRequest::OnPaymentResponseAvailable( ...@@ -658,7 +658,11 @@ void PaymentRequest::OnPaymentResponseAvailable(
: JourneyLogger::Event::EVENT_SELECTED_OTHER; : JourneyLogger::Event::EVENT_SELECTED_OTHER;
break; break;
} }
case PaymentApp::Type::UNDEFINED:
// Intentionally fall through.
case PaymentApp::Type::NATIVE_MOBILE_APP: case PaymentApp::Type::NATIVE_MOBILE_APP:
// Intentionally fall through.
case PaymentApp::Type::INTERNAL:
NOTREACHED(); NOTREACHED();
break; break;
} }
......
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