| 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 |