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.content.Intent; | 8 import android.content.Intent; |
9 import android.graphics.Bitmap; | 9 import android.graphics.Bitmap; |
10 import android.os.Handler; | 10 import android.os.Handler; |
(...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
176 /** Every origin can call canMakePayment() every 30 minutes. */ | 176 /** Every origin can call canMakePayment() every 30 minutes. */ |
177 private static final int CAN_MAKE_PAYMENT_QUERY_PERIOD_MS = 30 * 60 * 1000; | 177 private static final int CAN_MAKE_PAYMENT_QUERY_PERIOD_MS = 30 * 60 * 1000; |
178 | 178 |
179 private static PaymentRequestServiceObserverForTest sObserverForTest; | 179 private static PaymentRequestServiceObserverForTest sObserverForTest; |
180 | 180 |
181 /** True if show() was called in any PaymentRequestImpl object. */ | 181 /** True if show() was called in any PaymentRequestImpl object. */ |
182 private static boolean sIsShowing; | 182 private static boolean sIsShowing; |
183 | 183 |
184 /** | 184 /** |
185 * In-memory mapping of the origins of websites that have recently called ca
nMakePayment() | 185 * In-memory mapping of the origins of websites that have recently called ca
nMakePayment() |
186 * to the list of the payment methods that were been queried. Used for throt
tling the usage of | 186 * to the list of the payment methods that were being queried. Used for thro
ttling the usage of |
187 * this call. The mapping is shared among all instances of PaymentRequestImp
l in the browser | 187 * this call. The mapping is shared among all instances of PaymentRequestImp
l in the browser |
188 * process on UI thread. The user can reset the throttling mechanism by rest
arting the browser. | 188 * process on UI thread. The user can reset the throttling mechanism by rest
arting the browser. |
189 */ | 189 */ |
190 private static Map<String, CanMakePaymentQuery> sCanMakePaymentQueries; | 190 private static Map<String, CanMakePaymentQuery> sCanMakePaymentQueries; |
191 | 191 |
192 /** Monitors changes in the TabModelSelector. */ | 192 /** Monitors changes in the TabModelSelector. */ |
193 private final TabModelSelectorObserver mSelectorObserver = new EmptyTabModel
SelectorObserver() { | 193 private final TabModelSelectorObserver mSelectorObserver = new EmptyTabModel
SelectorObserver() { |
194 @Override | 194 @Override |
195 public void onTabModelSelected(TabModel newModel, TabModel oldModel) { | 195 public void onTabModelSelected(TabModel newModel, TabModel oldModel) { |
196 onDismiss(); | 196 onDismiss(); |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
261 private boolean mPaymentAppRunning; | 261 private boolean mPaymentAppRunning; |
262 private boolean mMerchantSupportsAutofillPaymentInstruments; | 262 private boolean mMerchantSupportsAutofillPaymentInstruments; |
263 private ContactEditor mContactEditor; | 263 private ContactEditor mContactEditor; |
264 private boolean mHasRecordedAbortReason; | 264 private boolean mHasRecordedAbortReason; |
265 private boolean mQueriedCanMakePayment; | 265 private boolean mQueriedCanMakePayment; |
266 private CurrencyStringFormatter mFormatter; | 266 private CurrencyStringFormatter mFormatter; |
267 | 267 |
268 /** True if any of the requested payment methods are supported. */ | 268 /** True if any of the requested payment methods are supported. */ |
269 private boolean mArePaymentMethodsSupported; | 269 private boolean mArePaymentMethodsSupported; |
270 | 270 |
| 271 /** |
| 272 * True after at least one usable payment instrument has been found. Should
be read only after |
| 273 * all payment apps have been queried. |
| 274 */ |
| 275 private boolean mCanMakePayment; |
| 276 |
271 /** The helper to create and fill the response to send to the merchant. */ | 277 /** The helper to create and fill the response to send to the merchant. */ |
272 private PaymentResponseHelper mPaymentResponseHelper; | 278 private PaymentResponseHelper mPaymentResponseHelper; |
273 | 279 |
274 /** | 280 /** |
275 * Builds the PaymentRequest service implementation. | 281 * Builds the PaymentRequest service implementation. |
276 * | 282 * |
277 * @param context The context where PaymentRequest has been invoked. | 283 * @param context The context where PaymentRequest has been invoked. |
278 * @param webContents The web contents that have invoked the PaymentRequ
est API. | 284 * @param webContents The web contents that have invoked the PaymentRequ
est API. |
279 */ | 285 */ |
280 public PaymentRequestImpl(Activity context, WebContents webContents) { | 286 public PaymentRequestImpl(Activity context, WebContents webContents) { |
(...skipping 886 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1167 } | 1173 } |
1168 return; | 1174 return; |
1169 } | 1175 } |
1170 | 1176 |
1171 if (query.getPreviousResponse() != null) { | 1177 if (query.getPreviousResponse() != null) { |
1172 respondCanMakePaymentQuery(query.getPreviousResponse().booleanValue(
)); | 1178 respondCanMakePaymentQuery(query.getPreviousResponse().booleanValue(
)); |
1173 return; | 1179 return; |
1174 } | 1180 } |
1175 | 1181 |
1176 query.addObserver(this); | 1182 query.addObserver(this); |
1177 if (mPendingApps.isEmpty() && mPendingInstruments.isEmpty()) { | 1183 if (isFinishedQueryingPaymentApps()) query.setResponse(mCanMakePayment); |
1178 query.setResponse(mPaymentMethodsSection != null | |
1179 && mPaymentMethodsSection.getSelectedItem() != null); | |
1180 } | |
1181 } | 1184 } |
1182 | 1185 |
1183 private void respondCanMakePaymentQuery(boolean response) { | 1186 private void respondCanMakePaymentQuery(boolean response) { |
1184 mClient.onCanMakePayment(response ? CanMakePaymentQueryResult.CAN_MAKE_P
AYMENT | 1187 mClient.onCanMakePayment(response ? CanMakePaymentQueryResult.CAN_MAKE_P
AYMENT |
1185 : CanMakePaymentQueryResult.CANNOT_MAKE_PAYMENT); | 1188 : CanMakePaymentQueryResult.CANNOT_MAKE_PAYMENT); |
1186 if (sObserverForTest != null) { | 1189 if (sObserverForTest != null) { |
1187 sObserverForTest.onPaymentRequestServiceCanMakePaymentQueryResponded
(); | 1190 sObserverForTest.onPaymentRequestServiceCanMakePaymentQueryResponded
(); |
1188 } | 1191 } |
1189 } | 1192 } |
1190 | 1193 |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1233 } | 1236 } |
1234 } | 1237 } |
1235 } | 1238 } |
1236 | 1239 |
1237 // Some payment apps still have not responded. Continue waiting for them
. | 1240 // Some payment apps still have not responded. Continue waiting for them
. |
1238 if (!mPendingApps.isEmpty()) return; | 1241 if (!mPendingApps.isEmpty()) return; |
1239 | 1242 |
1240 if (disconnectIfNoPaymentMethodsSupported()) return; | 1243 if (disconnectIfNoPaymentMethodsSupported()) return; |
1241 | 1244 |
1242 // Load the validation rules for each unique region code in the credit c
ard billing | 1245 // Load the validation rules for each unique region code in the credit c
ard billing |
1243 // addresses. | 1246 // addresses and check for validity. |
1244 Set<String> uniqueCountryCodes = new HashSet<>(); | 1247 Set<String> uniqueCountryCodes = new HashSet<>(); |
1245 for (int i = 0; i < mPendingAutofillInstruments.size(); ++i) { | 1248 for (int i = 0; i < mPendingAutofillInstruments.size(); ++i) { |
1246 assert mPendingAutofillInstruments.get(i) instanceof AutofillPayment
Instrument; | 1249 assert mPendingAutofillInstruments.get(i) instanceof AutofillPayment
Instrument; |
| 1250 AutofillPaymentInstrument creditCard = |
| 1251 (AutofillPaymentInstrument) mPendingAutofillInstruments.get(
i); |
1247 | 1252 |
1248 String countryCode = AutofillAddress | 1253 String countryCode = AutofillAddress.getCountryCode(creditCard.getBi
llingAddress()); |
1249 .getCountryCode(((AutofillPaymentInstrument) mPendingAutofil
lInstruments.get( | |
1250 i)).getBillingAddress()); | |
1251 if (!uniqueCountryCodes.contains(countryCode)) { | 1254 if (!uniqueCountryCodes.contains(countryCode)) { |
1252 uniqueCountryCodes.add(countryCode); | 1255 uniqueCountryCodes.add(countryCode); |
1253 PersonalDataManager.getInstance().loadRulesForRegion(countryCode
); | 1256 PersonalDataManager.getInstance().loadRulesForRegion(countryCode
); |
1254 } | 1257 } |
| 1258 |
| 1259 // If there's a card on file with a valid number and a name, then |
| 1260 // PaymentRequest.canMakePayment() returns true. |
| 1261 mCanMakePayment |= creditCard.isValid(); |
1255 } | 1262 } |
1256 | 1263 |
1257 // List order: | 1264 // List order: |
1258 // > Non-autofill instruments. | 1265 // > Non-autofill instruments. |
1259 // > Complete autofill instruments. | 1266 // > Complete autofill instruments. |
1260 // > Incomplete autofill instruments. | 1267 // > Incomplete autofill instruments. |
1261 Collections.sort(mPendingAutofillInstruments, COMPLETENESS_COMPARATOR); | 1268 Collections.sort(mPendingAutofillInstruments, COMPLETENESS_COMPARATOR); |
1262 mPendingInstruments.addAll(mPendingAutofillInstruments); | 1269 mPendingInstruments.addAll(mPendingAutofillInstruments); |
1263 | 1270 |
1264 // Log the number of suggested credit cards. | 1271 // Log the number of suggested credit cards. |
1265 mJourneyLogger.setNumberOfSuggestionsShown(PaymentRequestJourneyLogger.S
ECTION_CREDIT_CARDS, | 1272 mJourneyLogger.setNumberOfSuggestionsShown(PaymentRequestJourneyLogger.S
ECTION_CREDIT_CARDS, |
1266 mPendingAutofillInstruments.size()); | 1273 mPendingAutofillInstruments.size()); |
1267 | 1274 |
1268 mPendingAutofillInstruments.clear(); | 1275 mPendingAutofillInstruments.clear(); |
1269 | 1276 |
1270 // Pre-select the first instrument on the list, if it is complete. | 1277 // Possibly pre-select the first instrument on the list. |
1271 int selection = SectionInformation.NO_SELECTION; | 1278 int selection = SectionInformation.NO_SELECTION; |
1272 if (!mPendingInstruments.isEmpty()) { | 1279 if (!mPendingInstruments.isEmpty()) { |
1273 PaymentInstrument first = mPendingInstruments.get(0); | 1280 PaymentInstrument first = mPendingInstruments.get(0); |
1274 if (!(first instanceof AutofillPaymentInstrument) | 1281 if (first instanceof AutofillPaymentInstrument) { |
1275 || ((AutofillPaymentInstrument) first).isComplete()) { | 1282 AutofillPaymentInstrument creditCard = (AutofillPaymentInstrumen
t) first; |
| 1283 if (creditCard.isComplete()) selection = 0; |
| 1284 } else { |
| 1285 // If a payment app is available, then PaymentRequest.canMakePay
ment() returns true. |
| 1286 mCanMakePayment = true; |
1276 selection = 0; | 1287 selection = 0; |
1277 } | 1288 } |
1278 } | 1289 } |
1279 | 1290 |
1280 CanMakePaymentQuery query = sCanMakePaymentQueries.get(mOrigin); | 1291 CanMakePaymentQuery query = sCanMakePaymentQueries.get(mOrigin); |
1281 if (query != null) query.setResponse(selection == 0); | 1292 if (query != null) query.setResponse(mCanMakePayment); |
1282 | 1293 |
1283 // The list of payment instruments is ready to display. | 1294 // The list of payment instruments is ready to display. |
1284 mPaymentMethodsSection = new SectionInformation(PaymentRequestUI.TYPE_PA
YMENT_METHODS, | 1295 mPaymentMethodsSection = new SectionInformation(PaymentRequestUI.TYPE_PA
YMENT_METHODS, |
1285 selection, mPendingInstruments); | 1296 selection, mPendingInstruments); |
1286 | 1297 |
1287 mPendingInstruments.clear(); | 1298 mPendingInstruments.clear(); |
1288 | 1299 |
1289 updateInstrumentModifiedTotals(); | 1300 updateInstrumentModifiedTotals(); |
1290 | 1301 |
1291 // UI has requested the full list of payment instruments. Provide it now
. | 1302 // UI has requested the full list of payment instruments. Provide it now
. |
1292 if (mPaymentInformationCallback != null) providePaymentInformation(); | 1303 if (mPaymentInformationCallback != null) providePaymentInformation(); |
1293 } | 1304 } |
1294 | 1305 |
1295 /** | 1306 /** |
1296 * If no payment methods are supported, disconnect from the client and retur
n true. | 1307 * If no payment methods are supported, disconnect from the client and retur
n true. |
1297 * | 1308 * |
1298 * @return True if no payment methods are supported | 1309 * @return True if no payment methods are supported |
1299 */ | 1310 */ |
1300 private boolean disconnectIfNoPaymentMethodsSupported() { | 1311 private boolean disconnectIfNoPaymentMethodsSupported() { |
1301 if (mPendingApps == null || !mPendingApps.isEmpty() || !mPendingInstrume
nts.isEmpty()) { | 1312 if (!isFinishedQueryingPaymentApps()) return false; |
1302 // Waiting for pending apps and instruments. | |
1303 return false; | |
1304 } | |
1305 | 1313 |
1306 boolean foundPaymentMethods = mPaymentMethodsSection != null | 1314 boolean foundPaymentMethods = mPaymentMethodsSection != null |
1307 && !mPaymentMethodsSection.isEmpty(); | 1315 && !mPaymentMethodsSection.isEmpty(); |
1308 boolean userCanAddCreditCard = mMerchantSupportsAutofillPaymentInstrumen
ts | 1316 boolean userCanAddCreditCard = mMerchantSupportsAutofillPaymentInstrumen
ts |
1309 && !ChromeFeatureList.isEnabled(ChromeFeatureList.NO_CREDIT_CARD
_ABORT); | 1317 && !ChromeFeatureList.isEnabled(ChromeFeatureList.NO_CREDIT_CARD
_ABORT); |
1310 | 1318 |
1311 if (!mArePaymentMethodsSupported | 1319 if (!mArePaymentMethodsSupported |
1312 || (getIsShowing() && !foundPaymentMethods && !userCanAddCreditC
ard)) { | 1320 || (getIsShowing() && !foundPaymentMethods && !userCanAddCreditC
ard)) { |
1313 // All payment apps have responded, but none of them have instrument
s. It's possible to | 1321 // All payment apps have responded, but none of them have instrument
s. It's possible to |
1314 // add credit cards, but the merchant does not support them either.
The payment request | 1322 // add credit cards, but the merchant does not support them either.
The payment request |
1315 // must be rejected. | 1323 // must be rejected. |
1316 disconnectFromClientWithDebugMessage("Requested payment methods have
no instruments", | 1324 disconnectFromClientWithDebugMessage("Requested payment methods have
no instruments", |
1317 PaymentErrorReason.NOT_SUPPORTED); | 1325 PaymentErrorReason.NOT_SUPPORTED); |
1318 recordAbortReasonHistogram(mArePaymentMethodsSupported | 1326 recordAbortReasonHistogram(mArePaymentMethodsSupported |
1319 ? PaymentRequestMetrics.ABORT_REASON_NO_MATCHING_PAYMENT_MET
HOD | 1327 ? PaymentRequestMetrics.ABORT_REASON_NO_MATCHING_PAYMENT_MET
HOD |
1320 : PaymentRequestMetrics.ABORT_REASON_NO_SUPPORTED_PAYMENT_ME
THOD); | 1328 : PaymentRequestMetrics.ABORT_REASON_NO_SUPPORTED_PAYMENT_ME
THOD); |
1321 if (sObserverForTest != null) sObserverForTest.onPaymentRequestServi
ceShowFailed(); | 1329 if (sObserverForTest != null) sObserverForTest.onPaymentRequestServi
ceShowFailed(); |
1322 return true; | 1330 return true; |
1323 } | 1331 } |
1324 | 1332 |
1325 return false; | 1333 return false; |
1326 } | 1334 } |
1327 | 1335 |
| 1336 /** @return True after payment apps have been queried. */ |
| 1337 private boolean isFinishedQueryingPaymentApps() { |
| 1338 return mPendingApps != null && mPendingApps.isEmpty() && mPendingInstrum
ents.isEmpty(); |
| 1339 } |
| 1340 |
1328 /** | 1341 /** |
1329 * Saves the given instrument in either "autofill" or "non-autofill" list. T
he separation | 1342 * Saves the given instrument in either "autofill" or "non-autofill" list. T
he separation |
1330 * enables placing autofill instruments on the bottom of the list. | 1343 * enables placing autofill instruments on the bottom of the list. |
1331 * | 1344 * |
1332 * @param instrument The instrument to add to either "autofill" or "non-auto
fill" list. | 1345 * @param instrument The instrument to add to either "autofill" or "non-auto
fill" list. |
1333 */ | 1346 */ |
1334 private void addPendingInstrument(PaymentInstrument instrument) { | 1347 private void addPendingInstrument(PaymentInstrument instrument) { |
1335 if (instrument instanceof AutofillPaymentInstrument) { | 1348 if (instrument instanceof AutofillPaymentInstrument) { |
1336 mPendingAutofillInstruments.add(instrument); | 1349 mPendingAutofillInstruments.add(instrument); |
1337 } else { | 1350 } else { |
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1487 "PaymentRequest.CheckoutFunnel.Aborted", abortReason, | 1500 "PaymentRequest.CheckoutFunnel.Aborted", abortReason, |
1488 PaymentRequestMetrics.ABORT_REASON_MAX); | 1501 PaymentRequestMetrics.ABORT_REASON_MAX); |
1489 | 1502 |
1490 if (abortReason == PaymentRequestMetrics.ABORT_REASON_ABORTED_BY_USER) { | 1503 if (abortReason == PaymentRequestMetrics.ABORT_REASON_ABORTED_BY_USER) { |
1491 mJourneyLogger.recordJourneyStatsHistograms("UserAborted"); | 1504 mJourneyLogger.recordJourneyStatsHistograms("UserAborted"); |
1492 } else { | 1505 } else { |
1493 mJourneyLogger.recordJourneyStatsHistograms("OtherAborted"); | 1506 mJourneyLogger.recordJourneyStatsHistograms("OtherAborted"); |
1494 } | 1507 } |
1495 } | 1508 } |
1496 } | 1509 } |
OLD | NEW |