| Index: ios/chrome/browser/ui/payments/payment_request_manager.mm
|
| diff --git a/ios/chrome/browser/ui/payments/payment_request_manager.mm b/ios/chrome/browser/ui/payments/payment_request_manager.mm
|
| index 79398b3ea49472c772110a1314562b2a0cb93075..906134c7144abd8cc0f5c9c426550392879e07d8 100644
|
| --- a/ios/chrome/browser/ui/payments/payment_request_manager.mm
|
| +++ b/ios/chrome/browser/ui/payments/payment_request_manager.mm
|
| @@ -13,15 +13,19 @@
|
| #include "base/strings/sys_string_conversions.h"
|
| #include "base/strings/utf_string_conversions.h"
|
| #import "base/values.h"
|
| +#include "components/autofill/core/browser/autofill_country.h"
|
| #include "components/autofill/core/browser/autofill_data_util.h"
|
| #include "components/autofill/core/browser/autofill_manager.h"
|
| #include "components/autofill/core/browser/credit_card.h"
|
| #include "components/autofill/core/browser/personal_data_manager.h"
|
| #include "components/autofill/ios/browser/autofill_driver_ios.h"
|
| +#include "components/payments/core/address_normalization_manager.h"
|
| +#include "components/payments/core/address_normalizer_impl.h"
|
| #include "components/payments/core/payment_address.h"
|
| #include "components/payments/core/payment_request_data_util.h"
|
| #include "ios/chrome/browser/application_context.h"
|
| #include "ios/chrome/browser/autofill/personal_data_manager_factory.h"
|
| +#include "ios/chrome/browser/autofill/validation_rules_storage_factory.h"
|
| #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
|
| #include "ios/chrome/browser/payments/payment_request.h"
|
| #include "ios/chrome/browser/procedural_block_types.h"
|
| @@ -41,6 +45,8 @@
|
| #include "ios/web/public/web_state/url_verification_constants.h"
|
| #include "ios/web/public/web_state/web_state.h"
|
| #import "ios/web/public/web_state/web_state_observer_bridge.h"
|
| +#include "third_party/libaddressinput/chromium/chrome_metadata_source.h"
|
| +#include "third_party/libaddressinput/chromium/chrome_storage_impl.h"
|
|
|
| #if !defined(__has_feature) || !__has_feature(objc_arc)
|
| #error "This file requires ARC support."
|
| @@ -61,6 +67,14 @@ const NSTimeInterval kTimeoutInterval = 60.0;
|
| NSString* kAbortMessage = @"The payment request was aborted.";
|
| NSString* kCancelMessage = @"The payment request was canceled.";
|
|
|
| +struct PendingPaymentResponse {
|
| + autofill::CreditCard creditCard;
|
| + base::string16 verificationCode;
|
| + autofill::AutofillProfile billingAddress;
|
| + autofill::AutofillProfile shippingAddress;
|
| + autofill::AutofillProfile contactAddress;
|
| +};
|
| +
|
| } // namespace
|
|
|
| @interface PaymentRequestManager ()<CRWWebStateObserver,
|
| @@ -104,6 +118,15 @@ NSString* kCancelMessage = @"The payment request was canceled.";
|
| // Timer used to cancel the Payment Request flow and close the UI if the
|
| // page does not settle the pending update promise in a timely fashion.
|
| NSTimer* _updateEventTimeoutTimer;
|
| +
|
| + // AddressNormalizationManager used to normalize the various addresses (e.g.
|
| + // shipping, contact, billing).
|
| + std::unique_ptr<payments::AddressNormalizationManager>
|
| + _addressNormalizationManager;
|
| +
|
| + // Storage for data to return in the payment response, until we're ready to
|
| + // send an actual PaymentResponse.
|
| + PendingPaymentResponse _pendingPaymentResponse;
|
| }
|
|
|
| // Object that manages JavaScript injection into the web view.
|
| @@ -135,7 +158,7 @@ NSString* kCancelMessage = @"The payment request was canceled.";
|
|
|
| // Called by |_updateEventTimeoutTimer|, displays an error message. Upon
|
| // dismissal of the error message, cancels the Payment Request as if it was
|
| -// performend by the user.
|
| +// performed by the user.
|
| - (BOOL)displayErrorThenCancelRequest;
|
|
|
| // Called by |_paymentResponseTimeoutTimer|, invokes handleResponseComplete:
|
| @@ -169,6 +192,10 @@ NSString* kCancelMessage = @"The payment request was canceled.";
|
| // was rejected.
|
| - (void)setUpdateEventTimeoutTimer;
|
|
|
| +// Called when the relevant addresses from a Payment Request have been
|
| +// normalized. Resolves the request promise with a PaymentResponse.
|
| +- (void)paymentRequestAddressNormalizationDidComplete;
|
| +
|
| @end
|
|
|
| @implementation PaymentRequestManager
|
| @@ -322,6 +349,43 @@ NSString* kCancelMessage = @"The payment request was canceled.";
|
| return NO;
|
| }
|
|
|
| +- (void)startAddressNormalizer {
|
| + autofill::PersonalDataManager* personalDataManager =
|
| + _paymentRequest->GetPersonalDataManager();
|
| +
|
| + std::unique_ptr<i18n::addressinput::Source> addressNormalizerSource =
|
| + base::MakeUnique<autofill::ChromeMetadataSource>(
|
| + I18N_ADDRESS_VALIDATION_DATA_URL,
|
| + personalDataManager->GetURLRequestContextGetter());
|
| +
|
| + std::unique_ptr<i18n::addressinput::Storage> addressNormalizerStorage =
|
| + autofill::ValidationRulesStorageFactory::CreateStorage();
|
| +
|
| + std::unique_ptr<payments::AddressNormalizer> addressNormalizer =
|
| + base::MakeUnique<payments::AddressNormalizerImpl>(
|
| + std::move(addressNormalizerSource),
|
| + std::move(addressNormalizerStorage));
|
| +
|
| + // Kickoff the process of loading the rules (which is asynchronous) for each
|
| + // profile's country, to get faster address normalization later.
|
| + for (const autofill::AutofillProfile* profile :
|
| + personalDataManager->GetProfilesToSuggest()) {
|
| + std::string countryCode =
|
| + base::UTF16ToUTF8(profile->GetRawInfo(autofill::ADDRESS_HOME_COUNTRY));
|
| + if (autofill::data_util::IsValidCountryCode(countryCode)) {
|
| + addressNormalizer->LoadRulesForRegion(countryCode);
|
| + }
|
| + }
|
| +
|
| + const std::string default_country_code =
|
| + autofill::AutofillCountry::CountryCodeForLocale(
|
| + GetApplicationContext()->GetApplicationLocale());
|
| +
|
| + _addressNormalizationManager =
|
| + base::MakeUnique<payments::AddressNormalizationManager>(
|
| + std::move(addressNormalizer), default_country_code);
|
| +}
|
| +
|
| // Ensures that |_paymentRequest| is set to the correct value for |message|.
|
| // Returns YES if |_paymentRequest| was already set to the right value, or if it
|
| // was updated to match |message|.
|
| @@ -359,6 +423,8 @@ NSString* kCancelMessage = @"The payment request was canceled.";
|
| return NO;
|
| }
|
|
|
| + [self startAddressNormalizer];
|
| +
|
| UIImage* pageFavicon = nil;
|
| web::NavigationItem* navigationItem =
|
| [self webState]->GetNavigationManager()->GetVisibleItem();
|
| @@ -566,25 +632,10 @@ NSString* kCancelMessage = @"The payment request was canceled.";
|
| }
|
|
|
| - (void)paymentRequestCoordinator:(PaymentRequestCoordinator*)coordinator
|
| - didCompletePaymentRequest:(PaymentRequest*)paymentRequest
|
| - card:(const autofill::CreditCard&)card
|
| - verificationCode:(const base::string16&)verificationCode {
|
| - web::PaymentResponse paymentResponse;
|
| -
|
| - // If the merchant specified the card network as part of the "basic-card"
|
| - // payment method, return "basic-card" as the method_name. Otherwise, return
|
| - // the name of the network directly.
|
| - std::string issuer_network =
|
| - autofill::data_util::GetPaymentRequestData(card.network())
|
| - .basic_card_issuer_network;
|
| - paymentResponse.method_name =
|
| - paymentRequest->basic_card_specified_networks().find(issuer_network) !=
|
| - paymentRequest->basic_card_specified_networks().end()
|
| - ? base::ASCIIToUTF16("basic-card")
|
| - : base::ASCIIToUTF16(issuer_network);
|
| -
|
| - // Get the billing address
|
| - autofill::AutofillProfile billingAddress;
|
| + didCompletePaymentRequestWithCard:(const autofill::CreditCard&)card
|
| + verificationCode:(const base::string16&)verificationCode {
|
| + _pendingPaymentResponse.creditCard = card;
|
| + _pendingPaymentResponse.verificationCode = verificationCode;
|
|
|
| // TODO(crbug.com/714768): Make sure the billing address is set and valid
|
| // before getting here. Once the bug is addressed, there will be no need to
|
| @@ -593,61 +644,93 @@ NSString* kCancelMessage = @"The payment request was canceled.";
|
| if (!card.billing_address_id().empty()) {
|
| autofill::AutofillProfile* billingAddressPtr =
|
| autofill::PersonalDataManager::GetProfileFromProfilesByGUID(
|
| - card.billing_address_id(), paymentRequest->billing_profiles());
|
| - if (billingAddressPtr)
|
| - billingAddress = *billingAddressPtr;
|
| + card.billing_address_id(), _paymentRequest->billing_profiles());
|
| + if (billingAddressPtr) {
|
| + _pendingPaymentResponse.billingAddress = *billingAddressPtr;
|
| + _addressNormalizationManager->StartNormalizingAddress(
|
| + &_pendingPaymentResponse.billingAddress);
|
| + }
|
| }
|
|
|
| + if (_paymentRequest->request_shipping()) {
|
| + // TODO(crbug.com/602666): User should get here only if they have selected
|
| + // a shipping address.
|
| + DCHECK(_paymentRequest->selected_shipping_profile());
|
| + _pendingPaymentResponse.shippingAddress =
|
| + *_paymentRequest->selected_shipping_profile();
|
| + _addressNormalizationManager->StartNormalizingAddress(
|
| + &_pendingPaymentResponse.shippingAddress);
|
| + }
|
| +
|
| + if (_paymentRequest->request_payer_name() ||
|
| + _paymentRequest->request_payer_email() ||
|
| + _paymentRequest->request_payer_phone()) {
|
| + // TODO(crbug.com/602666): User should get here only if they have selected
|
| + // a contact info.
|
| + DCHECK(_paymentRequest->selected_contact_profile());
|
| + _pendingPaymentResponse.contactAddress =
|
| + *_paymentRequest->selected_contact_profile();
|
| + _addressNormalizationManager->StartNormalizingAddress(
|
| + &_pendingPaymentResponse.contactAddress);
|
| + }
|
| +
|
| + __weak PaymentRequestManager* weakSelf = self;
|
| + _addressNormalizationManager->FinalizeWithCompletionCallback(
|
| + base::BindBlockArc(^() {
|
| + [weakSelf paymentRequestAddressNormalizationDidComplete];
|
| + }));
|
| +}
|
| +
|
| +- (void)paymentRequestAddressNormalizationDidComplete {
|
| + web::PaymentResponse paymentResponse;
|
| +
|
| + // If the merchant specified the card network as part of the "basic-card"
|
| + // payment method, return "basic-card" as the method_name. Otherwise, return
|
| + // the name of the network directly.
|
| + std::string issuer_network = autofill::data_util::GetPaymentRequestData(
|
| + _pendingPaymentResponse.creditCard.network())
|
| + .basic_card_issuer_network;
|
| + paymentResponse.method_name =
|
| + _paymentRequest->basic_card_specified_networks().find(issuer_network) !=
|
| + _paymentRequest->basic_card_specified_networks().end()
|
| + ? base::ASCIIToUTF16("basic-card")
|
| + : base::ASCIIToUTF16(issuer_network);
|
| +
|
| paymentResponse.details =
|
| payments::data_util::GetBasicCardResponseFromAutofillCreditCard(
|
| - card, verificationCode, billingAddress,
|
| + _pendingPaymentResponse.creditCard,
|
| + _pendingPaymentResponse.verificationCode,
|
| + _pendingPaymentResponse.billingAddress,
|
| GetApplicationContext()->GetApplicationLocale());
|
|
|
| - if (paymentRequest->request_shipping()) {
|
| - autofill::AutofillProfile* shippingAddress =
|
| - paymentRequest->selected_shipping_profile();
|
| - // TODO(crbug.com/602666): User should get here only if they have selected
|
| - // a shipping address.
|
| - DCHECK(shippingAddress);
|
| + if (_paymentRequest->request_shipping()) {
|
| paymentResponse.shipping_address =
|
| payments::data_util::GetPaymentAddressFromAutofillProfile(
|
| - *shippingAddress, GetApplicationContext()->GetApplicationLocale());
|
| + _pendingPaymentResponse.shippingAddress,
|
| + GetApplicationContext()->GetApplicationLocale());
|
|
|
| web::PaymentShippingOption* shippingOption =
|
| - paymentRequest->selected_shipping_option();
|
| + _paymentRequest->selected_shipping_option();
|
| DCHECK(shippingOption);
|
| paymentResponse.shipping_option = shippingOption->id;
|
| }
|
|
|
| - if (paymentRequest->request_payer_name()) {
|
| - autofill::AutofillProfile* contactInfo =
|
| - paymentRequest->selected_contact_profile();
|
| - // TODO(crbug.com/602666): User should get here only if they have selected
|
| - // a contact info.
|
| - DCHECK(contactInfo);
|
| - paymentResponse.payer_name =
|
| - contactInfo->GetInfo(autofill::AutofillType(autofill::NAME_FULL),
|
| - GetApplicationContext()->GetApplicationLocale());
|
| + if (_paymentRequest->request_payer_name()) {
|
| + paymentResponse.payer_name = _pendingPaymentResponse.contactAddress.GetInfo(
|
| + autofill::AutofillType(autofill::NAME_FULL),
|
| + GetApplicationContext()->GetApplicationLocale());
|
| }
|
|
|
| - if (paymentRequest->request_payer_email()) {
|
| - autofill::AutofillProfile* contactInfo =
|
| - paymentRequest->selected_contact_profile();
|
| - // TODO(crbug.com/602666): User should get here only if they have selected
|
| - // a contact info.
|
| - DCHECK(contactInfo);
|
| + if (_paymentRequest->request_payer_email()) {
|
| paymentResponse.payer_email =
|
| - contactInfo->GetRawInfo(autofill::EMAIL_ADDRESS);
|
| + _pendingPaymentResponse.contactAddress.GetRawInfo(
|
| + autofill::EMAIL_ADDRESS);
|
| }
|
|
|
| - if (paymentRequest->request_payer_phone()) {
|
| - autofill::AutofillProfile* contactInfo =
|
| - paymentRequest->selected_contact_profile();
|
| - // TODO(crbug.com/602666): User should get here only if they have selected
|
| - // a contact info.
|
| - DCHECK(contactInfo);
|
| + if (_paymentRequest->request_payer_phone()) {
|
| paymentResponse.payer_phone =
|
| - contactInfo->GetRawInfo(autofill::PHONE_HOME_WHOLE_NUMBER);
|
| + _pendingPaymentResponse.contactAddress.GetRawInfo(
|
| + autofill::PHONE_HOME_WHOLE_NUMBER);
|
| }
|
|
|
| [_paymentRequestJsManager
|
|
|