1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 package org.chromium.components.payments;
6 
7 import android.graphics.drawable.Drawable;
8 
9 import androidx.annotation.Nullable;
10 
11 import org.chromium.base.task.PostTask;
12 import org.chromium.components.autofill.EditableOption;
13 import org.chromium.content_public.browser.UiThreadTaskTraits;
14 import org.chromium.payments.mojom.PaymentDetailsModifier;
15 import org.chromium.payments.mojom.PaymentItem;
16 import org.chromium.payments.mojom.PaymentMethodData;
17 import org.chromium.payments.mojom.PaymentOptions;
18 import org.chromium.payments.mojom.PaymentRequestDetailsUpdate;
19 import org.chromium.payments.mojom.PaymentShippingOption;
20 
21 import java.util.List;
22 import java.util.Map;
23 import java.util.Set;
24 
25 /**
26  * The base class for a single payment app, e.g., a payment handler.
27  */
28 public abstract class PaymentApp extends EditableOption {
29     /**
30      * Whether complete and valid autofill data for merchant's request is available, e.g., if
31      * merchant specifies `requestPayerEmail: true`, then this variable is true only if the autofill
32      * data contains a valid email address. May be used in canMakePayment() for some types of
33      * app, such as AutofillPaymentInstrument.
34      */
35     protected boolean mHaveRequestedAutofillData;
36 
37     /**
38      * The interface for the requester of payment details from the app.
39      */
40     public interface InstrumentDetailsCallback {
41         /**
42          * Called by the payment app to let Chrome know that the payment app's UI is now hidden, but
43          * the payment details have not been returned yet. This is a good time to show a "loading"
44          * progress indicator UI.
45          */
onInstrumentDetailsLoadingWithoutUI()46         void onInstrumentDetailsLoadingWithoutUI();
47 
48         /**
49          * Called after retrieving payment details.
50          *
51          * @param methodName         Method name. For example, "visa".
52          * @param stringifiedDetails JSON-serialized object. For example, {"card": "123"}.
53          * @param payerData          Payer's shipping address and contact information.
54          */
onInstrumentDetailsReady( String methodName, String stringifiedDetails, PayerData payerData)55         void onInstrumentDetailsReady(
56                 String methodName, String stringifiedDetails, PayerData payerData);
57 
58         /**
59          * Called if unable to retrieve payment details.
60          * @param errorMessage Developer-facing error message to be used when rejecting the promise
61          *                     returned from PaymentRequest.show().
62          */
onInstrumentDetailsError(String errorMessage)63         void onInstrumentDetailsError(String errorMessage);
64     }
65 
66     /** The interface for the requester to abort payment. */
67     public interface AbortCallback {
68         /**
69          * Called after aborting payment is finished.
70          *
71          * @param abortSucceeded Indicates whether abort is succeed.
72          */
onInstrumentAbortResult(boolean abortSucceeded)73         void onInstrumentAbortResult(boolean abortSucceeded);
74     }
75 
PaymentApp(String id, String label, String sublabel, Drawable icon)76     protected PaymentApp(String id, String label, String sublabel, Drawable icon) {
77         super(id, label, sublabel, icon);
78     }
79 
PaymentApp( String id, String label, String sublabel, String tertiarylabel, Drawable icon)80     protected PaymentApp(
81             String id, String label, String sublabel, String tertiarylabel, Drawable icon) {
82         super(id, label, sublabel, tertiarylabel, icon);
83     }
84 
85     /**
86      * Sets the modified total for this payment app.
87      *
88      * @param modifiedTotal The new modified total to use.
89      */
setModifiedTotal(@ullable String modifiedTotal)90     public void setModifiedTotal(@Nullable String modifiedTotal) {
91         updatePromoMessage(modifiedTotal);
92     }
93 
94     /**
95      * Returns a set of payment method names for this app, e.g., "basic-card".
96      *
97      * @return The method names for this app.
98      */
getInstrumentMethodNames()99     public abstract Set<String> getInstrumentMethodNames();
100 
101     /**
102      * @return Whether this is an autofill app. All autofill apps are sorted below all non-autofill
103      *         apps.
104      */
isAutofillInstrument()105     public boolean isAutofillInstrument() {
106         return false;
107     }
108 
109     /** @return Whether this is a server autofill app. */
isServerAutofillInstrument()110     public boolean isServerAutofillInstrument() {
111         return false;
112     }
113 
114     /**
115      * @return Whether this is a replacement for all server autofill apps. If at least one of
116      *         the displayed apps returns true here, then all apps that return true in
117      *         isServerAutofillInstrument() should be hidden.
118      */
isServerAutofillInstrumentReplacement()119     public boolean isServerAutofillInstrumentReplacement() {
120         return false;
121     }
122 
123     /**
124      * @return Whether the app supports the payment method with the method data. For example,
125      *         supported card types and networks in the data should be verified for 'basic-card'
126      *         payment method.
127      */
isValidForPaymentMethodData(String method, @Nullable PaymentMethodData data)128     public boolean isValidForPaymentMethodData(String method, @Nullable PaymentMethodData data) {
129         return getInstrumentMethodNames().contains(method);
130     }
131 
132     /**
133      * @return Whether the app can collect and return shipping address.
134      */
handlesShippingAddress()135     public boolean handlesShippingAddress() {
136         return false;
137     }
138 
139     /**
140      * @return Whether the app can collect and return payer's name.
141      */
handlesPayerName()142     public boolean handlesPayerName() {
143         return false;
144     }
145 
146     /**
147      * @return Whether the app can collect and return payer's email.
148      */
handlesPayerEmail()149     public boolean handlesPayerEmail() {
150         return false;
151     }
152 
153     /**
154      * @return Whether the app can collect and return payer's phone.
155      */
handlesPayerPhone()156     public boolean handlesPayerPhone() {
157         return false;
158     }
159 
160     /** @return The country code (or null if none) associated with this payment app. */
161     @Nullable
getCountryCode()162     public String getCountryCode() {
163         return null;
164     }
165 
166     /**
167      * @param haveRequestedAutofillData Whether complete and valid autofill data for merchant's
168      *                                  request is available.
169      */
setHaveRequestedAutofillData(boolean haveRequestedAutofillData)170     public void setHaveRequestedAutofillData(boolean haveRequestedAutofillData) {
171         mHaveRequestedAutofillData = haveRequestedAutofillData;
172     }
173 
174     /**
175      * @return Whether presence of this payment app should cause the
176      *         PaymentRequest.canMakePayment() to return true.
177      */
canMakePayment()178     public boolean canMakePayment() {
179         return true;
180     }
181 
182     /** @return Whether this payment app can be pre-selected for immediate payment. */
canPreselect()183     public boolean canPreselect() {
184         return true;
185     }
186 
187     /** @return Whether skip-UI flow with this app requires a user gesture. */
isUserGestureRequiredToSkipUi()188     public boolean isUserGestureRequiredToSkipUi() {
189         return true;
190     }
191 
192     /**
193      * Invoke the payment app to retrieve the payment details.
194      *
195      * The callback will be invoked with the resulting payment details or error.
196      *
197      * @param id               The unique identifier of the PaymentRequest.
198      * @param merchantName     The name of the merchant.
199      * @param origin           The origin of this merchant.
200      * @param iframeOrigin     The origin of the iframe that invoked PaymentRequest.
201      * @param certificateChain The site certificate chain of the merchant. Can be null for localhost
202      *                         or local file, which are secure contexts without SSL.
203      * @param methodDataMap    The payment-method specific data for all applicable payment methods,
204      *                         e.g., whether the app should be invoked in test or production, a
205      *                         merchant identifier, or a public key.
206      * @param total            The total amount.
207      * @param displayItems     The shopping cart items.
208      * @param modifiers        The relevant payment details modifiers.
209      * @param paymentOptions   The payment options of the PaymentRequest.
210      * @param shippingOptions  The shipping options of the PaymentRequest.
211      * @param callback         The object that will receive the payment details.
212      */
invokePaymentApp(String id, String merchantName, String origin, String iframeOrigin, @Nullable byte[][] certificateChain, Map<String, PaymentMethodData> methodDataMap, PaymentItem total, List<PaymentItem> displayItems, Map<String, PaymentDetailsModifier> modifiers, PaymentOptions paymentOptions, List<PaymentShippingOption> shippingOptions, InstrumentDetailsCallback callback)213     public void invokePaymentApp(String id, String merchantName, String origin, String iframeOrigin,
214             @Nullable byte[][] certificateChain, Map<String, PaymentMethodData> methodDataMap,
215             PaymentItem total, List<PaymentItem> displayItems,
216             Map<String, PaymentDetailsModifier> modifiers, PaymentOptions paymentOptions,
217             List<PaymentShippingOption> shippingOptions, InstrumentDetailsCallback callback) {}
218 
219     /**
220      * Update the payment information in response to payment method, shipping address, or shipping
221      * option change events.
222      *
223      * @param response The merchant's response to the payment method, shipping address, or shipping
224      *         option change events.
225      */
updateWith(PaymentRequestDetailsUpdate response)226     public void updateWith(PaymentRequestDetailsUpdate response) {}
227 
228     /**
229      * Called when the merchant ignored the payment method, shipping address or shipping option
230      * change event.
231      */
onPaymentDetailsNotUpdated()232     public void onPaymentDetailsNotUpdated() {}
233 
234     /**
235      * @return True after changePaymentMethodFromInvokedApp(), changeShippingOptionFromInvokedApp(),
236      *         or changeShippingAddressFromInvokedApp() and before update updateWith() or
237      *         onPaymentDetailsNotUpdated().
238      */
isWaitingForPaymentDetailsUpdate()239     public boolean isWaitingForPaymentDetailsUpdate() {
240         return false;
241     }
242 
243     /**
244      * Abort invocation of the payment app.
245      * @param callback The callback to return abort result.
246      */
abortPaymentApp(AbortCallback callback)247     public void abortPaymentApp(AbortCallback callback) {
248         PostTask.postTask(UiThreadTaskTraits.DEFAULT, new Runnable() {
249             @Override
250             public void run() {
251                 callback.onInstrumentAbortResult(false);
252             }
253         });
254     }
255 
256     /** Cleans up any resources held by the payment app. For example, closes server connections. */
dismissInstrument()257     public abstract void dismissInstrument();
258 
259     /** @return Whether the payment app is ready for a minimal UI flow. */
isReadyForMinimalUI()260     public boolean isReadyForMinimalUI() {
261         return false;
262     }
263 
264     /** @return Account balance for minimal UI flow. */
265     @Nullable
accountBalance()266     public String accountBalance() {
267         return null;
268     }
269 
270     /** Disable opening a window for this payment app. */
disableShowingOwnUI()271     public void disableShowingOwnUI() {}
272 
273     /**
274      * @return The identifier for another payment app that should be hidden when this payment app is
275      * present.
276      */
277     @Nullable
getApplicationIdentifierToHide()278     public String getApplicationIdentifierToHide() {
279         return null;
280     }
281 
282     /**
283      * @return The set of identifier of other apps that would cause this app to be hidden, if any of
284      * them are present, e.g., ["com.bobpay.production", "com.bobpay.beta"].
285      */
286     @Nullable
getApplicationIdentifiersThatHideThisApp()287     public Set<String> getApplicationIdentifiersThatHideThisApp() {
288         return null;
289     }
290 
291     /**
292      * @return The ukm source id assigned to the payment app.
293      */
getUkmSourceId()294     public long getUkmSourceId() {
295         return 0;
296     }
297 
298     /**
299      * Sets the endpoint for payment handler communication. Must be called before invoking this
300      * payment app. Used only by payment apps that are backed by a payment handler.
301      * @param host The endpoint for payment handler communication. Should not be null.
302      */
setPaymentHandlerHost(PaymentHandlerHost host)303     public void setPaymentHandlerHost(PaymentHandlerHost host) {}
304 
305     /** @return The type of payment app. */
getPaymentAppType()306     public @PaymentAppType int getPaymentAppType() {
307         return PaymentAppType.UNDEFINED;
308     }
309 
310     /**
311      * @return Whether this app should be chosen over other available payment apps. For example,
312      * when the Play Billing payment app is available in a TWA.
313      */
isPreferred()314     public boolean isPreferred() {
315         return false;
316     }
317 }
318