OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 package org.chromium.chrome.browser.payments; | 5 package org.chromium.chrome.browser.payments; |
6 | 6 |
7 import android.app.Activity; | 7 import android.app.Activity; |
8 import android.graphics.Bitmap; | 8 import android.graphics.Bitmap; |
9 import android.os.Handler; | 9 import android.os.Handler; |
| 10 import android.support.v4.util.ArrayMap; |
10 import android.text.TextUtils; | 11 import android.text.TextUtils; |
11 | 12 |
12 import org.chromium.base.Callback; | 13 import org.chromium.base.Callback; |
13 import org.chromium.base.Log; | 14 import org.chromium.base.Log; |
14 import org.chromium.base.VisibleForTesting; | 15 import org.chromium.base.VisibleForTesting; |
15 import org.chromium.base.metrics.RecordHistogram; | 16 import org.chromium.base.metrics.RecordHistogram; |
16 import org.chromium.chrome.R; | 17 import org.chromium.chrome.R; |
17 import org.chromium.chrome.browser.ChromeActivity; | 18 import org.chromium.chrome.browser.ChromeActivity; |
18 import org.chromium.chrome.browser.ChromeFeatureList; | 19 import org.chromium.chrome.browser.ChromeFeatureList; |
19 import org.chromium.chrome.browser.autofill.PersonalDataManager; | 20 import org.chromium.chrome.browser.autofill.PersonalDataManager; |
(...skipping 10 matching lines...) Expand all Loading... |
30 import org.chromium.chrome.browser.tab.Tab; | 31 import org.chromium.chrome.browser.tab.Tab; |
31 import org.chromium.chrome.browser.tabmodel.EmptyTabModelObserver; | 32 import org.chromium.chrome.browser.tabmodel.EmptyTabModelObserver; |
32 import org.chromium.chrome.browser.tabmodel.EmptyTabModelSelectorObserver; | 33 import org.chromium.chrome.browser.tabmodel.EmptyTabModelSelectorObserver; |
33 import org.chromium.chrome.browser.tabmodel.TabModel; | 34 import org.chromium.chrome.browser.tabmodel.TabModel; |
34 import org.chromium.chrome.browser.tabmodel.TabModel.TabSelectionType; | 35 import org.chromium.chrome.browser.tabmodel.TabModel.TabSelectionType; |
35 import org.chromium.chrome.browser.tabmodel.TabModelObserver; | 36 import org.chromium.chrome.browser.tabmodel.TabModelObserver; |
36 import org.chromium.chrome.browser.tabmodel.TabModelSelectorObserver; | 37 import org.chromium.chrome.browser.tabmodel.TabModelSelectorObserver; |
37 import org.chromium.components.url_formatter.UrlFormatter; | 38 import org.chromium.components.url_formatter.UrlFormatter; |
38 import org.chromium.content_public.browser.WebContents; | 39 import org.chromium.content_public.browser.WebContents; |
39 import org.chromium.mojo.system.MojoException; | 40 import org.chromium.mojo.system.MojoException; |
| 41 import org.chromium.payments.mojom.ActivePaymentQueryResult; |
40 import org.chromium.payments.mojom.PaymentComplete; | 42 import org.chromium.payments.mojom.PaymentComplete; |
41 import org.chromium.payments.mojom.PaymentDetails; | 43 import org.chromium.payments.mojom.PaymentDetails; |
42 import org.chromium.payments.mojom.PaymentErrorReason; | 44 import org.chromium.payments.mojom.PaymentErrorReason; |
43 import org.chromium.payments.mojom.PaymentItem; | 45 import org.chromium.payments.mojom.PaymentItem; |
44 import org.chromium.payments.mojom.PaymentMethodData; | 46 import org.chromium.payments.mojom.PaymentMethodData; |
45 import org.chromium.payments.mojom.PaymentOptions; | 47 import org.chromium.payments.mojom.PaymentOptions; |
46 import org.chromium.payments.mojom.PaymentRequest; | 48 import org.chromium.payments.mojom.PaymentRequest; |
47 import org.chromium.payments.mojom.PaymentRequestClient; | 49 import org.chromium.payments.mojom.PaymentRequestClient; |
48 import org.chromium.payments.mojom.PaymentResponse; | 50 import org.chromium.payments.mojom.PaymentResponse; |
49 import org.chromium.payments.mojom.PaymentShippingOption; | 51 import org.chromium.payments.mojom.PaymentShippingOption; |
50 import org.chromium.payments.mojom.PaymentShippingType; | 52 import org.chromium.payments.mojom.PaymentShippingType; |
51 | 53 |
52 import java.util.ArrayList; | 54 import java.util.ArrayList; |
53 import java.util.Arrays; | 55 import java.util.Arrays; |
54 import java.util.Collections; | 56 import java.util.Collections; |
55 import java.util.Comparator; | 57 import java.util.Comparator; |
56 import java.util.HashMap; | |
57 import java.util.HashSet; | 58 import java.util.HashSet; |
58 import java.util.List; | 59 import java.util.List; |
59 import java.util.Locale; | 60 import java.util.Locale; |
60 import java.util.Map; | 61 import java.util.Map; |
61 import java.util.Set; | 62 import java.util.Set; |
62 | 63 |
63 /** | 64 /** |
64 * Android implementation of the PaymentRequest service defined in | 65 * Android implementation of the PaymentRequest service defined in |
65 * components/payments/payment_request.mojom. | 66 * components/payments/payment_request.mojom. |
66 */ | 67 */ |
67 public class PaymentRequestImpl implements PaymentRequest, PaymentRequestUI.Clie
nt, | 68 public class PaymentRequestImpl implements PaymentRequest, PaymentRequestUI.Clie
nt, |
68 PaymentApp.InstrumentsCallback, PaymentInstrument.InstrumentDetailsCallb
ack, | 69 PaymentApp.InstrumentsCallback, PaymentInstrument.InstrumentDetailsCallb
ack, |
69 PaymentResponseHelper.PaymentResponseRequesterDelegate { | 70 PaymentResponseHelper.PaymentResponseRequesterDelegate { |
70 /** | 71 /** |
71 * Observer to be notified when PaymentRequest UI has been dismissed. | |
72 */ | |
73 public interface PaymentRequestDismissObserver { | |
74 /** | |
75 * Called when PaymentRequest UI has been dismissed. | |
76 */ | |
77 void onPaymentRequestDismissed(); | |
78 } | |
79 | |
80 /** | |
81 * A test-only observer for the PaymentRequest service implementation. | 72 * A test-only observer for the PaymentRequest service implementation. |
82 */ | 73 */ |
83 public interface PaymentRequestServiceObserverForTest { | 74 public interface PaymentRequestServiceObserverForTest { |
84 /** | 75 /** |
85 * Called when an abort request was denied. | 76 * Called when an abort request was denied. |
86 */ | 77 */ |
87 void onPaymentRequestServiceUnableToAbort(); | 78 void onPaymentRequestServiceUnableToAbort(); |
88 | 79 |
89 /** | 80 /** |
90 * Called when the controller is notified of billing address change, but
does not alter the | 81 * Called when the controller is notified of billing address change, but
does not alter the |
91 * editor UI. | 82 * editor UI. |
92 */ | 83 */ |
93 void onPaymentRequestServiceBillingAddressChangeProcessed(); | 84 void onPaymentRequestServiceBillingAddressChangeProcessed(); |
94 | 85 |
95 /** | 86 /** |
96 * Called when the controller is notified of an expiration month change. | 87 * Called when the controller is notified of an expiration month change. |
97 */ | 88 */ |
98 void onPaymentRequestServiceExpirationMonthChange(); | 89 void onPaymentRequestServiceExpirationMonthChange(); |
99 | 90 |
100 /** | 91 /** |
101 * Called when a show request failed. This can happen when: | 92 * Called when a show request failed. This can happen when: |
102 * <ul> | 93 * <ul> |
103 * <li>The merchant requests only unsupported payment methods.</li> | 94 * <li>The merchant requests only unsupported payment methods.</li> |
104 * <li>The merchant requests only payment methods that don't have inst
ruments and are not | 95 * <li>The merchant requests only payment methods that don't have inst
ruments and are not |
105 * able to add instruments from PaymentRequest UI.</li> | 96 * able to add instruments from PaymentRequest UI.</li> |
106 * </ul> | 97 * </ul> |
107 */ | 98 */ |
108 void onPaymentRequestServiceShowFailed(); | 99 void onPaymentRequestServiceShowFailed(); |
| 100 |
| 101 /** |
| 102 * Called when the canMakeActivePayment() request has been responded. |
| 103 */ |
| 104 void onPaymentRequestServiceActivePaymentQueryResponded(); |
109 } | 105 } |
110 | 106 |
111 private static final String TAG = "cr_PaymentRequest"; | 107 private static final String TAG = "cr_PaymentRequest"; |
112 private static final String ANDROID_PAY_METHOD_NAME = "https://android.com/p
ay"; | 108 private static final String ANDROID_PAY_METHOD_NAME = "https://android.com/p
ay"; |
113 private static final int SUGGESTIONS_LIMIT = 4; | 109 private static final int SUGGESTIONS_LIMIT = 4; |
114 private static final Comparator<Completable> COMPLETENESS_COMPARATOR = | 110 private static final Comparator<Completable> COMPLETENESS_COMPARATOR = |
115 new Comparator<Completable>() { | 111 new Comparator<Completable>() { |
116 @Override | 112 @Override |
117 public int compare(Completable a, Completable b) { | 113 public int compare(Completable a, Completable b) { |
118 return (b.isComplete() ? 1 : 0) - (a.isComplete() ? 1 : 0); | 114 return (b.isComplete() ? 1 : 0) - (a.isComplete() ? 1 : 0); |
119 } | 115 } |
120 }; | 116 }; |
121 | 117 |
| 118 /** Every origin can call canMakeActivePayment() every 30 minutes. */ |
| 119 private static final int CAN_MAKE_ACTIVE_PAYMENT_QUERY_PERIOD_MS = 30 * 60 *
1000; |
| 120 |
122 private static PaymentRequestServiceObserverForTest sObserverForTest; | 121 private static PaymentRequestServiceObserverForTest sObserverForTest; |
123 | 122 |
| 123 /** True if show() was called in any PaymentRequestImpl object. */ |
| 124 private static boolean sIsShowing; |
| 125 |
| 126 /** |
| 127 * In-memory mapping of the origins of websites that have recently called ca
nMakeActivePayment() |
| 128 * to the list of the payment methods that were been queried. Used for throt
tling the usage of |
| 129 * this call. The user can clear the list by restarting the browser. |
| 130 */ |
| 131 private static Map<String, Set<String>> sCanMakeActivePaymentQueries; |
| 132 |
124 /** Monitors changes in the TabModelSelector. */ | 133 /** Monitors changes in the TabModelSelector. */ |
125 private final TabModelSelectorObserver mSelectorObserver = new EmptyTabModel
SelectorObserver() { | 134 private final TabModelSelectorObserver mSelectorObserver = new EmptyTabModel
SelectorObserver() { |
126 @Override | 135 @Override |
127 public void onTabModelSelected(TabModel newModel, TabModel oldModel) { | 136 public void onTabModelSelected(TabModel newModel, TabModel oldModel) { |
128 onDismiss(); | 137 onDismiss(); |
129 } | 138 } |
130 }; | 139 }; |
131 | 140 |
132 /** Monitors changes in the current TabModel. */ | 141 /** Monitors changes in the current TabModel. */ |
133 private final TabModelObserver mTabModelObserver = new EmptyTabModelObserver
() { | 142 private final TabModelObserver mTabModelObserver = new EmptyTabModelObserver
() { |
134 @Override | 143 @Override |
135 public void didSelectTab(Tab tab, TabSelectionType type, int lastId) { | 144 public void didSelectTab(Tab tab, TabSelectionType type, int lastId) { |
136 if (tab == null || tab.getId() != lastId) onDismiss(); | 145 if (tab == null || tab.getId() != lastId) onDismiss(); |
137 } | 146 } |
138 }; | 147 }; |
139 | 148 |
140 private final Handler mHandler = new Handler(); | 149 private final Handler mHandler = new Handler(); |
141 private final ChromeActivity mContext; | 150 private final ChromeActivity mContext; |
142 private final PaymentRequestDismissObserver mDismissObserver; | |
143 private final String mMerchantName; | 151 private final String mMerchantName; |
144 private final String mOrigin; | 152 private final String mOrigin; |
145 private final List<PaymentApp> mApps; | 153 private final List<PaymentApp> mApps; |
146 private final AddressEditor mAddressEditor; | 154 private final AddressEditor mAddressEditor; |
147 private final CardEditor mCardEditor; | 155 private final CardEditor mCardEditor; |
148 private final PaymentRequestJourneyLogger mJourneyLogger = new PaymentReques
tJourneyLogger(); | 156 private final PaymentRequestJourneyLogger mJourneyLogger = new PaymentReques
tJourneyLogger(); |
149 | 157 |
150 private Bitmap mFavicon; | 158 private Bitmap mFavicon; |
151 private PaymentRequestClient mClient; | 159 private PaymentRequestClient mClient; |
152 | 160 |
(...skipping 27 matching lines...) Expand all Loading... |
180 private List<PaymentApp> mPendingApps; | 188 private List<PaymentApp> mPendingApps; |
181 private List<PaymentInstrument> mPendingInstruments; | 189 private List<PaymentInstrument> mPendingInstruments; |
182 private List<PaymentInstrument> mPendingAutofillInstruments; | 190 private List<PaymentInstrument> mPendingAutofillInstruments; |
183 private SectionInformation mPaymentMethodsSection; | 191 private SectionInformation mPaymentMethodsSection; |
184 private PaymentRequestUI mUI; | 192 private PaymentRequestUI mUI; |
185 private Callback<PaymentInformation> mPaymentInformationCallback; | 193 private Callback<PaymentInformation> mPaymentInformationCallback; |
186 private boolean mPaymentAppRunning; | 194 private boolean mPaymentAppRunning; |
187 private boolean mMerchantSupportsAutofillPaymentInstruments; | 195 private boolean mMerchantSupportsAutofillPaymentInstruments; |
188 private ContactEditor mContactEditor; | 196 private ContactEditor mContactEditor; |
189 private boolean mHasRecordedAbortReason; | 197 private boolean mHasRecordedAbortReason; |
| 198 private boolean mQueriedCanMakeActivePayment; |
190 | 199 |
191 /** True if any of the requested payment methods are supported. */ | 200 /** True if any of the requested payment methods are supported. */ |
192 private boolean mArePaymentMethodsSupported; | 201 private boolean mArePaymentMethodsSupported; |
193 | 202 |
194 /** True if show() was called. */ | |
195 private boolean mIsShowing; | |
196 | |
197 /** The helper to create and fill the response to send to the merchant. */ | 203 /** The helper to create and fill the response to send to the merchant. */ |
198 private PaymentResponseHelper mPaymentResponseHelper; | 204 private PaymentResponseHelper mPaymentResponseHelper; |
199 | 205 |
200 /** | 206 /** |
201 * Builds the PaymentRequest service implementation. | 207 * Builds the PaymentRequest service implementation. |
202 * | 208 * |
203 * @param context The context where PaymentRequest has been invoked. | 209 * @param context The context where PaymentRequest has been invoked. |
204 * @param webContents The web contents that have invoked the PaymentRequ
est API. | 210 * @param webContents The web contents that have invoked the PaymentRequ
est API. |
205 * @param dismissObserver The observer to notify when PaymentRequest UI has
been dismissed. | |
206 */ | 211 */ |
207 public PaymentRequestImpl(Activity context, WebContents webContents, | 212 public PaymentRequestImpl(Activity context, WebContents webContents) { |
208 PaymentRequestDismissObserver dismissObserver) { | |
209 assert context != null; | 213 assert context != null; |
210 assert webContents != null; | 214 assert webContents != null; |
211 assert dismissObserver != null; | |
212 | 215 |
213 assert context instanceof ChromeActivity; | 216 assert context instanceof ChromeActivity; |
214 mContext = (ChromeActivity) context; | 217 mContext = (ChromeActivity) context; |
215 | 218 |
216 mDismissObserver = dismissObserver; | |
217 mMerchantName = webContents.getTitle(); | 219 mMerchantName = webContents.getTitle(); |
218 // The feature is available only in secure context, so it's OK to not sh
ow HTTPS. | 220 // The feature is available only in secure context, so it's OK to not sh
ow HTTPS. |
219 mOrigin = UrlFormatter.formatUrlForSecurityDisplay(webContents.getVisibl
eUrl(), false); | 221 mOrigin = UrlFormatter.formatUrlForSecurityDisplay( |
| 222 webContents.getLastCommittedUrl(), false); |
220 | 223 |
221 final FaviconHelper faviconHelper = new FaviconHelper(); | 224 final FaviconHelper faviconHelper = new FaviconHelper(); |
222 faviconHelper.getLocalFaviconImageForURL(Profile.getLastUsedProfile(), | 225 faviconHelper.getLocalFaviconImageForURL(Profile.getLastUsedProfile(), |
223 webContents.getVisibleUrl(), | 226 webContents.getVisibleUrl(), |
224 mContext.getResources().getDimensionPixelSize(R.dimen.payments_f
avicon_size), | 227 mContext.getResources().getDimensionPixelSize(R.dimen.payments_f
avicon_size), |
225 new FaviconHelper.FaviconImageCallback() { | 228 new FaviconHelper.FaviconImageCallback() { |
226 @Override | 229 @Override |
227 public void onFaviconAvailable(Bitmap bitmap, String iconUrl
) { | 230 public void onFaviconAvailable(Bitmap bitmap, String iconUrl
) { |
228 faviconHelper.destroy(); | 231 faviconHelper.destroy(); |
229 if (bitmap == null) return; | 232 if (bitmap == null) return; |
(...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
395 | 398 |
396 PaymentRequestMetrics.recordRequestedInformationHistogram(requestPayerEm
ail, | 399 PaymentRequestMetrics.recordRequestedInformationHistogram(requestPayerEm
ail, |
397 requestPayerPhone, requestShipping, requestPayerName); | 400 requestPayerPhone, requestShipping, requestPayerName); |
398 } | 401 } |
399 | 402 |
400 /** | 403 /** |
401 * Called by the merchant website to show the payment request to the user. | 404 * Called by the merchant website to show the payment request to the user. |
402 */ | 405 */ |
403 @Override | 406 @Override |
404 public void show() { | 407 public void show() { |
405 if (mClient == null || mIsShowing) return; | 408 if (mClient == null) return; |
406 | 409 |
407 mIsShowing = true; | 410 if (getIsShowing()) { |
| 411 disconnectFromClientWithDebugMessage("A PaymentRequest UI is already
showing"); |
| 412 recordAbortReasonHistogram( |
| 413 PaymentRequestMetrics.ABORT_REASON_INVALID_DATA_FROM_RENDERE
R); |
| 414 return; |
| 415 } |
| 416 |
| 417 setIsShowing(true); |
408 if (disconnectIfNoPaymentMethodsSupported()) return; | 418 if (disconnectIfNoPaymentMethodsSupported()) return; |
409 | 419 |
410 // Catch any time the user switches tabs. Because the dialog is modal,
a user shouldn't be | 420 // Catch any time the user switches tabs. Because the dialog is modal,
a user shouldn't be |
411 // allowed to switch tabs, which can happen if the user receives an exte
rnal Intent. | 421 // allowed to switch tabs, which can happen if the user receives an exte
rnal Intent. |
412 mContext.getTabModelSelector().addObserver(mSelectorObserver); | 422 mContext.getTabModelSelector().addObserver(mSelectorObserver); |
413 mContext.getCurrentTabModel().addObserver(mTabModelObserver); | 423 mContext.getCurrentTabModel().addObserver(mTabModelObserver); |
414 | 424 |
415 mUI.show(); | 425 mUI.show(); |
416 recordSuccessFunnelHistograms("Shown"); | 426 recordSuccessFunnelHistograms("Shown"); |
417 } | 427 } |
418 | 428 |
419 private static Map<String, PaymentMethodData> getValidatedMethodData( | 429 private static Map<String, PaymentMethodData> getValidatedMethodData( |
420 PaymentMethodData[] methodData, CardEditor paymentMethodsCollector)
{ | 430 PaymentMethodData[] methodData, CardEditor paymentMethodsCollector)
{ |
421 // Payment methodData are required. | 431 // Payment methodData are required. |
422 if (methodData == null || methodData.length == 0) return null; | 432 if (methodData == null || methodData.length == 0) return null; |
423 Map<String, PaymentMethodData> result = new HashMap<>(); | 433 Map<String, PaymentMethodData> result = new ArrayMap<>(); |
424 for (int i = 0; i < methodData.length; i++) { | 434 for (int i = 0; i < methodData.length; i++) { |
425 String[] methods = methodData[i].supportedMethods; | 435 String[] methods = methodData[i].supportedMethods; |
426 | 436 |
427 // Payment methods are required. | 437 // Payment methods are required. |
428 if (methods == null || methods.length == 0) return null; | 438 if (methods == null || methods.length == 0) return null; |
429 | 439 |
430 for (int j = 0; j < methods.length; j++) { | 440 for (int j = 0; j < methods.length; j++) { |
431 // Payment methods should be non-empty. | 441 // Payment methods should be non-empty. |
432 if (TextUtils.isEmpty(methods[j])) return null; | 442 if (TextUtils.isEmpty(methods[j])) return null; |
433 result.put(methods[j], methodData[i]); | 443 result.put(methods[j], methodData[i]); |
434 } | 444 } |
435 | 445 |
436 paymentMethodsCollector.addAcceptedPaymentMethodsIfRecognized(method
s); | 446 paymentMethodsCollector.addAcceptedPaymentMethodsIfRecognized(method
s); |
437 } | 447 } |
438 return result; | 448 return result; |
439 } | 449 } |
440 | 450 |
441 /** Queries the installed payment apps for their instruments that merchant s
upports. */ | 451 /** Queries the installed payment apps for their instruments that merchant s
upports. */ |
442 private void getMatchingPaymentInstruments() { | 452 private void getMatchingPaymentInstruments() { |
443 mPendingApps = new ArrayList<>(mApps); | 453 mPendingApps = new ArrayList<>(mApps); |
444 mPendingInstruments = new ArrayList<>(); | 454 mPendingInstruments = new ArrayList<>(); |
445 mPendingAutofillInstruments = new ArrayList<>(); | 455 mPendingAutofillInstruments = new ArrayList<>(); |
446 | 456 |
447 Map<PaymentApp, Map<String, PaymentMethodData>> queryApps = new HashMap<
>(); | 457 Map<PaymentApp, Map<String, PaymentMethodData>> queryApps = new ArrayMap
<>(); |
448 for (int i = 0; i < mApps.size(); i++) { | 458 for (int i = 0; i < mApps.size(); i++) { |
449 PaymentApp app = mApps.get(i); | 459 PaymentApp app = mApps.get(i); |
450 Map<String, PaymentMethodData> appMethods = | 460 Map<String, PaymentMethodData> appMethods = |
451 filterMerchantMethodData(mMethodData, app.getAppMethodNames(
)); | 461 filterMerchantMethodData(mMethodData, app.getAppMethodNames(
)); |
452 if (appMethods == null) { | 462 if (appMethods == null) { |
453 mPendingApps.remove(app); | 463 mPendingApps.remove(app); |
454 } else { | 464 } else { |
455 mArePaymentMethodsSupported = true; | 465 mArePaymentMethodsSupported = true; |
456 mMerchantSupportsAutofillPaymentInstruments |= app instanceof Au
tofillPaymentApp; | 466 mMerchantSupportsAutofillPaymentInstruments |= app instanceof Au
tofillPaymentApp; |
457 queryApps.put(app, appMethods); | 467 queryApps.put(app, appMethods); |
458 } | 468 } |
459 } | 469 } |
460 | 470 |
461 // Query instruments after mMerchantSupportsAutofillPaymentInstruments h
as been initialized, | 471 // Query instruments after mMerchantSupportsAutofillPaymentInstruments h
as been initialized, |
462 // so a fast response from a non-autofill payment app at the front of th
e app list does not | 472 // so a fast response from a non-autofill payment app at the front of th
e app list does not |
463 // cause NOT_SUPPORTED payment rejection. | 473 // cause NOT_SUPPORTED payment rejection. |
464 for (Map.Entry<PaymentApp, Map<String, PaymentMethodData>> q : queryApps
.entrySet()) { | 474 for (Map.Entry<PaymentApp, Map<String, PaymentMethodData>> q : queryApps
.entrySet()) { |
465 q.getKey().getInstruments(q.getValue(), this); | 475 q.getKey().getInstruments(q.getValue(), this); |
466 } | 476 } |
467 } | 477 } |
468 | 478 |
469 /** Filter out merchant method data that's not relevant to a payment app. Ca
n return null. */ | 479 /** Filter out merchant method data that's not relevant to a payment app. Ca
n return null. */ |
470 private static Map<String, PaymentMethodData> filterMerchantMethodData( | 480 private static Map<String, PaymentMethodData> filterMerchantMethodData( |
471 Map<String, PaymentMethodData> merchantMethodData, Set<String> appMe
thods) { | 481 Map<String, PaymentMethodData> merchantMethodData, Set<String> appMe
thods) { |
472 Map<String, PaymentMethodData> result = null; | 482 Map<String, PaymentMethodData> result = null; |
473 for (String method : appMethods) { | 483 for (String method : appMethods) { |
474 if (merchantMethodData.containsKey(method)) { | 484 if (merchantMethodData.containsKey(method)) { |
475 if (result == null) result = new HashMap<>(); | 485 if (result == null) result = new ArrayMap<>(); |
476 result.put(method, merchantMethodData.get(method)); | 486 result.put(method, merchantMethodData.get(method)); |
477 } | 487 } |
478 } | 488 } |
479 return result; | 489 return result; |
480 } | 490 } |
481 | 491 |
482 /** | 492 /** |
483 * Called by merchant to update the shipping options and line items after th
e user has selected | 493 * Called by merchant to update the shipping options and line items after th
e user has selected |
484 * their shipping address or shipping option. | 494 * their shipping address or shipping option. |
485 */ | 495 */ |
(...skipping 422 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
908 * Called when the merchant website has processed the payment. | 918 * Called when the merchant website has processed the payment. |
909 */ | 919 */ |
910 @Override | 920 @Override |
911 public void complete(int result) { | 921 public void complete(int result) { |
912 if (mClient == null) return; | 922 if (mClient == null) return; |
913 recordSuccessFunnelHistograms("Completed"); | 923 recordSuccessFunnelHistograms("Completed"); |
914 closeUI(PaymentComplete.FAIL != result); | 924 closeUI(PaymentComplete.FAIL != result); |
915 } | 925 } |
916 | 926 |
917 /** | 927 /** |
| 928 * Called by the merchant website to check if the user has complete payment
instruments. |
| 929 */ |
| 930 @Override |
| 931 public void canMakeActivePayment() { |
| 932 if (mClient == null) return; |
| 933 |
| 934 if (sCanMakeActivePaymentQueries == null) sCanMakeActivePaymentQueries =
new ArrayMap<>(); |
| 935 |
| 936 if (sCanMakeActivePaymentQueries.containsKey(mOrigin)) { |
| 937 if (!mMethodData.keySet().equals(sCanMakeActivePaymentQueries.get(mO
rigin))) { |
| 938 mClient.onCanMakeActivePayment(ActivePaymentQueryResult.QUERY_QU
OTA_EXCEEDED); |
| 939 if (sObserverForTest != null) { |
| 940 sObserverForTest.onPaymentRequestServiceActivePaymentQueryRe
sponded(); |
| 941 } |
| 942 return; |
| 943 } |
| 944 } else { |
| 945 sCanMakeActivePaymentQueries.put(mOrigin, mMethodData.keySet()); |
| 946 mHandler.postDelayed(new Runnable() { |
| 947 @Override |
| 948 public void run() { |
| 949 sCanMakeActivePaymentQueries.remove(mOrigin); |
| 950 } |
| 951 }, CAN_MAKE_ACTIVE_PAYMENT_QUERY_PERIOD_MS); |
| 952 } |
| 953 |
| 954 if (!mPendingApps.isEmpty() || !mPendingInstruments.isEmpty()) { |
| 955 mQueriedCanMakeActivePayment = true; |
| 956 } else { |
| 957 mClient.onCanMakeActivePayment(mPaymentMethodsSection == null |
| 958 || mPaymentMethodsSection.getSelectedItem() == null |
| 959 ? ActivePaymentQueryResult.CANNOT_MAKE_ACTIVE_PAYMEN
T |
| 960 : ActivePaymentQueryResult.CAN_MAKE_ACTIVE_PAYMENT); |
| 961 if (sObserverForTest != null) { |
| 962 sObserverForTest.onPaymentRequestServiceActivePaymentQueryRespon
ded(); |
| 963 } |
| 964 } |
| 965 } |
| 966 |
| 967 /** |
918 * Called when the renderer closes the Mojo connection. | 968 * Called when the renderer closes the Mojo connection. |
919 */ | 969 */ |
920 @Override | 970 @Override |
921 public void close() { | 971 public void close() { |
922 if (mClient == null) return; | 972 if (mClient == null) return; |
923 closeClient(); | 973 closeClient(); |
924 closeUI(true); | 974 closeUI(true); |
925 recordAbortReasonHistogram(PaymentRequestMetrics.ABORT_REASON_MOJO_RENDE
RER_CLOSING); | 975 recordAbortReasonHistogram(PaymentRequestMetrics.ABORT_REASON_MOJO_RENDE
RER_CLOSING); |
926 } | 976 } |
927 | 977 |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
994 // Pre-select the first instrument on the list, if it is complete. | 1044 // Pre-select the first instrument on the list, if it is complete. |
995 int selection = SectionInformation.NO_SELECTION; | 1045 int selection = SectionInformation.NO_SELECTION; |
996 if (!mPendingInstruments.isEmpty()) { | 1046 if (!mPendingInstruments.isEmpty()) { |
997 PaymentInstrument first = mPendingInstruments.get(0); | 1047 PaymentInstrument first = mPendingInstruments.get(0); |
998 if (!(first instanceof AutofillPaymentInstrument) | 1048 if (!(first instanceof AutofillPaymentInstrument) |
999 || ((AutofillPaymentInstrument) first).isComplete()) { | 1049 || ((AutofillPaymentInstrument) first).isComplete()) { |
1000 selection = 0; | 1050 selection = 0; |
1001 } | 1051 } |
1002 } | 1052 } |
1003 | 1053 |
| 1054 if (mQueriedCanMakeActivePayment) { |
| 1055 mQueriedCanMakeActivePayment = false; |
| 1056 mClient.onCanMakeActivePayment(selection == 0 |
| 1057 ? ActivePaymentQueryResult.CAN_MAKE_ACTIVE_PAYMENT |
| 1058 : ActivePaymentQueryResult.CANNOT_MAKE_ACTIVE_PAYMEN
T); |
| 1059 if (sObserverForTest != null) { |
| 1060 sObserverForTest.onPaymentRequestServiceActivePaymentQueryRespon
ded(); |
| 1061 } |
| 1062 } |
| 1063 |
1004 // The list of payment instruments is ready to display. | 1064 // The list of payment instruments is ready to display. |
1005 mPaymentMethodsSection = new SectionInformation(PaymentRequestUI.TYPE_PA
YMENT_METHODS, | 1065 mPaymentMethodsSection = new SectionInformation(PaymentRequestUI.TYPE_PA
YMENT_METHODS, |
1006 selection, mPendingInstruments); | 1066 selection, mPendingInstruments); |
1007 | 1067 |
1008 mPendingInstruments.clear(); | 1068 mPendingInstruments.clear(); |
1009 | 1069 |
1010 // UI has requested the full list of payment instruments. Provide it now
. | 1070 // UI has requested the full list of payment instruments. Provide it now
. |
1011 if (mPaymentInformationCallback != null) providePaymentInformation(); | 1071 if (mPaymentInformationCallback != null) providePaymentInformation(); |
1012 } | 1072 } |
1013 | 1073 |
1014 /** | 1074 /** |
1015 * If no payment methods are supported, disconnect from the client and retur
n true. | 1075 * If no payment methods are supported, disconnect from the client and retur
n true. |
1016 * | 1076 * |
1017 * @return True if no payment methods are supported | 1077 * @return True if no payment methods are supported |
1018 */ | 1078 */ |
1019 private boolean disconnectIfNoPaymentMethodsSupported() { | 1079 private boolean disconnectIfNoPaymentMethodsSupported() { |
1020 boolean waitingForPaymentApps = !mPendingApps.isEmpty() || !mPendingInst
ruments.isEmpty(); | 1080 boolean waitingForPaymentApps = !mPendingApps.isEmpty() || !mPendingInst
ruments.isEmpty(); |
1021 boolean foundPaymentMethods = | 1081 boolean foundPaymentMethods = |
1022 mPaymentMethodsSection != null && !mPaymentMethodsSection.isEmpt
y(); | 1082 mPaymentMethodsSection != null && !mPaymentMethodsSection.isEmpt
y(); |
1023 boolean userCanAddCreditCard = mMerchantSupportsAutofillPaymentInstrumen
ts | 1083 boolean userCanAddCreditCard = mMerchantSupportsAutofillPaymentInstrumen
ts |
1024 && !ChromeFeatureList.isEnabled(ChromeFeatureList.NO_CREDIT_CARD
_ABORT); | 1084 && !ChromeFeatureList.isEnabled(ChromeFeatureList.NO_CREDIT_CARD
_ABORT); |
1025 | 1085 |
1026 if (!mArePaymentMethodsSupported | 1086 if (!mArePaymentMethodsSupported |
1027 || (mIsShowing && !waitingForPaymentApps && !foundPaymentMethods | 1087 || (getIsShowing() && !waitingForPaymentApps && !foundPaymentMet
hods |
1028 && !userCanAddCreditCard)) { | 1088 && !userCanAddCreditCard)) { |
1029 // All payment apps have responded, but none of them have instrument
s. It's possible to | 1089 // All payment apps have responded, but none of them have instrument
s. It's possible to |
1030 // add credit cards, but the merchant does not support them either.
The payment request | 1090 // add credit cards, but the merchant does not support them either.
The payment request |
1031 // must be rejected. | 1091 // must be rejected. |
1032 disconnectFromClientWithDebugMessage("Requested payment methods have
no instruments", | 1092 disconnectFromClientWithDebugMessage("Requested payment methods have
no instruments", |
1033 PaymentErrorReason.NOT_SUPPORTED); | 1093 PaymentErrorReason.NOT_SUPPORTED); |
1034 recordAbortReasonHistogram(mArePaymentMethodsSupported | 1094 recordAbortReasonHistogram(mArePaymentMethodsSupported |
1035 ? PaymentRequestMetrics.ABORT_REASON_NO_MATCHING_PAY
MENT_METHOD | 1095 ? PaymentRequestMetrics.ABORT_REASON_NO_MATCHING_PAY
MENT_METHOD |
1036 : PaymentRequestMetrics.ABORT_REASON_NO_SUPPORTED_PA
YMENT_METHOD); | 1096 : PaymentRequestMetrics.ABORT_REASON_NO_SUPPORTED_PA
YMENT_METHOD); |
1037 if (sObserverForTest != null) sObserverForTest.onPaymentRequestServi
ceShowFailed(); | 1097 if (sObserverForTest != null) sObserverForTest.onPaymentRequestServi
ceShowFailed(); |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1134 mPaymentMethodsSection = null; | 1194 mPaymentMethodsSection = null; |
1135 } | 1195 } |
1136 | 1196 |
1137 mContext.getTabModelSelector().removeObserver(mSelectorObserver); | 1197 mContext.getTabModelSelector().removeObserver(mSelectorObserver); |
1138 mContext.getCurrentTabModel().removeObserver(mTabModelObserver); | 1198 mContext.getCurrentTabModel().removeObserver(mTabModelObserver); |
1139 } | 1199 } |
1140 | 1200 |
1141 private void closeClient() { | 1201 private void closeClient() { |
1142 if (mClient != null) mClient.close(); | 1202 if (mClient != null) mClient.close(); |
1143 mClient = null; | 1203 mClient = null; |
1144 mDismissObserver.onPaymentRequestDismissed(); | 1204 setIsShowing(false); |
| 1205 } |
| 1206 |
| 1207 private static boolean getIsShowing() { |
| 1208 return sIsShowing; |
| 1209 } |
| 1210 |
| 1211 private static void setIsShowing(boolean isShowing) { |
| 1212 sIsShowing = isShowing; |
1145 } | 1213 } |
1146 | 1214 |
1147 @VisibleForTesting | 1215 @VisibleForTesting |
1148 public static void setObserverForTest(PaymentRequestServiceObserverForTest o
bserverForTest) { | 1216 public static void setObserverForTest(PaymentRequestServiceObserverForTest o
bserverForTest) { |
1149 sObserverForTest = observerForTest; | 1217 sObserverForTest = observerForTest; |
1150 } | 1218 } |
1151 | 1219 |
1152 /** | 1220 /** |
1153 * Records specific histograms related to the different steps of a successfu
l checkout. | 1221 * Records specific histograms related to the different steps of a successfu
l checkout. |
1154 */ | 1222 */ |
(...skipping 19 matching lines...) Expand all Loading... |
1174 "PaymentRequest.CheckoutFunnel.Aborted", abortReason, | 1242 "PaymentRequest.CheckoutFunnel.Aborted", abortReason, |
1175 PaymentRequestMetrics.ABORT_REASON_MAX); | 1243 PaymentRequestMetrics.ABORT_REASON_MAX); |
1176 | 1244 |
1177 if (abortReason == PaymentRequestMetrics.ABORT_REASON_ABORTED_BY_USER) { | 1245 if (abortReason == PaymentRequestMetrics.ABORT_REASON_ABORTED_BY_USER) { |
1178 mJourneyLogger.recordJourneyStatsHistograms("UserAborted"); | 1246 mJourneyLogger.recordJourneyStatsHistograms("UserAborted"); |
1179 } else { | 1247 } else { |
1180 mJourneyLogger.recordJourneyStatsHistograms("OtherAborted"); | 1248 mJourneyLogger.recordJourneyStatsHistograms("OtherAborted"); |
1181 } | 1249 } |
1182 } | 1250 } |
1183 } | 1251 } |
OLD | NEW |