Commit 8081c029 authored by sebsg's avatar sebsg Committed by Commit bot

[Payments] Normalize billing address before sending to the merchant.

BUG=654773

Review-Url: https://codereview.chromium.org/2413533003
Cr-Commit-Position: refs/heads/master@{#427242}
parent be2411a9
...@@ -761,10 +761,10 @@ public class PersonalDataManager { ...@@ -761,10 +761,10 @@ public class PersonalDataManager {
mPersonalDataManagerAndroid, guid, regionCode, delegate); mPersonalDataManagerAndroid, guid, regionCode, delegate);
} }
/** Cancels the pending address normalization. */ /** Cancels the pending address normalizations. */
public void cancelPendingAddressNormalization() { public void cancelPendingAddressNormalizations() {
ThreadUtils.assertOnUiThread(); ThreadUtils.assertOnUiThread();
nativeCancelPendingAddressNormalization(mPersonalDataManagerAndroid); nativeCancelPendingAddressNormalizations(mPersonalDataManagerAndroid);
} }
/** /**
...@@ -872,7 +872,7 @@ public class PersonalDataManager { ...@@ -872,7 +872,7 @@ public class PersonalDataManager {
long nativePersonalDataManagerAndroid, String regionCode); long nativePersonalDataManagerAndroid, String regionCode);
private native boolean nativeStartAddressNormalization(long nativePersonalDataManagerAndroid, private native boolean nativeStartAddressNormalization(long nativePersonalDataManagerAndroid,
String guid, String regionCode, NormalizedAddressRequestDelegate delegate); String guid, String regionCode, NormalizedAddressRequestDelegate delegate);
private native void nativeCancelPendingAddressNormalization( private native void nativeCancelPendingAddressNormalizations(
long nativePersonalDataManagerAndroid); long nativePersonalDataManagerAndroid);
private static native boolean nativeIsAutofillEnabled(); private static native boolean nativeIsAutofillEnabled();
private static native void nativeSetAutofillEnabled(boolean enable); private static native void nativeSetAutofillEnabled(boolean enable);
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
package org.chromium.chrome.browser.payments; package org.chromium.chrome.browser.payments;
import android.content.Context; import android.content.Context;
import android.os.Handler;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.JsonWriter; import android.util.JsonWriter;
...@@ -15,6 +16,7 @@ import org.chromium.chrome.browser.autofill.PersonalDataManager; ...@@ -15,6 +16,7 @@ import org.chromium.chrome.browser.autofill.PersonalDataManager;
import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard; import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
import org.chromium.chrome.browser.autofill.PersonalDataManager.FullCardRequestDelegate; import org.chromium.chrome.browser.autofill.PersonalDataManager.FullCardRequestDelegate;
import org.chromium.chrome.browser.autofill.PersonalDataManager.NormalizedAddressRequestDelegate;
import org.chromium.content_public.browser.WebContents; import org.chromium.content_public.browser.WebContents;
import org.chromium.payments.mojom.PaymentItem; import org.chromium.payments.mojom.PaymentItem;
...@@ -27,14 +29,17 @@ import javax.annotation.Nullable; ...@@ -27,14 +29,17 @@ import javax.annotation.Nullable;
/** /**
* The locally stored credit card payment instrument. * The locally stored credit card payment instrument.
*/ */
public class AutofillPaymentInstrument public class AutofillPaymentInstrument extends PaymentInstrument
extends PaymentInstrument implements FullCardRequestDelegate { implements FullCardRequestDelegate, NormalizedAddressRequestDelegate {
private final Context mContext; private final Context mContext;
private final WebContents mWebContents; private final WebContents mWebContents;
private CreditCard mCard; private CreditCard mCard;
private boolean mIsComplete; private boolean mIsComplete;
private String mSecurityCode;
@Nullable private AutofillProfile mBillingAddress; @Nullable private AutofillProfile mBillingAddress;
@Nullable private InstrumentDetailsCallback mCallback; @Nullable private InstrumentDetailsCallback mCallback;
private boolean mIsWaitingForBillingNormalization;
private boolean mIsWaitingForFullCardDetails;
/** /**
* Builds a payment instrument for the given credit card. * Builds a payment instrument for the given credit card.
...@@ -67,24 +72,81 @@ public class AutofillPaymentInstrument ...@@ -67,24 +72,81 @@ public class AutofillPaymentInstrument
public void getInstrumentDetails(String unusedMerchantName, String unusedOrigin, public void getInstrumentDetails(String unusedMerchantName, String unusedOrigin,
PaymentItem unusedTotal, List<PaymentItem> unusedCart, JSONObject unusedDetails, PaymentItem unusedTotal, List<PaymentItem> unusedCart, JSONObject unusedDetails,
InstrumentDetailsCallback callback) { InstrumentDetailsCallback callback) {
// The billing address should never be null for a credit card at this point.
assert mBillingAddress != null;
assert mIsComplete; assert mIsComplete;
assert mCallback == null; assert mCallback == null;
mCallback = callback; mCallback = callback;
mIsWaitingForBillingNormalization = true;
mIsWaitingForFullCardDetails = true;
// Start the billing address normalization.
PersonalDataManager.getInstance().normalizeAddress(
mBillingAddress.getGUID(), AutofillAddress.getCountryCode(mBillingAddress), this);
// Start to get the full card details.
PersonalDataManager.getInstance().getFullCard(mWebContents, mCard, this); PersonalDataManager.getInstance().getFullCard(mWebContents, mCard, this);
} }
@Override @Override
public void onFullCardDetails(CreditCard card, String cvc) { public void onFullCardDetails(CreditCard updatedCard, String cvc) {
// Keep the cvc for after the normalization.
mSecurityCode = cvc;
// Update the card's expiration date.
mCard.setMonth(updatedCard.getMonth());
mCard.setYear(updatedCard.getYear());
mIsWaitingForFullCardDetails = false;
// Show the loading UI while the address gets normalized.
mCallback.loadingInstrumentDetails();
// Wait for the billing address normalization before sending the instrument details.
if (mIsWaitingForBillingNormalization) {
// If the normalization is not completed yet, Start a timer to cancel it if it takes too
// long.
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
onAddressNormalized(null);
}
}, PersonalDataManager.getInstance().getNormalizationTimeoutMS());
return;
} else {
sendIntrumentDetails();
}
}
@Override
public void onAddressNormalized(AutofillProfile profile) {
if (!mIsWaitingForBillingNormalization) return;
mIsWaitingForBillingNormalization = false;
// If the normalization finished first, use the normalized address.
if (profile != null) mBillingAddress = profile;
// Wait for the full card details before sending the instrument details.
if (!mIsWaitingForFullCardDetails) sendIntrumentDetails();
}
/**
* Stringify the card details and send the resulting string and the method name to the
* registered callback.
*/
private void sendIntrumentDetails() {
StringWriter stringWriter = new StringWriter(); StringWriter stringWriter = new StringWriter();
JsonWriter json = new JsonWriter(stringWriter); JsonWriter json = new JsonWriter(stringWriter);
try { try {
json.beginObject(); json.beginObject();
json.name("cardholderName").value(card.getName()); json.name("cardholderName").value(mCard.getName());
json.name("cardNumber").value(card.getNumber()); json.name("cardNumber").value(mCard.getNumber());
json.name("expiryMonth").value(card.getMonth()); json.name("expiryMonth").value(mCard.getMonth());
json.name("expiryYear").value(card.getYear()); json.name("expiryYear").value(mCard.getYear());
json.name("cardSecurityCode").value(cvc); json.name("cardSecurityCode").value(mSecurityCode);
json.name("billingAddress").beginObject(); json.name("billingAddress").beginObject();
...@@ -117,9 +179,12 @@ public class AutofillPaymentInstrument ...@@ -117,9 +179,12 @@ public class AutofillPaymentInstrument
} catch (IOException e) { } catch (IOException e) {
onFullCardError(); onFullCardError();
return; return;
} finally {
mSecurityCode = "";
} }
mCallback.onInstrumentDetailsReady(card.getBasicCardPaymentType(), stringWriter.toString()); mCallback.onInstrumentDetailsReady(
mCard.getBasicCardPaymentType(), stringWriter.toString());
} }
private static String ensureNotNull(@Nullable String value) { private static String ensureNotNull(@Nullable String value) {
...@@ -172,4 +237,9 @@ public class AutofillPaymentInstrument ...@@ -172,4 +237,9 @@ public class AutofillPaymentInstrument
public CreditCard getCard() { public CreditCard getCard() {
return mCard; return mCard;
} }
}
/** @return The billing address associated with this credit card. */
public AutofillProfile getBillingAddress() {
return mBillingAddress;
}
}
\ No newline at end of file
...@@ -21,6 +21,12 @@ public abstract class PaymentInstrument extends PaymentOption { ...@@ -21,6 +21,12 @@ public abstract class PaymentInstrument extends PaymentOption {
* The interface for the requester of instrument details. * The interface for the requester of instrument details.
*/ */
public interface InstrumentDetailsCallback { public interface InstrumentDetailsCallback {
/**
* Called by the credit card payment instrument when CVC has been unmasked, but billing
* address has not been normalized yet.
*/
void loadingInstrumentDetails();
/** /**
* Called after retrieving instrument details. * Called after retrieving instrument details.
* *
......
...@@ -20,7 +20,6 @@ import org.chromium.chrome.R; ...@@ -20,7 +20,6 @@ import org.chromium.chrome.R;
import org.chromium.chrome.browser.ChromeActivity; import org.chromium.chrome.browser.ChromeActivity;
import org.chromium.chrome.browser.autofill.PersonalDataManager; import org.chromium.chrome.browser.autofill.PersonalDataManager;
import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
import org.chromium.chrome.browser.autofill.PersonalDataManager.NormalizedAddressRequestDelegate;
import org.chromium.chrome.browser.favicon.FaviconHelper; import org.chromium.chrome.browser.favicon.FaviconHelper;
import org.chromium.chrome.browser.payments.ui.Completable; import org.chromium.chrome.browser.payments.ui.Completable;
import org.chromium.chrome.browser.payments.ui.LineItem; import org.chromium.chrome.browser.payments.ui.LineItem;
...@@ -70,7 +69,7 @@ import java.util.Set; ...@@ -70,7 +69,7 @@ import java.util.Set;
*/ */
public class PaymentRequestImpl implements PaymentRequest, PaymentRequestUI.Client, public class PaymentRequestImpl implements PaymentRequest, PaymentRequestUI.Client,
PaymentApp.InstrumentsCallback, PaymentInstrument.InstrumentDetailsCallback, PaymentApp.InstrumentsCallback, PaymentInstrument.InstrumentDetailsCallback,
NormalizedAddressRequestDelegate { PaymentResponseHelper.PaymentResponseRequesterDelegate {
/** /**
* Observer to be notified when PaymentRequest UI has been dismissed. * Observer to be notified when PaymentRequest UI has been dismissed.
*/ */
...@@ -193,8 +192,8 @@ public class PaymentRequestImpl implements PaymentRequest, PaymentRequestUI.Clie ...@@ -193,8 +192,8 @@ public class PaymentRequestImpl implements PaymentRequest, PaymentRequestUI.Clie
/** True if show() was called. */ /** True if show() was called. */
private boolean mIsShowing; private boolean mIsShowing;
private boolean mIsWaitingForNormalization; /** The helper to create and fill the response to send to the merchant. */
private PaymentResponse mPendingPaymentResponse; private PaymentResponseHelper mPaymentResponseHelper;
/** /**
* Builds the PaymentRequest service implementation. * Builds the PaymentRequest service implementation.
...@@ -887,12 +886,24 @@ public class PaymentRequestImpl implements PaymentRequest, PaymentRequestUI.Clie ...@@ -887,12 +886,24 @@ public class PaymentRequestImpl implements PaymentRequest, PaymentRequestUI.Clie
}); });
} }
@Override
public void loadingInstrumentDetails() {
mUI.showProcessingMessage();
mPaymentResponseHelper.onInstrumentsDetailsLoading();
}
@Override @Override
public boolean onPayClicked(PaymentOption selectedShippingAddress, public boolean onPayClicked(PaymentOption selectedShippingAddress,
PaymentOption selectedShippingOption, PaymentOption selectedPaymentMethod) { PaymentOption selectedShippingOption, PaymentOption selectedPaymentMethod) {
assert selectedPaymentMethod instanceof PaymentInstrument; assert selectedPaymentMethod instanceof PaymentInstrument;
PaymentInstrument instrument = (PaymentInstrument) selectedPaymentMethod; PaymentInstrument instrument = (PaymentInstrument) selectedPaymentMethod;
mPaymentAppRunning = true; mPaymentAppRunning = true;
PaymentOption selectedContact =
mContactSection != null ? mContactSection.getSelectedItem() : null;
mPaymentResponseHelper = new PaymentResponseHelper(
selectedShippingAddress, selectedShippingOption, selectedContact, this);
instrument.getInstrumentDetails(mMerchantName, mOrigin, mRawTotal, mRawLineItems, instrument.getInstrumentDetails(mMerchantName, mOrigin, mRawTotal, mRawLineItems,
mMethodData.get(instrument.getInstrumentMethodName()), this); mMethodData.get(instrument.getInstrumentMethodName()), this);
recordSuccessFunnelHistograms("PayClicked"); recordSuccessFunnelHistograms("PayClicked");
...@@ -991,6 +1002,21 @@ public class PaymentRequestImpl implements PaymentRequest, PaymentRequestUI.Clie ...@@ -991,6 +1002,21 @@ public class PaymentRequestImpl implements PaymentRequest, PaymentRequestUI.Clie
if (disconnectIfNoPaymentMethodsSupported()) return; if (disconnectIfNoPaymentMethodsSupported()) return;
// Load the validation rules for each unique region code in the credit card billing
// addresses.
Set<String> uniqueCountryCodes = new HashSet<>();
for (int i = 0; i < mPendingAutofillInstruments.size(); ++i) {
assert mPendingAutofillInstruments.get(i) instanceof AutofillPaymentInstrument;
String countryCode = AutofillAddress.getCountryCode((
(AutofillPaymentInstrument) mPendingAutofillInstruments.get(
i)).getBillingAddress());
if (!uniqueCountryCodes.contains(countryCode)) {
uniqueCountryCodes.add(countryCode);
PersonalDataManager.getInstance().loadRulesForRegion(countryCode);
}
}
// List order: // List order:
// > Non-autofill instruments. // > Non-autofill instruments.
// > Complete autofill instruments. // > Complete autofill instruments.
...@@ -1080,29 +1106,7 @@ public class PaymentRequestImpl implements PaymentRequest, PaymentRequestUI.Clie ...@@ -1080,29 +1106,7 @@ public class PaymentRequestImpl implements PaymentRequest, PaymentRequestUI.Clie
*/ */
@Override @Override
public void onInstrumentDetailsReady(String methodName, String stringifiedDetails) { public void onInstrumentDetailsReady(String methodName, String stringifiedDetails) {
if (mClient == null) return; if (mClient == null || mPaymentResponseHelper == null) return;
PaymentResponse response = new PaymentResponse();
response.methodName = methodName;
response.stringifiedDetails = stringifiedDetails;
if (mContactSection != null) {
PaymentOption selectedContact = mContactSection.getSelectedItem();
if (selectedContact != null) {
// Contacts are created in show(). These should all be instances of AutofillContact.
assert selectedContact instanceof AutofillContact;
response.payerName = ((AutofillContact) selectedContact).getPayerName();
response.payerPhone = ((AutofillContact) selectedContact).getPayerPhone();
response.payerEmail = ((AutofillContact) selectedContact).getPayerEmail();
}
}
if (mUiShippingOptions != null) {
PaymentOption selectedShippingOption = mUiShippingOptions.getSelectedItem();
if (selectedShippingOption != null && selectedShippingOption.getIdentifier() != null) {
response.shippingOption = selectedShippingOption.getIdentifier();
}
}
// Record the payment method used to complete the transaction. If the payment method was an // Record the payment method used to complete the transaction. If the payment method was an
// Autofill credit card with an identifier, record its use. // Autofill credit card with an identifier, record its use.
...@@ -1122,84 +1126,16 @@ public class PaymentRequestImpl implements PaymentRequest, PaymentRequestUI.Clie ...@@ -1122,84 +1126,16 @@ public class PaymentRequestImpl implements PaymentRequest, PaymentRequestUI.Clie
PaymentRequestMetrics.SELECTED_METHOD_OTHER_PAYMENT_APP); PaymentRequestMetrics.SELECTED_METHOD_OTHER_PAYMENT_APP);
} }
mUI.showProcessingMessage();
if (mShippingAddressesSection != null) {
PaymentOption selectedShippingAddress = mShippingAddressesSection.getSelectedItem();
if (selectedShippingAddress != null) {
// Shipping addresses are created in show(). These should all be instances of
// AutofillAddress.
assert selectedShippingAddress instanceof AutofillAddress;
AutofillAddress selectedAutofillAddress = (AutofillAddress) selectedShippingAddress;
// Addresses to be sent to the merchant should always be complete.
assert selectedAutofillAddress.isComplete();
// Record the use of the profile.
PersonalDataManager.getInstance().recordAndLogProfileUse(
selectedAutofillAddress.getProfile().getGUID());
response.shippingAddress = selectedAutofillAddress.toPaymentAddress();
// Create the normalization task.
mPendingPaymentResponse = response;
mIsWaitingForNormalization = true;
boolean willNormalizeAsync = PersonalDataManager.getInstance().normalizeAddress(
selectedAutofillAddress.getProfile().getGUID(),
AutofillAddress.getCountryCode(selectedAutofillAddress.getProfile()), this);
if (willNormalizeAsync) {
// If the normalization was not done synchronously, start a timer to cancel the
// asynchronous normalization if it takes too long.
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
onAddressNormalized(null);
}
}, PersonalDataManager.getInstance().getNormalizationTimeoutMS());
}
// The payment response will be sent to the merchant in onAddressNormalized instead.
return;
}
}
mClient.onPaymentResponse(response);
recordSuccessFunnelHistograms("ReceivedInstrumentDetails"); recordSuccessFunnelHistograms("ReceivedInstrumentDetails");
mPaymentResponseHelper.onInstrumentDetailsReceived(methodName, stringifiedDetails);
} }
/**
* Callback method called either when the address has finished normalizing or when the timeout
* triggers. Replaces the address in the response with the normalized version if present and
* sends the response to the merchant.
*
* @param profile The profile with the address normalized or a null profile if the timeout
* triggered first.
*/
@Override @Override
public void onAddressNormalized(AutofillProfile profile) { public void onPaymentResponseReady(PaymentResponse response) {
// Check if the other task finished first. mClient.onPaymentResponse(response);
if (!mIsWaitingForNormalization) return; mPaymentResponseHelper = null;
mIsWaitingForNormalization = false; PersonalDataManager.getInstance().cancelPendingAddressNormalizations();
// Check if the response was already sent to the merchant.
if (mClient == null || mPendingPaymentResponse == null) return;
if (profile != null && !TextUtils.isEmpty(profile.getGUID())) {
// The normalization finished first: use the normalized address.
mPendingPaymentResponse.shippingAddress =
new AutofillAddress(profile, true /* isComplete */).toPaymentAddress();
} else {
// The timeout triggered first: cancel the normalization task.
PersonalDataManager.getInstance().cancelPendingAddressNormalization();
}
// Send the payment response to the merchant.
mClient.onPaymentResponse(mPendingPaymentResponse);
mPendingPaymentResponse = null;
recordSuccessFunnelHistograms("ReceivedInstrumentDetails");
} }
/** /**
......
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.payments;
import android.os.Handler;
import org.chromium.chrome.browser.autofill.PersonalDataManager;
import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
import org.chromium.chrome.browser.autofill.PersonalDataManager.NormalizedAddressRequestDelegate;
import org.chromium.chrome.browser.payments.ui.PaymentOption;
import org.chromium.payments.mojom.PaymentResponse;
/**
* The helper class to create and prepare a PaymentResponse.
*/
public class PaymentResponseHelper implements NormalizedAddressRequestDelegate {
/**
* Observer to be notified when the payment response is completed.
*/
public interface PaymentResponseRequesterDelegate {
/*
* Called when the payment response is ready to be sent to the merchant.
*
* @param response The payment response to send to the merchant.
*/
void onPaymentResponseReady(PaymentResponse response);
}
private PaymentResponse mPaymentResponse;
private PaymentResponseRequesterDelegate mDelegate;
private boolean mIsWaitingForShippingNormalization;
private boolean mIsWaitingForPaymentsDetails = true;
/**
* Builds a helper to contruct and fill a PaymentResponse.
*
* @param selectedShippingAddress The shipping address picked by the user.
* @param selectedShippingOption The shipping option picked by the user.
* @param selectedContact The contact info picked by the user.
* @param delegate The object that will recieve the completed PaymentResponse.
*/
public PaymentResponseHelper(PaymentOption selectedShippingAddress,
PaymentOption selectedShippingOption, PaymentOption selectedContact,
PaymentResponseRequesterDelegate delegate) {
mPaymentResponse = new PaymentResponse();
mDelegate = delegate;
// Set up the contact section of the response.
if (selectedContact != null) {
// Contacts are created in PaymentRequestImpl.init(). These should all be instances of
// AutofillContact.
assert selectedContact instanceof AutofillContact;
mPaymentResponse.payerName = ((AutofillContact) selectedContact).getPayerName();
mPaymentResponse.payerPhone = ((AutofillContact) selectedContact).getPayerPhone();
mPaymentResponse.payerEmail = ((AutofillContact) selectedContact).getPayerEmail();
}
// Set up the shipping section of the response.
if (selectedShippingOption != null && selectedShippingOption.getIdentifier() != null) {
mPaymentResponse.shippingOption = selectedShippingOption.getIdentifier();
}
// Set up the shipping address section of the response.
if (selectedShippingAddress != null) {
// Shipping addresses are created in PaymentRequestImpl.init(). These should all be
// instances of AutofillAddress.
assert selectedShippingAddress instanceof AutofillAddress;
AutofillAddress selectedAutofillAddress = (AutofillAddress) selectedShippingAddress;
// Addresses to be sent to the merchant should always be complete.
assert selectedAutofillAddress.isComplete();
// Record the use of the profile.
PersonalDataManager.getInstance().recordAndLogProfileUse(
selectedAutofillAddress.getProfile().getGUID());
mPaymentResponse.shippingAddress = selectedAutofillAddress.toPaymentAddress();
// The shipping address needs to be normalized before sending the response to the
// merchant.
mIsWaitingForShippingNormalization = true;
PersonalDataManager.getInstance().normalizeAddress(
selectedAutofillAddress.getProfile().getGUID(),
AutofillAddress.getCountryCode(selectedAutofillAddress.getProfile()), this);
}
}
/**
* Called when the intrument details have started loading. Starts a timeout to stop the shipping
* address normalization if it takes too long.
*/
public void onInstrumentsDetailsLoading() {
if (mIsWaitingForShippingNormalization) {
// If the normalization is not completed yet, start a timer to cancel it if it takes too
// long.
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
onAddressNormalized(null);
}
}, PersonalDataManager.getInstance().getNormalizationTimeoutMS());
}
}
/**
* Called after the payment instrument's details were received.
*
* @param methodName The method name of the payment instrument.
* @param stringifiedDetails A string containing all the details of the payment instrument's
* details.
*/
public void onInstrumentDetailsReceived(String methodName, String stringifiedDetails) {
mPaymentResponse.methodName = methodName;
mPaymentResponse.stringifiedDetails = stringifiedDetails;
mIsWaitingForPaymentsDetails = false;
// Wait for the shipping address normalization before sending the response.
if (!mIsWaitingForShippingNormalization) mDelegate.onPaymentResponseReady(mPaymentResponse);
}
@Override
public void onAddressNormalized(AutofillProfile profile) {
// Check if a normalization is still required.
if (!mIsWaitingForShippingNormalization) return;
mIsWaitingForShippingNormalization = false;
if (profile != null) {
// The normalization finished first: use the normalized address.
mPaymentResponse.shippingAddress =
new AutofillAddress(profile, true /* isComplete */).toPaymentAddress();
}
// Wait for the payment details before sending the response.
if (!mIsWaitingForPaymentsDetails) mDelegate.onPaymentResponseReady(mPaymentResponse);
}
}
...@@ -674,6 +674,7 @@ chrome_java_sources = [ ...@@ -674,6 +674,7 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java", "java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java",
"java/src/org/chromium/chrome/browser/payments/PaymentRequestJourneyLogger.java", "java/src/org/chromium/chrome/browser/payments/PaymentRequestJourneyLogger.java",
"java/src/org/chromium/chrome/browser/payments/PaymentRequestMetrics.java", "java/src/org/chromium/chrome/browser/payments/PaymentRequestMetrics.java",
"java/src/org/chromium/chrome/browser/payments/PaymentResponseHelper.java",
"java/src/org/chromium/chrome/browser/payments/ui/Completable.java", "java/src/org/chromium/chrome/browser/payments/ui/Completable.java",
"java/src/org/chromium/chrome/browser/payments/ui/EditorDialogToolbar.java", "java/src/org/chromium/chrome/browser/payments/ui/EditorDialogToolbar.java",
"java/src/org/chromium/chrome/browser/payments/ui/EditorDropdownField.java", "java/src/org/chromium/chrome/browser/payments/ui/EditorDropdownField.java",
......
...@@ -43,7 +43,7 @@ public class PaymentRequestUseStatsTest extends PaymentRequestTestBase { ...@@ -43,7 +43,7 @@ public class PaymentRequestUseStatsTest extends PaymentRequestTestBase {
mBillingAddressId, "" /* serverId */)); mBillingAddressId, "" /* serverId */));
// Set specific use stats for the profile and credit card. // Set specific use stats for the profile and credit card.
mHelper.setProfileUseStatsForTesting(mBillingAddressId, 20, 5000); mHelper.setProfileUseStatsForTesting(mBillingAddressId, 20, 5000);
mHelper.setCreditCardUseStatsForTesting(mCreditCardId, 10, 5000); mHelper.setCreditCardUseStatsForTesting(mCreditCardId, 1, 5000);
} }
/** Expect that using a profile and credit card to pay updates their usage stats. */ /** Expect that using a profile and credit card to pay updates their usage stats. */
...@@ -68,7 +68,7 @@ public class PaymentRequestUseStatsTest extends PaymentRequestTestBase { ...@@ -68,7 +68,7 @@ public class PaymentRequestUseStatsTest extends PaymentRequestTestBase {
assertEquals(21, mHelper.getProfileUseCountForTesting(mBillingAddressId)); assertEquals(21, mHelper.getProfileUseCountForTesting(mBillingAddressId));
assertTrue(timeBeforeRecord <= mHelper.getProfileUseDateForTesting(mBillingAddressId)); assertTrue(timeBeforeRecord <= mHelper.getProfileUseDateForTesting(mBillingAddressId));
assertTrue(timeAfterRecord >= mHelper.getProfileUseDateForTesting(mBillingAddressId)); assertTrue(timeAfterRecord >= mHelper.getProfileUseDateForTesting(mBillingAddressId));
assertEquals(11, mHelper.getCreditCardUseCountForTesting(mCreditCardId)); assertEquals(2, mHelper.getCreditCardUseCountForTesting(mCreditCardId));
assertTrue(timeBeforeRecord <= mHelper.getCreditCardUseDateForTesting(mCreditCardId)); assertTrue(timeBeforeRecord <= mHelper.getCreditCardUseDateForTesting(mCreditCardId));
assertTrue(timeAfterRecord >= mHelper.getCreditCardUseDateForTesting(mCreditCardId)); assertTrue(timeAfterRecord >= mHelper.getCreditCardUseDateForTesting(mCreditCardId));
} }
......
...@@ -266,7 +266,6 @@ class FullCardRequester : public payments::FullCardRequest::Delegate, ...@@ -266,7 +266,6 @@ class FullCardRequester : public payments::FullCardRequest::Delegate,
DISALLOW_COPY_AND_ASSIGN(FullCardRequester); DISALLOW_COPY_AND_ASSIGN(FullCardRequester);
}; };
// Self-deleting requester of address normalization.
class AddressNormalizationRequester class AddressNormalizationRequester
: public PersonalDataManagerAndroid::Delegate, : public PersonalDataManagerAndroid::Delegate,
public base::SupportsWeakPtr<AddressNormalizationRequester> { public base::SupportsWeakPtr<AddressNormalizationRequester> {
...@@ -285,7 +284,7 @@ class AddressNormalizationRequester ...@@ -285,7 +284,7 @@ class AddressNormalizationRequester
} }
private: private:
virtual ~AddressNormalizationRequester() {} ~AddressNormalizationRequester() override {}
void OnRulesSuccessfullyLoaded() override { void OnRulesSuccessfullyLoaded() override {
if (personal_data_manager_android_) { if (personal_data_manager_android_) {
...@@ -294,8 +293,6 @@ class AddressNormalizationRequester ...@@ -294,8 +293,6 @@ class AddressNormalizationRequester
env, jdelegate_, personal_data_manager_android_->NormalizeAddress( env, jdelegate_, personal_data_manager_android_->NormalizeAddress(
guid_, region_code_, env)); guid_, region_code_, env));
} }
delete this;
} }
ScopedJavaGlobalRef<jobject> jdelegate_; ScopedJavaGlobalRef<jobject> jdelegate_;
...@@ -580,6 +577,7 @@ void PersonalDataManagerAndroid::SetProfileUseStatsForTesting( ...@@ -580,6 +577,7 @@ void PersonalDataManagerAndroid::SetProfileUseStatsForTesting(
ConvertJavaStringToUTF8(env, jguid)); ConvertJavaStringToUTF8(env, jguid));
profile->set_use_count(static_cast<size_t>(count)); profile->set_use_count(static_cast<size_t>(count));
profile->set_use_date(base::Time::FromTimeT(date)); profile->set_use_date(base::Time::FromTimeT(date));
personal_data_manager_->NotifyPersonalDataChangedForTest(); personal_data_manager_->NotifyPersonalDataChangedForTest();
} }
...@@ -623,6 +621,7 @@ void PersonalDataManagerAndroid::SetCreditCardUseStatsForTesting( ...@@ -623,6 +621,7 @@ void PersonalDataManagerAndroid::SetCreditCardUseStatsForTesting(
ConvertJavaStringToUTF8(env, jguid)); ConvertJavaStringToUTF8(env, jguid));
card->set_use_count(static_cast<size_t>(count)); card->set_use_count(static_cast<size_t>(count));
card->set_use_date(base::Time::FromTimeT(date)); card->set_use_date(base::Time::FromTimeT(date));
personal_data_manager_->NotifyPersonalDataChangedForTest(); personal_data_manager_->NotifyPersonalDataChangedForTest();
} }
...@@ -662,11 +661,10 @@ void PersonalDataManagerAndroid::OnAddressValidationRulesLoaded( ...@@ -662,11 +661,10 @@ void PersonalDataManagerAndroid::OnAddressValidationRulesLoaded(
const std::string& region_code, const std::string& region_code,
bool success) { bool success) {
// Check if an address normalization is pending. // Check if an address normalization is pending.
std::map<std::string, Delegate*>::iterator it = auto it = pending_normalization_.find(region_code);
pending_normalization_.find(region_code);
if (it != pending_normalization_.end()) { if (it != pending_normalization_.end()) {
// The Delegate will self delete after normalizing. for (size_t i = 0; i < it->second.size(); ++i)
it->second->OnRulesSuccessfullyLoaded(); it->second[i]->OnRulesSuccessfullyLoaded();
pending_normalization_.erase(it); pending_normalization_.erase(it);
} }
} }
...@@ -680,8 +678,8 @@ jboolean PersonalDataManagerAndroid::StartAddressNormalization( ...@@ -680,8 +678,8 @@ jboolean PersonalDataManagerAndroid::StartAddressNormalization(
const std::string region_code = ConvertJavaStringToUTF8(env, jregion_code); const std::string region_code = ConvertJavaStringToUTF8(env, jregion_code);
const std::string guid = ConvertJavaStringToUTF8(env, jguid); const std::string guid = ConvertJavaStringToUTF8(env, jguid);
Delegate* requester = new AddressNormalizationRequester( std::unique_ptr<Delegate> requester(new AddressNormalizationRequester(
env, jdelegate, region_code, guid, AsWeakPtr()); env, jdelegate, region_code, guid, AsWeakPtr()));
// Check if the rules are already loaded. // Check if the rules are already loaded.
if (AreRulesLoadedForRegion(region_code)) { if (AreRulesLoadedForRegion(region_code)) {
...@@ -690,8 +688,17 @@ jboolean PersonalDataManagerAndroid::StartAddressNormalization( ...@@ -690,8 +688,17 @@ jboolean PersonalDataManagerAndroid::StartAddressNormalization(
} else { } else {
// Setup the variables so the profile gets normalized when the rules have // Setup the variables so the profile gets normalized when the rules have
// finished loading. // finished loading.
pending_normalization_.insert( auto it = pending_normalization_.find(region_code);
std::pair<std::string, Delegate*>(region_code, requester)); if (it == pending_normalization_.end()) {
// If no entry exists yet, create the entry and assign it to |it|.
it = pending_normalization_
.insert(std::make_pair(region_code,
std::vector<std::unique_ptr<Delegate>>()))
.first;
}
it->second.push_back(std::move(requester));
return true; return true;
} }
} }
...@@ -723,7 +730,7 @@ ScopedJavaLocalRef<jobject> PersonalDataManagerAndroid::NormalizeAddress( ...@@ -723,7 +730,7 @@ ScopedJavaLocalRef<jobject> PersonalDataManagerAndroid::NormalizeAddress(
return CreateJavaProfileFromNative(env, *profile); return CreateJavaProfileFromNative(env, *profile);
} }
void PersonalDataManagerAndroid::CancelPendingAddressNormalization( void PersonalDataManagerAndroid::CancelPendingAddressNormalizations(
JNIEnv* env, JNIEnv* env,
const base::android::JavaParamRef<jobject>& unused_obj) { const base::android::JavaParamRef<jobject>& unused_obj) {
pending_normalization_.clear(); pending_normalization_.clear();
......
...@@ -28,6 +28,7 @@ class PersonalDataManagerAndroid ...@@ -28,6 +28,7 @@ class PersonalDataManagerAndroid
class Delegate { class Delegate {
public: public:
virtual void OnRulesSuccessfullyLoaded() = 0; virtual void OnRulesSuccessfullyLoaded() = 0;
virtual ~Delegate() {}
}; };
PersonalDataManagerAndroid(JNIEnv* env, jobject obj); PersonalDataManagerAndroid(JNIEnv* env, jobject obj);
...@@ -298,7 +299,7 @@ class PersonalDataManagerAndroid ...@@ -298,7 +299,7 @@ class PersonalDataManagerAndroid
JNIEnv* env); JNIEnv* env);
// Cancels the pending address normalization task. // Cancels the pending address normalization task.
void CancelPendingAddressNormalization( void CancelPendingAddressNormalizations(
JNIEnv* env, JNIEnv* env,
const base::android::JavaParamRef<jobject>& unused_obj); const base::android::JavaParamRef<jobject>& unused_obj);
...@@ -340,8 +341,9 @@ class PersonalDataManagerAndroid ...@@ -340,8 +341,9 @@ class PersonalDataManagerAndroid
// The address validator used to normalize addresses. // The address validator used to normalize addresses.
AddressValidator address_validator_; AddressValidator address_validator_;
// Map associating a region code to a pending normalization. // Map associating a region code to pending normalizations.
std::map<std::string, Delegate*> pending_normalization_; std::map<std::string, std::vector<std::unique_ptr<Delegate>>>
pending_normalization_;
DISALLOW_COPY_AND_ASSIGN(PersonalDataManagerAndroid); DISALLOW_COPY_AND_ASSIGN(PersonalDataManagerAndroid);
}; };
......
...@@ -68,6 +68,7 @@ bool FullCardRequest::IsGettingFullCard() const { ...@@ -68,6 +68,7 @@ bool FullCardRequest::IsGettingFullCard() const {
return !!request_; return !!request_;
} }
// TODO(crbug.com/656981): Update the credit card expiration on file.
void FullCardRequest::OnUnmaskResponse(const UnmaskResponse& response) { void FullCardRequest::OnUnmaskResponse(const UnmaskResponse& response) {
if (!response.exp_month.empty()) if (!response.exp_month.empty())
request_->card.SetRawInfo(CREDIT_CARD_EXP_MONTH, response.exp_month); request_->card.SetRawInfo(CREDIT_CARD_EXP_MONTH, response.exp_month);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment