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.json.JSONException; | 13 import org.json.JSONException; |
13 import org.json.JSONObject; | 14 import org.json.JSONObject; |
14 | 15 |
15 import org.chromium.base.Callback; | 16 import org.chromium.base.Callback; |
16 import org.chromium.base.Log; | 17 import org.chromium.base.Log; |
17 import org.chromium.base.VisibleForTesting; | 18 import org.chromium.base.VisibleForTesting; |
18 import org.chromium.base.metrics.RecordHistogram; | 19 import org.chromium.base.metrics.RecordHistogram; |
19 import org.chromium.chrome.R; | 20 import org.chromium.chrome.R; |
(...skipping 14 matching lines...) Expand all Loading... | |
34 import org.chromium.chrome.browser.tabmodel.EmptyTabModelObserver; | 35 import org.chromium.chrome.browser.tabmodel.EmptyTabModelObserver; |
35 import org.chromium.chrome.browser.tabmodel.EmptyTabModelSelectorObserver; | 36 import org.chromium.chrome.browser.tabmodel.EmptyTabModelSelectorObserver; |
36 import org.chromium.chrome.browser.tabmodel.TabModel; | 37 import org.chromium.chrome.browser.tabmodel.TabModel; |
37 import org.chromium.chrome.browser.tabmodel.TabModel.TabSelectionType; | 38 import org.chromium.chrome.browser.tabmodel.TabModel.TabSelectionType; |
38 import org.chromium.chrome.browser.tabmodel.TabModelObserver; | 39 import org.chromium.chrome.browser.tabmodel.TabModelObserver; |
39 import org.chromium.chrome.browser.tabmodel.TabModelSelectorObserver; | 40 import org.chromium.chrome.browser.tabmodel.TabModelSelectorObserver; |
40 import org.chromium.components.safejson.JsonSanitizer; | 41 import org.chromium.components.safejson.JsonSanitizer; |
41 import org.chromium.components.url_formatter.UrlFormatter; | 42 import org.chromium.components.url_formatter.UrlFormatter; |
42 import org.chromium.content_public.browser.WebContents; | 43 import org.chromium.content_public.browser.WebContents; |
43 import org.chromium.mojo.system.MojoException; | 44 import org.chromium.mojo.system.MojoException; |
45 import org.chromium.payments.mojom.ActivePaymentQueryResult; | |
44 import org.chromium.payments.mojom.PaymentComplete; | 46 import org.chromium.payments.mojom.PaymentComplete; |
45 import org.chromium.payments.mojom.PaymentDetails; | 47 import org.chromium.payments.mojom.PaymentDetails; |
46 import org.chromium.payments.mojom.PaymentErrorReason; | 48 import org.chromium.payments.mojom.PaymentErrorReason; |
47 import org.chromium.payments.mojom.PaymentItem; | 49 import org.chromium.payments.mojom.PaymentItem; |
48 import org.chromium.payments.mojom.PaymentMethodData; | 50 import org.chromium.payments.mojom.PaymentMethodData; |
49 import org.chromium.payments.mojom.PaymentOptions; | 51 import org.chromium.payments.mojom.PaymentOptions; |
50 import org.chromium.payments.mojom.PaymentRequest; | 52 import org.chromium.payments.mojom.PaymentRequest; |
51 import org.chromium.payments.mojom.PaymentRequestClient; | 53 import org.chromium.payments.mojom.PaymentRequestClient; |
52 import org.chromium.payments.mojom.PaymentResponse; | 54 import org.chromium.payments.mojom.PaymentResponse; |
53 import org.chromium.payments.mojom.PaymentShippingOption; | 55 import org.chromium.payments.mojom.PaymentShippingOption; |
54 import org.chromium.payments.mojom.PaymentShippingType; | 56 import org.chromium.payments.mojom.PaymentShippingType; |
55 | 57 |
56 import java.io.IOException; | 58 import java.io.IOException; |
57 import java.util.ArrayList; | 59 import java.util.ArrayList; |
58 import java.util.Arrays; | 60 import java.util.Arrays; |
59 import java.util.Collections; | 61 import java.util.Collections; |
60 import java.util.Comparator; | 62 import java.util.Comparator; |
61 import java.util.HashMap; | |
62 import java.util.HashSet; | 63 import java.util.HashSet; |
63 import java.util.List; | 64 import java.util.List; |
64 import java.util.Locale; | 65 import java.util.Locale; |
65 import java.util.Map; | 66 import java.util.Map; |
66 import java.util.Set; | 67 import java.util.Set; |
67 | 68 |
68 /** | 69 /** |
69 * Android implementation of the PaymentRequest service defined in | 70 * Android implementation of the PaymentRequest service defined in |
70 * components/payments/payment_request.mojom. | 71 * components/payments/payment_request.mojom. |
71 */ | 72 */ |
72 public class PaymentRequestImpl implements PaymentRequest, PaymentRequestUI.Clie nt, | 73 public class PaymentRequestImpl implements PaymentRequest, PaymentRequestUI.Clie nt, |
73 PaymentApp.InstrumentsCallback, PaymentInstrument.InstrumentDetailsCallb ack, | 74 PaymentApp.InstrumentsCallback, PaymentInstrument.InstrumentDetailsCallb ack, |
74 PaymentResponseHelper.PaymentResponseRequesterDelegate { | 75 PaymentResponseHelper.PaymentResponseRequesterDelegate { |
75 /** | 76 /** |
76 * Observer to be notified when PaymentRequest UI has been dismissed. | |
77 */ | |
78 public interface PaymentRequestDismissObserver { | |
79 /** | |
80 * Called when PaymentRequest UI has been dismissed. | |
81 */ | |
82 void onPaymentRequestDismissed(); | |
83 } | |
84 | |
85 /** | |
86 * A test-only observer for the PaymentRequest service implementation. | 77 * A test-only observer for the PaymentRequest service implementation. |
87 */ | 78 */ |
88 public interface PaymentRequestServiceObserverForTest { | 79 public interface PaymentRequestServiceObserverForTest { |
89 /** | 80 /** |
90 * Called when an abort request was denied. | 81 * Called when an abort request was denied. |
91 */ | 82 */ |
92 void onPaymentRequestServiceUnableToAbort(); | 83 void onPaymentRequestServiceUnableToAbort(); |
93 | 84 |
94 /** | 85 /** |
95 * Called when the controller is notified of billing address change, but does not alter the | 86 * Called when the controller is notified of billing address change, but does not alter the |
96 * editor UI. | 87 * editor UI. |
97 */ | 88 */ |
98 void onPaymentRequestServiceBillingAddressChangeProcessed(); | 89 void onPaymentRequestServiceBillingAddressChangeProcessed(); |
99 | 90 |
100 /** | 91 /** |
101 * Called when the controller is notified of an expiration month change. | 92 * Called when the controller is notified of an expiration month change. |
102 */ | 93 */ |
103 void onPaymentRequestServiceExpirationMonthChange(); | 94 void onPaymentRequestServiceExpirationMonthChange(); |
104 | 95 |
105 /** | 96 /** |
106 * Called when a show request failed. This can happen when: | 97 * Called when a show request failed. This can happen when: |
107 * <ul> | 98 * <ul> |
108 * <li>The merchant requests only unsupported payment methods.</li> | 99 * <li>The merchant requests only unsupported payment methods.</li> |
109 * <li>The merchant requests only payment methods that don't have inst ruments and are not | 100 * <li>The merchant requests only payment methods that don't have inst ruments and are not |
110 * able to add instruments from PaymentRequest UI.</li> | 101 * able to add instruments from PaymentRequest UI.</li> |
111 * </ul> | 102 * </ul> |
112 */ | 103 */ |
113 void onPaymentRequestServiceShowFailed(); | 104 void onPaymentRequestServiceShowFailed(); |
105 | |
106 /** | |
107 * Called when the canMakeActivePayment() request has been responded. | |
108 */ | |
109 void onPaymentRequestServiceActivePaymentQueryResponded(); | |
114 } | 110 } |
115 | 111 |
116 private static final String TAG = "cr_PaymentRequest"; | 112 private static final String TAG = "cr_PaymentRequest"; |
117 private static final String ANDROID_PAY_METHOD_NAME = "https://android.com/p ay"; | 113 private static final String ANDROID_PAY_METHOD_NAME = "https://android.com/p ay"; |
118 private static final int SUGGESTIONS_LIMIT = 4; | 114 private static final int SUGGESTIONS_LIMIT = 4; |
119 private static final Comparator<Completable> COMPLETENESS_COMPARATOR = | 115 private static final Comparator<Completable> COMPLETENESS_COMPARATOR = |
120 new Comparator<Completable>() { | 116 new Comparator<Completable>() { |
121 @Override | 117 @Override |
122 public int compare(Completable a, Completable b) { | 118 public int compare(Completable a, Completable b) { |
123 return (b.isComplete() ? 1 : 0) - (a.isComplete() ? 1 : 0); | 119 return (b.isComplete() ? 1 : 0) - (a.isComplete() ? 1 : 0); |
124 } | 120 } |
125 }; | 121 }; |
126 | 122 |
123 /** Every origin can call canMakeActivePayment() every 30 minutes. */ | |
124 private static final int CAN_MAKE_ACTIVE_PAYMENT_QUERY_PERIOD_MS = 30 * 60 * 1000; | |
125 | |
127 private static PaymentRequestServiceObserverForTest sObserverForTest; | 126 private static PaymentRequestServiceObserverForTest sObserverForTest; |
128 | 127 |
128 /** True if show() was called in any PaymentRequestImpl object. */ | |
129 private static boolean sIsShowing; | |
130 | |
131 /** | |
132 * In-memory mapping of the origins of websites that have recently called ca nMakeActivePayment() | |
133 * to the list of the payment methods that were been queried. Used for throt tling the usage of | |
134 * this call. The user can clear the list by restarting the browser. | |
135 */ | |
136 private static Map<String, Set<String>> sCanMakeActivePaymentQueries; | |
137 | |
129 /** Monitors changes in the TabModelSelector. */ | 138 /** Monitors changes in the TabModelSelector. */ |
130 private final TabModelSelectorObserver mSelectorObserver = new EmptyTabModel SelectorObserver() { | 139 private final TabModelSelectorObserver mSelectorObserver = new EmptyTabModel SelectorObserver() { |
131 @Override | 140 @Override |
132 public void onTabModelSelected(TabModel newModel, TabModel oldModel) { | 141 public void onTabModelSelected(TabModel newModel, TabModel oldModel) { |
133 onDismiss(); | 142 onDismiss(); |
134 } | 143 } |
135 }; | 144 }; |
136 | 145 |
137 /** Monitors changes in the current TabModel. */ | 146 /** Monitors changes in the current TabModel. */ |
138 private final TabModelObserver mTabModelObserver = new EmptyTabModelObserver () { | 147 private final TabModelObserver mTabModelObserver = new EmptyTabModelObserver () { |
139 @Override | 148 @Override |
140 public void didSelectTab(Tab tab, TabSelectionType type, int lastId) { | 149 public void didSelectTab(Tab tab, TabSelectionType type, int lastId) { |
141 if (tab == null || tab.getId() != lastId) onDismiss(); | 150 if (tab == null || tab.getId() != lastId) onDismiss(); |
142 } | 151 } |
143 }; | 152 }; |
144 | 153 |
145 private final Handler mHandler = new Handler(); | 154 private final Handler mHandler = new Handler(); |
146 private final ChromeActivity mContext; | 155 private final ChromeActivity mContext; |
147 private final PaymentRequestDismissObserver mDismissObserver; | |
148 private final String mMerchantName; | 156 private final String mMerchantName; |
149 private final String mOrigin; | 157 private final String mOrigin; |
150 private final List<PaymentApp> mApps; | 158 private final List<PaymentApp> mApps; |
151 private final AddressEditor mAddressEditor; | 159 private final AddressEditor mAddressEditor; |
152 private final CardEditor mCardEditor; | 160 private final CardEditor mCardEditor; |
153 private final PaymentRequestJourneyLogger mJourneyLogger = new PaymentReques tJourneyLogger(); | 161 private final PaymentRequestJourneyLogger mJourneyLogger = new PaymentReques tJourneyLogger(); |
154 | 162 |
155 private Bitmap mFavicon; | 163 private Bitmap mFavicon; |
156 private PaymentRequestClient mClient; | 164 private PaymentRequestClient mClient; |
157 | 165 |
(...skipping 27 matching lines...) Expand all Loading... | |
185 private List<PaymentApp> mPendingApps; | 193 private List<PaymentApp> mPendingApps; |
186 private List<PaymentInstrument> mPendingInstruments; | 194 private List<PaymentInstrument> mPendingInstruments; |
187 private List<PaymentInstrument> mPendingAutofillInstruments; | 195 private List<PaymentInstrument> mPendingAutofillInstruments; |
188 private SectionInformation mPaymentMethodsSection; | 196 private SectionInformation mPaymentMethodsSection; |
189 private PaymentRequestUI mUI; | 197 private PaymentRequestUI mUI; |
190 private Callback<PaymentInformation> mPaymentInformationCallback; | 198 private Callback<PaymentInformation> mPaymentInformationCallback; |
191 private boolean mPaymentAppRunning; | 199 private boolean mPaymentAppRunning; |
192 private boolean mMerchantSupportsAutofillPaymentInstruments; | 200 private boolean mMerchantSupportsAutofillPaymentInstruments; |
193 private ContactEditor mContactEditor; | 201 private ContactEditor mContactEditor; |
194 private boolean mHasRecordedAbortReason; | 202 private boolean mHasRecordedAbortReason; |
203 private boolean mQueriedCanMakeActivePayment; | |
195 | 204 |
196 /** True if any of the requested payment methods are supported. */ | 205 /** True if any of the requested payment methods are supported. */ |
197 private boolean mArePaymentMethodsSupported; | 206 private boolean mArePaymentMethodsSupported; |
198 | 207 |
199 /** True if show() was called. */ | |
200 private boolean mIsShowing; | |
201 | |
202 /** The helper to create and fill the response to send to the merchant. */ | 208 /** The helper to create and fill the response to send to the merchant. */ |
203 private PaymentResponseHelper mPaymentResponseHelper; | 209 private PaymentResponseHelper mPaymentResponseHelper; |
204 | 210 |
205 /** | 211 /** |
206 * Builds the PaymentRequest service implementation. | 212 * Builds the PaymentRequest service implementation. |
207 * | 213 * |
208 * @param context The context where PaymentRequest has been invoked. | 214 * @param context The context where PaymentRequest has been invoked. |
209 * @param webContents The web contents that have invoked the PaymentRequ est API. | 215 * @param webContents The web contents that have invoked the PaymentRequ est API. |
210 * @param dismissObserver The observer to notify when PaymentRequest UI has been dismissed. | |
211 */ | 216 */ |
212 public PaymentRequestImpl(Activity context, WebContents webContents, | 217 public PaymentRequestImpl(Activity context, WebContents webContents) { |
213 PaymentRequestDismissObserver dismissObserver) { | |
214 assert context != null; | 218 assert context != null; |
215 assert webContents != null; | 219 assert webContents != null; |
216 assert dismissObserver != null; | |
217 | 220 |
218 assert context instanceof ChromeActivity; | 221 assert context instanceof ChromeActivity; |
219 mContext = (ChromeActivity) context; | 222 mContext = (ChromeActivity) context; |
220 | 223 |
221 mDismissObserver = dismissObserver; | |
222 mMerchantName = webContents.getTitle(); | 224 mMerchantName = webContents.getTitle(); |
223 // The feature is available only in secure context, so it's OK to not sh ow HTTPS. | 225 // The feature is available only in secure context, so it's OK to not sh ow HTTPS. |
224 mOrigin = UrlFormatter.formatUrlForSecurityDisplay(webContents.getVisibl eUrl(), false); | 226 mOrigin = UrlFormatter.formatUrlForSecurityDisplay(webContents.getVisibl eUrl(), false); |
225 | 227 |
226 final FaviconHelper faviconHelper = new FaviconHelper(); | 228 final FaviconHelper faviconHelper = new FaviconHelper(); |
227 faviconHelper.getLocalFaviconImageForURL(Profile.getLastUsedProfile(), | 229 faviconHelper.getLocalFaviconImageForURL(Profile.getLastUsedProfile(), |
228 webContents.getVisibleUrl(), | 230 webContents.getVisibleUrl(), |
229 mContext.getResources().getDimensionPixelSize(R.dimen.payments_f avicon_size), | 231 mContext.getResources().getDimensionPixelSize(R.dimen.payments_f avicon_size), |
230 new FaviconHelper.FaviconImageCallback() { | 232 new FaviconHelper.FaviconImageCallback() { |
231 @Override | 233 @Override |
(...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
400 | 402 |
401 PaymentRequestMetrics.recordRequestedInformationHistogram(requestPayerEm ail, | 403 PaymentRequestMetrics.recordRequestedInformationHistogram(requestPayerEm ail, |
402 requestPayerPhone, requestShipping, requestPayerName); | 404 requestPayerPhone, requestShipping, requestPayerName); |
403 } | 405 } |
404 | 406 |
405 /** | 407 /** |
406 * Called by the merchant website to show the payment request to the user. | 408 * Called by the merchant website to show the payment request to the user. |
407 */ | 409 */ |
408 @Override | 410 @Override |
409 public void show() { | 411 public void show() { |
410 if (mClient == null || mIsShowing) return; | 412 if (mClient == null) return; |
411 | 413 |
412 mIsShowing = true; | 414 if (sIsShowing) { |
415 disconnectFromClientWithDebugMessage("A PaymentRequest UI is already showing"); | |
416 return; | |
417 } | |
418 | |
419 sIsShowing = true; | |
413 if (disconnectIfNoPaymentMethodsSupported()) return; | 420 if (disconnectIfNoPaymentMethodsSupported()) return; |
414 | 421 |
415 // Catch any time the user switches tabs. Because the dialog is modal, a user shouldn't be | 422 // Catch any time the user switches tabs. Because the dialog is modal, a user shouldn't be |
416 // allowed to switch tabs, which can happen if the user receives an exte rnal Intent. | 423 // allowed to switch tabs, which can happen if the user receives an exte rnal Intent. |
417 mContext.getTabModelSelector().addObserver(mSelectorObserver); | 424 mContext.getTabModelSelector().addObserver(mSelectorObserver); |
418 mContext.getCurrentTabModel().addObserver(mTabModelObserver); | 425 mContext.getCurrentTabModel().addObserver(mTabModelObserver); |
419 | 426 |
420 mUI.show(); | 427 mUI.show(); |
421 recordSuccessFunnelHistograms("Shown"); | 428 recordSuccessFunnelHistograms("Shown"); |
422 } | 429 } |
423 | 430 |
424 private static Map<String, JSONObject> getValidatedMethodData( | 431 private static Map<String, JSONObject> getValidatedMethodData( |
425 PaymentMethodData[] methodData, CardEditor paymentMethodsCollector) { | 432 PaymentMethodData[] methodData, CardEditor paymentMethodsCollector) { |
426 // Payment methodData are required. | 433 // Payment methodData are required. |
427 if (methodData == null || methodData.length == 0) return null; | 434 if (methodData == null || methodData.length == 0) return null; |
428 Map<String, JSONObject> result = new HashMap<>(); | 435 Map<String, JSONObject> result = new ArrayMap<>(); |
429 for (int i = 0; i < methodData.length; i++) { | 436 for (int i = 0; i < methodData.length; i++) { |
430 JSONObject data = null; | 437 JSONObject data = null; |
431 if (!TextUtils.isEmpty(methodData[i].stringifiedData)) { | 438 if (!TextUtils.isEmpty(methodData[i].stringifiedData)) { |
432 try { | 439 try { |
433 data = new JSONObject(JsonSanitizer.sanitize(methodData[i].s tringifiedData)); | 440 data = new JSONObject(JsonSanitizer.sanitize(methodData[i].s tringifiedData)); |
434 } catch (JSONException | IOException | IllegalStateException e) { | 441 } catch (JSONException | IOException | IllegalStateException e) { |
435 // Payment method specific data should be a JSON object. | 442 // Payment method specific data should be a JSON object. |
436 // According to the payment request spec[1], for each method data, | 443 // According to the payment request spec[1], for each method data, |
437 // if the data field is supplied but is not a JSON-serializa ble object, | 444 // if the data field is supplied but is not a JSON-serializa ble object, |
438 // then should throw a TypeError. So, we should return null here even if | 445 // then should throw a TypeError. So, we should return null here even if |
(...skipping 18 matching lines...) Expand all Loading... | |
457 } | 464 } |
458 return result; | 465 return result; |
459 } | 466 } |
460 | 467 |
461 /** Queries the installed payment apps for their instruments that merchant s upports. */ | 468 /** Queries the installed payment apps for their instruments that merchant s upports. */ |
462 private void getMatchingPaymentInstruments() { | 469 private void getMatchingPaymentInstruments() { |
463 mPendingApps = new ArrayList<>(mApps); | 470 mPendingApps = new ArrayList<>(mApps); |
464 mPendingInstruments = new ArrayList<>(); | 471 mPendingInstruments = new ArrayList<>(); |
465 mPendingAutofillInstruments = new ArrayList<>(); | 472 mPendingAutofillInstruments = new ArrayList<>(); |
466 | 473 |
467 Map<PaymentApp, Map<String, JSONObject>> queryApps = new HashMap<>(); | 474 Map<PaymentApp, Map<String, JSONObject>> queryApps = new ArrayMap<>(); |
468 for (int i = 0; i < mApps.size(); i++) { | 475 for (int i = 0; i < mApps.size(); i++) { |
469 PaymentApp app = mApps.get(i); | 476 PaymentApp app = mApps.get(i); |
470 Map<String, JSONObject> appMethods = | 477 Map<String, JSONObject> appMethods = |
471 filterMerchantMethodData(mMethodData, app.getAppMethodNames( )); | 478 filterMerchantMethodData(mMethodData, app.getAppMethodNames( )); |
472 if (appMethods == null) { | 479 if (appMethods == null) { |
473 mPendingApps.remove(app); | 480 mPendingApps.remove(app); |
474 } else { | 481 } else { |
475 mArePaymentMethodsSupported = true; | 482 mArePaymentMethodsSupported = true; |
476 mMerchantSupportsAutofillPaymentInstruments |= app instanceof Au tofillPaymentApp; | 483 mMerchantSupportsAutofillPaymentInstruments |= app instanceof Au tofillPaymentApp; |
477 queryApps.put(app, appMethods); | 484 queryApps.put(app, appMethods); |
478 } | 485 } |
479 } | 486 } |
480 | 487 |
481 // Query instruments after mMerchantSupportsAutofillPaymentInstruments h as been initialized, | 488 // Query instruments after mMerchantSupportsAutofillPaymentInstruments h as been initialized, |
482 // so a fast response from a non-autofill payment app at the front of th e app list does not | 489 // so a fast response from a non-autofill payment app at the front of th e app list does not |
483 // cause NOT_SUPPORTED payment rejection. | 490 // cause NOT_SUPPORTED payment rejection. |
484 for (Map.Entry<PaymentApp, Map<String, JSONObject>> q : queryApps.entryS et()) { | 491 for (Map.Entry<PaymentApp, Map<String, JSONObject>> q : queryApps.entryS et()) { |
485 q.getKey().getInstruments(q.getValue(), this); | 492 q.getKey().getInstruments(q.getValue(), this); |
486 } | 493 } |
487 } | 494 } |
488 | 495 |
489 /** Filter out merchant method data that's not relevant to a payment app. Ca n return null. */ | 496 /** Filter out merchant method data that's not relevant to a payment app. Ca n return null. */ |
490 private static Map<String, JSONObject> filterMerchantMethodData( | 497 private static Map<String, JSONObject> filterMerchantMethodData( |
491 Map<String, JSONObject> merchantMethodData, Set<String> appMethods) { | 498 Map<String, JSONObject> merchantMethodData, Set<String> appMethods) { |
492 Map<String, JSONObject> result = null; | 499 Map<String, JSONObject> result = null; |
493 for (String method : appMethods) { | 500 for (String method : appMethods) { |
494 if (merchantMethodData.containsKey(method)) { | 501 if (merchantMethodData.containsKey(method)) { |
495 if (result == null) result = new HashMap<>(); | 502 if (result == null) result = new ArrayMap<>(); |
496 result.put(method, merchantMethodData.get(method)); | 503 result.put(method, merchantMethodData.get(method)); |
497 } | 504 } |
498 } | 505 } |
499 return result; | 506 return result; |
500 } | 507 } |
501 | 508 |
502 /** | 509 /** |
503 * Called by merchant to update the shipping options and line items after th e user has selected | 510 * Called by merchant to update the shipping options and line items after th e user has selected |
504 * their shipping address or shipping option. | 511 * their shipping address or shipping option. |
505 */ | 512 */ |
(...skipping 422 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
928 * Called when the merchant website has processed the payment. | 935 * Called when the merchant website has processed the payment. |
929 */ | 936 */ |
930 @Override | 937 @Override |
931 public void complete(int result) { | 938 public void complete(int result) { |
932 if (mClient == null) return; | 939 if (mClient == null) return; |
933 recordSuccessFunnelHistograms("Completed"); | 940 recordSuccessFunnelHistograms("Completed"); |
934 closeUI(PaymentComplete.FAIL != result); | 941 closeUI(PaymentComplete.FAIL != result); |
935 } | 942 } |
936 | 943 |
937 /** | 944 /** |
945 * Called by the merchant website to check if the user has complete payment instruments. | |
946 */ | |
947 @Override | |
948 public void canMakeActivePayment() { | |
949 if (mClient == null) return; | |
950 | |
951 if (sCanMakeActivePaymentQueries == null) sCanMakeActivePaymentQueries = new ArrayMap<>(); | |
952 | |
953 if (sCanMakeActivePaymentQueries.containsKey(mOrigin)) { | |
Marijn Kruisselbrink
2016/11/17 18:06:21
Is mOrigin the correct key to use here? I realize
please use gerrit instead
2016/11/17 20:07:21
After reading the comments on these methods, I sho
| |
954 if (!mMethodData.keySet().equals(sCanMakeActivePaymentQueries.get(mO rigin))) { | |
955 mClient.onCanMakeActivePayment(ActivePaymentQueryResult.QUERY_QU OTA_EXCEEDED); | |
956 if (sObserverForTest != null) { | |
957 sObserverForTest.onPaymentRequestServiceActivePaymentQueryRe sponded(); | |
958 } | |
959 return; | |
960 } | |
961 } else { | |
962 sCanMakeActivePaymentQueries.put(mOrigin, mMethodData.keySet()); | |
963 mHandler.postDelayed(new Runnable() { | |
964 @Override | |
965 public void run() { | |
966 sCanMakeActivePaymentQueries.remove(mOrigin); | |
967 } | |
968 }, CAN_MAKE_ACTIVE_PAYMENT_QUERY_PERIOD_MS); | |
969 } | |
970 | |
971 if (!mPendingApps.isEmpty() || !mPendingInstruments.isEmpty()) { | |
972 mQueriedCanMakeActivePayment = true; | |
973 } else { | |
974 mClient.onCanMakeActivePayment(mPaymentMethodsSection == null | |
975 || mPaymentMethodsSection.getSelectedItem() == null | |
976 ? ActivePaymentQueryResult.CANNOT_MAKE_ACTIVE_PAYMEN T | |
977 : ActivePaymentQueryResult.CAN_MAKE_ACTIVE_PAYMENT); | |
978 if (sObserverForTest != null) { | |
979 sObserverForTest.onPaymentRequestServiceActivePaymentQueryRespon ded(); | |
980 } | |
981 } | |
982 } | |
983 | |
984 /** | |
938 * Called when the renderer closes the Mojo connection. | 985 * Called when the renderer closes the Mojo connection. |
939 */ | 986 */ |
940 @Override | 987 @Override |
941 public void close() { | 988 public void close() { |
942 if (mClient == null) return; | 989 if (mClient == null) return; |
943 closeClient(); | 990 closeClient(); |
944 closeUI(true); | 991 closeUI(true); |
945 recordAbortReasonHistogram(PaymentRequestMetrics.ABORT_REASON_MOJO_RENDE RER_CLOSING); | 992 recordAbortReasonHistogram(PaymentRequestMetrics.ABORT_REASON_MOJO_RENDE RER_CLOSING); |
946 } | 993 } |
947 | 994 |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1014 // Pre-select the first instrument on the list, if it is complete. | 1061 // Pre-select the first instrument on the list, if it is complete. |
1015 int selection = SectionInformation.NO_SELECTION; | 1062 int selection = SectionInformation.NO_SELECTION; |
1016 if (!mPendingInstruments.isEmpty()) { | 1063 if (!mPendingInstruments.isEmpty()) { |
1017 PaymentInstrument first = mPendingInstruments.get(0); | 1064 PaymentInstrument first = mPendingInstruments.get(0); |
1018 if (!(first instanceof AutofillPaymentInstrument) | 1065 if (!(first instanceof AutofillPaymentInstrument) |
1019 || ((AutofillPaymentInstrument) first).isComplete()) { | 1066 || ((AutofillPaymentInstrument) first).isComplete()) { |
1020 selection = 0; | 1067 selection = 0; |
1021 } | 1068 } |
1022 } | 1069 } |
1023 | 1070 |
1071 if (mQueriedCanMakeActivePayment) { | |
1072 mQueriedCanMakeActivePayment = false; | |
1073 mClient.onCanMakeActivePayment(selection == 0 | |
1074 ? ActivePaymentQueryResult.CAN_MAKE_ACTIVE_PAYMENT | |
1075 : ActivePaymentQueryResult.CANNOT_MAKE_ACTIVE_PAYMEN T); | |
1076 if (sObserverForTest != null) { | |
1077 sObserverForTest.onPaymentRequestServiceActivePaymentQueryRespon ded(); | |
1078 } | |
1079 } | |
1080 | |
1024 // The list of payment instruments is ready to display. | 1081 // The list of payment instruments is ready to display. |
1025 mPaymentMethodsSection = new SectionInformation(PaymentRequestUI.TYPE_PA YMENT_METHODS, | 1082 mPaymentMethodsSection = new SectionInformation(PaymentRequestUI.TYPE_PA YMENT_METHODS, |
1026 selection, mPendingInstruments); | 1083 selection, mPendingInstruments); |
1027 | 1084 |
1028 mPendingInstruments.clear(); | 1085 mPendingInstruments.clear(); |
1029 | 1086 |
1030 // UI has requested the full list of payment instruments. Provide it now . | 1087 // UI has requested the full list of payment instruments. Provide it now . |
1031 if (mPaymentInformationCallback != null) providePaymentInformation(); | 1088 if (mPaymentInformationCallback != null) providePaymentInformation(); |
1032 } | 1089 } |
1033 | 1090 |
1034 /** | 1091 /** |
1035 * If no payment methods are supported, disconnect from the client and retur n true. | 1092 * If no payment methods are supported, disconnect from the client and retur n true. |
1036 * | 1093 * |
1037 * @return True if no payment methods are supported | 1094 * @return True if no payment methods are supported |
1038 */ | 1095 */ |
1039 private boolean disconnectIfNoPaymentMethodsSupported() { | 1096 private boolean disconnectIfNoPaymentMethodsSupported() { |
1040 boolean waitingForPaymentApps = !mPendingApps.isEmpty() || !mPendingInst ruments.isEmpty(); | 1097 boolean waitingForPaymentApps = !mPendingApps.isEmpty() || !mPendingInst ruments.isEmpty(); |
1041 boolean foundPaymentMethods = | 1098 boolean foundPaymentMethods = |
1042 mPaymentMethodsSection != null && !mPaymentMethodsSection.isEmpt y(); | 1099 mPaymentMethodsSection != null && !mPaymentMethodsSection.isEmpt y(); |
1043 boolean userCanAddCreditCard = mMerchantSupportsAutofillPaymentInstrumen ts | 1100 boolean userCanAddCreditCard = mMerchantSupportsAutofillPaymentInstrumen ts |
1044 && !ChromeFeatureList.isEnabled(ChromeFeatureList.NO_CREDIT_CARD _ABORT); | 1101 && !ChromeFeatureList.isEnabled(ChromeFeatureList.NO_CREDIT_CARD _ABORT); |
1045 | 1102 |
1046 if (!mArePaymentMethodsSupported | 1103 if (!mArePaymentMethodsSupported |
1047 || (mIsShowing && !waitingForPaymentApps && !foundPaymentMethods | 1104 || (sIsShowing && !waitingForPaymentApps && !foundPaymentMethods |
1048 && !userCanAddCreditCard)) { | 1105 && !userCanAddCreditCard)) { |
1049 // All payment apps have responded, but none of them have instrument s. It's possible to | 1106 // All payment apps have responded, but none of them have instrument s. It's possible to |
1050 // add credit cards, but the merchant does not support them either. The payment request | 1107 // add credit cards, but the merchant does not support them either. The payment request |
1051 // must be rejected. | 1108 // must be rejected. |
1052 disconnectFromClientWithDebugMessage("Requested payment methods have no instruments", | 1109 disconnectFromClientWithDebugMessage("Requested payment methods have no instruments", |
1053 PaymentErrorReason.NOT_SUPPORTED); | 1110 PaymentErrorReason.NOT_SUPPORTED); |
1054 recordAbortReasonHistogram(mArePaymentMethodsSupported | 1111 recordAbortReasonHistogram(mArePaymentMethodsSupported |
1055 ? PaymentRequestMetrics.ABORT_REASON_NO_MATCHING_PAY MENT_METHOD | 1112 ? PaymentRequestMetrics.ABORT_REASON_NO_MATCHING_PAY MENT_METHOD |
1056 : PaymentRequestMetrics.ABORT_REASON_NO_SUPPORTED_PA YMENT_METHOD); | 1113 : PaymentRequestMetrics.ABORT_REASON_NO_SUPPORTED_PA YMENT_METHOD); |
1057 if (sObserverForTest != null) sObserverForTest.onPaymentRequestServi ceShowFailed(); | 1114 if (sObserverForTest != null) sObserverForTest.onPaymentRequestServi ceShowFailed(); |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1154 mPaymentMethodsSection = null; | 1211 mPaymentMethodsSection = null; |
1155 } | 1212 } |
1156 | 1213 |
1157 mContext.getTabModelSelector().removeObserver(mSelectorObserver); | 1214 mContext.getTabModelSelector().removeObserver(mSelectorObserver); |
1158 mContext.getCurrentTabModel().removeObserver(mTabModelObserver); | 1215 mContext.getCurrentTabModel().removeObserver(mTabModelObserver); |
1159 } | 1216 } |
1160 | 1217 |
1161 private void closeClient() { | 1218 private void closeClient() { |
1162 if (mClient != null) mClient.close(); | 1219 if (mClient != null) mClient.close(); |
1163 mClient = null; | 1220 mClient = null; |
1164 mDismissObserver.onPaymentRequestDismissed(); | 1221 sIsShowing = false; |
1165 } | 1222 } |
1166 | 1223 |
1167 @VisibleForTesting | 1224 @VisibleForTesting |
1168 public static void setObserverForTest(PaymentRequestServiceObserverForTest o bserverForTest) { | 1225 public static void setObserverForTest(PaymentRequestServiceObserverForTest o bserverForTest) { |
1169 sObserverForTest = observerForTest; | 1226 sObserverForTest = observerForTest; |
1170 } | 1227 } |
1171 | 1228 |
1172 /** | 1229 /** |
1173 * Records specific histograms related to the different steps of a successfu l checkout. | 1230 * Records specific histograms related to the different steps of a successfu l checkout. |
1174 */ | 1231 */ |
(...skipping 19 matching lines...) Expand all Loading... | |
1194 "PaymentRequest.CheckoutFunnel.Aborted", abortReason, | 1251 "PaymentRequest.CheckoutFunnel.Aborted", abortReason, |
1195 PaymentRequestMetrics.ABORT_REASON_MAX); | 1252 PaymentRequestMetrics.ABORT_REASON_MAX); |
1196 | 1253 |
1197 if (abortReason == PaymentRequestMetrics.ABORT_REASON_ABORTED_BY_USER) { | 1254 if (abortReason == PaymentRequestMetrics.ABORT_REASON_ABORTED_BY_USER) { |
1198 mJourneyLogger.recordJourneyStatsHistograms("UserAborted"); | 1255 mJourneyLogger.recordJourneyStatsHistograms("UserAborted"); |
1199 } else { | 1256 } else { |
1200 mJourneyLogger.recordJourneyStatsHistograms("OtherAborted"); | 1257 mJourneyLogger.recordJourneyStatsHistograms("OtherAborted"); |
1201 } | 1258 } |
1202 } | 1259 } |
1203 } | 1260 } |
OLD | NEW |