Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(328)

Side by Side Diff: chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java

Issue 2467393002: Add canMakeActivePayment() method to web payments. (Closed)
Patch Set: Hide behind a flag Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698