| // 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.intent; |
| |
| import android.os.Bundle; |
| import android.os.Parcelable; |
| import android.text.TextUtils; |
| import android.util.JsonWriter; |
| |
| import androidx.annotation.Nullable; |
| |
| import java.io.IOException; |
| import java.io.StringWriter; |
| import java.util.Collection; |
| import java.util.List; |
| /** |
| * The types that corresponds to the types in org.chromium.payments.mojom. The fields of these types |
| * are the subset of those in the mojom types. The subset is minimally selected based on the need of |
| * this package. This class should be independent of the org.chromium package. |
| * |
| * @see <a |
| * href="https://web.dev/android-payment-apps-overview/#parameters-2">Payment |
| * parameters</a> |
| * @see <a |
| * href="https://web.dev/android-payment-apps-overview/#parameters">“Is |
| * ready to pay” parameters</a> |
| */ |
| public final class WebPaymentIntentHelperType { |
| private static final String EMPTY_JSON_DATA = "{}"; |
| |
| /** |
| * The class that corresponds to mojom.PaymentCurrencyAmount, with minimally required fields. |
| */ |
| public static final class PaymentCurrencyAmount { |
| public static String EXTRA_CURRENCY = "currency"; |
| public static String EXTRA_VALUE = "value"; |
| |
| public final String currency; |
| public final String value; |
| public PaymentCurrencyAmount(String currency, String value) { |
| this.currency = currency; |
| this.value = value; |
| } |
| |
| /** |
| * Serializes this object into the provided json writer. |
| * @param json The json object to which the seri |
| */ |
| public void serialize(JsonWriter json) throws IOException { |
| // {{{ |
| json.beginObject(); |
| json.name("currency").value(currency); |
| json.name("value").value(value); |
| json.endObject(); |
| // }}} |
| } |
| /** |
| * Serializes this object |
| * @return The serialized payment currency amount. |
| */ |
| public String serialize() { |
| StringWriter stringWriter = new StringWriter(); |
| JsonWriter json = new JsonWriter(stringWriter); |
| try { |
| serialize(json); |
| } catch (IOException e) { |
| return null; |
| } |
| return stringWriter.toString(); |
| } |
| |
| /* package */ Bundle asBundle() { |
| Bundle bundle = new Bundle(); |
| bundle.putString(EXTRA_CURRENCY, currency); |
| bundle.putString(EXTRA_VALUE, value); |
| return bundle; |
| } |
| } |
| |
| /** The class that corresponds mojom.PaymentItem, with minimally required fields. */ |
| public static final class PaymentItem { |
| public final PaymentCurrencyAmount amount; |
| public PaymentItem(PaymentCurrencyAmount amount) { |
| this.amount = amount; |
| } |
| /** |
| * Serializes this object into the provided json writer after adding an empty string for the |
| * redacted "label" field. |
| * @param json The json writer used for serialization |
| */ |
| public void serializeAndRedact(JsonWriter json) throws IOException { |
| // item {{{ |
| json.beginObject(); |
| // Redact the total label, because the payment app does not need it to complete the |
| // transaction. Matches the behavior of: |
| // https://w3c.github.io/payment-handler/#total-attribute |
| json.name("label").value(""); |
| |
| // amount {{{ |
| json.name("amount"); |
| amount.serialize(json); |
| // }}} amount |
| |
| json.endObject(); |
| // }}} item |
| } |
| } |
| |
| /** The class that corresponds mojom.PaymentDetailsModifier, with minimally required fields. */ |
| public static final class PaymentDetailsModifier { |
| public final PaymentItem total; |
| public final PaymentMethodData methodData; |
| public PaymentDetailsModifier(PaymentItem total, PaymentMethodData methodData) { |
| this.total = total; |
| this.methodData = methodData; |
| } |
| |
| /** |
| * Serializes payment details modifiers. |
| * @param modifiers The collection of details modifiers to serialize. |
| * @return The serialized payment details modifiers |
| */ |
| public static String serializeModifiers(Collection<PaymentDetailsModifier> modifiers) { |
| StringWriter stringWriter = new StringWriter(); |
| JsonWriter json = new JsonWriter(stringWriter); |
| try { |
| json.beginArray(); |
| for (PaymentDetailsModifier modifier : modifiers) { |
| checkNotNull(modifier, "PaymentDetailsModifier"); |
| modifier.serialize(json); |
| } |
| json.endArray(); |
| } catch (IOException e) { |
| return EMPTY_JSON_DATA; |
| } |
| return stringWriter.toString(); |
| } |
| |
| private void serialize(JsonWriter json) throws IOException { |
| // {{{ |
| json.beginObject(); |
| |
| // total {{{ |
| if (total != null) { |
| json.name("total"); |
| total.serializeAndRedact(json); |
| } else { |
| json.name("total").nullValue(); |
| } |
| // }}} total |
| |
| // TODO(https://crbug.com/754779): The supportedMethods field was already changed from |
| // array to string but we should keep backward-compatibility for now. supportedMethods |
| // {{{ |
| json.name("supportedMethods").beginArray(); |
| json.value(methodData.supportedMethod); |
| json.endArray(); |
| // }}} supportedMethods |
| |
| // data {{{ |
| json.name("data").value(methodData.stringifiedData); |
| // }}} |
| |
| json.endObject(); |
| // }}} |
| } |
| } |
| |
| /** The class that corresponds mojom.PaymentMethodData, with minimally required fields. */ |
| public static final class PaymentMethodData { |
| public final String supportedMethod; |
| public final String stringifiedData; |
| public PaymentMethodData(String supportedMethod, String stringifiedData) { |
| this.supportedMethod = supportedMethod; |
| this.stringifiedData = stringifiedData; |
| } |
| } |
| |
| /** The class that mirrors mojom.PaymentShippingOption. */ |
| public static final class PaymentShippingOption { |
| public static final String EXTRA_SHIPPING_OPTION_ID = "id"; |
| public static final String EXTRA_SHIPPING_OPTION_LABEL = "label"; |
| public static final String EXTRA_SHIPPING_OPTION_AMOUNT = "amount"; |
| public static final String EXTRA_SHIPPING_OPTION_SELECTED = "selected"; |
| |
| public final String id; |
| public final String label; |
| public final PaymentCurrencyAmount amount; |
| public final boolean selected; |
| public PaymentShippingOption( |
| String id, String label, PaymentCurrencyAmount amount, boolean selected) { |
| this.id = id; |
| this.label = label; |
| this.amount = amount; |
| this.selected = selected; |
| } |
| |
| private Bundle asBundle() { |
| Bundle bundle = new Bundle(); |
| bundle.putString(EXTRA_SHIPPING_OPTION_ID, id); |
| bundle.putString(EXTRA_SHIPPING_OPTION_LABEL, label); |
| bundle.putBundle(EXTRA_SHIPPING_OPTION_AMOUNT, amount.asBundle()); |
| bundle.putBoolean(EXTRA_SHIPPING_OPTION_SELECTED, selected); |
| return bundle; |
| } |
| |
| /** |
| * Create a parcelable array of payment shipping options. |
| * @param shippingOptions The list of available shipping options |
| * @return The parcelable array of shipping options passed to the native payment app. |
| */ |
| public static Parcelable[] buildPaymentShippingOptionList( |
| List<PaymentShippingOption> shippingOptions) { |
| Parcelable[] result = new Parcelable[shippingOptions.size()]; |
| int index = 0; |
| for (PaymentShippingOption option : shippingOptions) { |
| result[index++] = option.asBundle(); |
| } |
| return result; |
| } |
| } |
| |
| /** The class that mirrors mojom.PaymentOptions. */ |
| public static final class PaymentOptions { |
| public final boolean requestPayerName; |
| public final boolean requestPayerEmail; |
| public final boolean requestPayerPhone; |
| public final boolean requestShipping; |
| public final String shippingType; |
| |
| public PaymentOptions(boolean requestPayerName, boolean requestPayerEmail, |
| boolean requestPayerPhone, boolean requestShipping, @Nullable String shippingType) { |
| this.requestPayerName = requestPayerName; |
| this.requestPayerEmail = requestPayerEmail; |
| this.requestPayerPhone = requestPayerPhone; |
| this.requestShipping = requestShipping; |
| this.shippingType = shippingType; |
| } |
| } |
| private static void checkNotNull(Object value, String name) { |
| if (value == null) throw new IllegalArgumentException(name + " should not be null."); |
| } |
| |
| /** The class that mirrors mojom.PaymentHandlerMethodData. */ |
| public static final class PaymentHandlerMethodData { |
| public static final String EXTRA_METHOD_NAME = "methodName"; |
| public static final String EXTRA_STRINGIFIED_DETAILS = "details"; |
| |
| public final String methodName; |
| public final String stringifiedData; |
| public PaymentHandlerMethodData(String methodName, String stringifiedData) { |
| this.methodName = methodName; |
| this.stringifiedData = stringifiedData; |
| } |
| |
| /* package */ Bundle asBundle() { |
| Bundle bundle = new Bundle(); |
| bundle.putString(EXTRA_METHOD_NAME, methodName); |
| bundle.putString(EXTRA_STRINGIFIED_DETAILS, stringifiedData); |
| return bundle; |
| } |
| } |
| |
| /** The class that mirrors mojom.PaymentRequestDetailsUpdate. */ |
| public static final class PaymentRequestDetailsUpdate { |
| public static final String EXTRA_TOTAL = "total"; |
| public static final String EXTRA_SHIPPING_OPTIONS = "shippingOptions"; |
| public static final String EXTRA_ERROR_MESSAGE = "error"; |
| public static final String EXTRA_STRINGIFIED_PAYMENT_METHOD_ERRORS = |
| "stringifiedPaymentMethodErrors"; |
| public static final String EXTRA_ADDRESS_ERRORS = "addressErrors"; |
| |
| @Nullable |
| public final PaymentCurrencyAmount total; |
| @Nullable |
| public final List<PaymentShippingOption> shippingOptions; |
| @Nullable |
| public final String error; |
| @Nullable |
| public final String stringifiedPaymentMethodErrors; |
| @Nullable |
| public final Bundle bundledShippingAddressErrors; |
| |
| public PaymentRequestDetailsUpdate(@Nullable PaymentCurrencyAmount total, |
| @Nullable List<PaymentShippingOption> shippingOptions, @Nullable String error, |
| @Nullable String stringifiedPaymentMethodErrors, |
| @Nullable Bundle bundledShippingAddressErrors) { |
| this.total = total; |
| this.shippingOptions = shippingOptions; |
| this.error = error; |
| this.stringifiedPaymentMethodErrors = stringifiedPaymentMethodErrors; |
| this.bundledShippingAddressErrors = bundledShippingAddressErrors; |
| } |
| |
| /** |
| * Converts PaymentRequestDetailsUpdate to a bundle which will be passed to the invoked |
| * payment app. |
| * @return The converted PaymentRequestDetailsUpdate |
| */ |
| public Bundle asBundle() { |
| Bundle bundle = new Bundle(); |
| if (total != null) { |
| bundle.putBundle(WebPaymentIntentHelper.EXTRA_TOTAL, total.asBundle()); |
| } |
| if (shippingOptions != null && !shippingOptions.isEmpty()) { |
| bundle.putParcelableArray(EXTRA_SHIPPING_OPTIONS, |
| PaymentShippingOption.buildPaymentShippingOptionList(shippingOptions)); |
| } |
| if (!TextUtils.isEmpty(error)) bundle.putString(EXTRA_ERROR_MESSAGE, error); |
| if (!TextUtils.isEmpty(stringifiedPaymentMethodErrors)) { |
| bundle.putString( |
| EXTRA_STRINGIFIED_PAYMENT_METHOD_ERRORS, stringifiedPaymentMethodErrors); |
| } |
| if (bundledShippingAddressErrors != null) { |
| bundle.putBundle(EXTRA_ADDRESS_ERRORS, bundledShippingAddressErrors); |
| } |
| return bundle; |
| } |
| } |
| } |