diff options
Diffstat (limited to 'chromium/components/autofill/core/browser/credit_card_save_manager.cc')
-rw-r--r-- | chromium/components/autofill/core/browser/credit_card_save_manager.cc | 209 |
1 files changed, 119 insertions, 90 deletions
diff --git a/chromium/components/autofill/core/browser/credit_card_save_manager.cc b/chromium/components/autofill/core/browser/credit_card_save_manager.cc index 5eac76c7094..d0aba9954e5 100644 --- a/chromium/components/autofill/core/browser/credit_card_save_manager.cc +++ b/chromium/components/autofill/core/browser/credit_card_save_manager.cc @@ -34,6 +34,7 @@ #include "components/autofill/core/browser/personal_data_manager.h" #include "components/autofill/core/browser/validation.h" #include "components/autofill/core/common/autofill_clock.h" +#include "components/autofill/core/common/autofill_features.h" #include "components/autofill/core/common/autofill_util.h" #include "components/prefs/pref_service.h" #include "services/identity/public/cpp/identity_manager.h" @@ -86,11 +87,13 @@ CreditCardSaveManager::CreditCardSaveManager( CreditCardSaveManager::~CreditCardSaveManager() {} void CreditCardSaveManager::OfferCardLocalSave(const CreditCard& card) { + if (card.HasFirstAndLastName()) + AutofillMetrics::LogSaveCardWithFirstAndLastNameOffered(/*is_local=*/true); if (observer_for_testing_) observer_for_testing_->OnOfferLocalSave(); client_->ConfirmSaveCreditCardLocally( card, base::Bind(base::IgnoreResult( - &PersonalDataManager::SaveImportedCreditCard), + &PersonalDataManager::OnAcceptedLocalCreditCardSave), base::Unretained(personal_data_manager_), card)); } @@ -98,25 +101,26 @@ void CreditCardSaveManager::AttemptToOfferCardUploadSave( const FormStructure& submitted_form, const CreditCard& card, const bool uploading_local_card) { + // Abort the uploading if |payments_client_| is nullptr. + if (!payments_client_) + return; + payments_client_->SetSaveDelegate(this); upload_request_ = payments::PaymentsClient::UploadRequestDetails(); upload_request_.card = card; uploading_local_card_ = uploading_local_card; - // Ideally, in order to upload a card, we must have both: - // 1) Card with CVC - // 2) 1+ recently-used or modified addresses that meet the client-side - // validation rules - // We perform all checks before returning or logging in order to know where we - // stand with regards to card upload information. If the "send detected - // values" experiment is disabled and any problems were found, we do not offer - // to save the card. We could fall back to a local save, but we believe that - // sometimes offering upload and sometimes offering local save is a confusing - // user experience. - - // Alternatively, if the "send detected values" experiment is enabled, always - // ping Google Payments regardless and ask if save is allowed. Include what - // data was found as part of the request, and let Payments decide whether - // upload save should be offered. + // In an ideal scenario, when uploading a card, we would have: + // 1) Card number and expiration + // 2) CVC + // 3) 1+ recently-used or modified addresses that meet validation rules (or + // only the address countries if the relevant feature is enabled). + // 4) Cardholder name or names on the address profiles + // At a minimum, only #1 (card number and expiration) is absolutely required + // in order to save a card to Google Payments. We perform all checks before + // returning or logging in order to know where we stand with regards to card + // upload information. Then, we ping Google Payments and ask if upload save + // should be offered with the given amount of information, letting Payments + // make the final offer-to-save decision. found_cvc_field_ = false; found_value_in_cvc_field_ = false; found_cvc_value_in_non_cvc_field_ = false; @@ -151,25 +155,7 @@ void CreditCardSaveManager::AttemptToOfferCardUploadSave( upload_decision_metrics_ |= GetCVCCardUploadDecisionMetric(); } - // If any problems were found across CVC/name/address, - // |upload_decision_metrics_| will be non-zero. If the "send detected values" - // experiment is on, continue anyway and just let Payments know that not - // everything was found, as Payments may still allow the card to be saved. - // If the experiment is off, follow the legacy logic of aborting upload save. - if (upload_decision_metrics_ && - !IsAutofillUpstreamSendDetectedValuesExperimentEnabled()) { - LogCardUploadDecisions(upload_decision_metrics_); - pending_upload_request_origin_ = url::Origin(); - if (observer_for_testing_) - observer_for_testing_->OnDecideToNotRequestUploadSave(); - return; - } - // Add active experiments to the request payload. - if (IsAutofillUpstreamSendDetectedValuesExperimentEnabled()) { - upload_request_.active_experiments.push_back( - kAutofillUpstreamSendDetectedValues.name); - } if (IsAutofillUpstreamSendPanFirstSixExperimentEnabled()) { upload_request_.active_experiments.push_back( kAutofillUpstreamSendPanFirstSix.name); @@ -179,11 +165,22 @@ void CreditCardSaveManager::AttemptToOfferCardUploadSave( kAutofillUpstreamUpdatePromptExplanation.name); } + int detected_values = GetDetectedValues(); + // If the user must provide cardholder name, log it and set + // |should_request_name_from_user_| so the offer-to-save dialog know to ask + // for it. + should_request_name_from_user_ = false; + if (detected_values & DetectedValue::USER_PROVIDED_NAME) { + upload_decision_metrics_ |= + AutofillMetrics::USER_REQUESTED_TO_PROVIDE_CARDHOLDER_NAME; + should_request_name_from_user_ = true; + } + // All required data is available, start the upload process. if (observer_for_testing_) observer_for_testing_->OnDecideToRequestUploadSave(); payments_client_->GetUploadDetails( - upload_request_.profiles, GetDetectedValues(), + upload_request_.profiles, detected_values, base::UTF16ToASCII(CreditCard::StripSeparators(card.number())) .substr(0, 6), upload_request_.active_experiments, app_locale_); @@ -198,9 +195,28 @@ bool CreditCardSaveManager::IsCreditCardUploadEnabled() { client_->GetIdentityManager()->GetPrimaryAccountInfo().email); } +bool CreditCardSaveManager::IsUploadEnabledForNetwork( + const std::string& network) { + if (network == kEloCard && + base::FeatureList::IsEnabled(features::kAutofillUpstreamDisallowElo)) { + return false; + } else if (network == kJCBCard && + base::FeatureList::IsEnabled( + features::kAutofillUpstreamDisallowJcb)) { + return false; + } + return true; +} + void CreditCardSaveManager::OnDidUploadCard( AutofillClient::PaymentsRpcResult result, const std::string& server_id) { + if (result == AutofillClient::SUCCESS && + upload_request_.card.HasFirstAndLastName()) { + AutofillMetrics::LogSaveCardWithFirstAndLastNameComplete( + /*is_local=*/false); + } + // We don't do anything user-visible if the upload attempt fails. If the // upload succeeds and we can store unmasked cards on this OS, we will keep a // copy of the card as a full server card on the device. @@ -228,8 +244,9 @@ void CreditCardSaveManager::OnDidGetUploadDetails( user_did_accept_upload_prompt_ = false; client_->ConfirmSaveCreditCardToCloud( upload_request_.card, std::move(legal_message), - base::Bind(&CreditCardSaveManager::OnUserDidAcceptUpload, - weak_ptr_factory_.GetWeakPtr())); + should_request_name_from_user_, + base::BindOnce(&CreditCardSaveManager::OnUserDidAcceptUpload, + weak_ptr_factory_.GetWeakPtr())); client_->LoadRiskData( base::Bind(&CreditCardSaveManager::OnDidGetUploadRiskData, weak_ptr_factory_.GetWeakPtr())); @@ -237,56 +254,32 @@ void CreditCardSaveManager::OnDidGetUploadDetails( AutofillMetrics::LogUploadOfferedCardOriginMetric( uploading_local_card_ ? AutofillMetrics::OFFERING_UPLOAD_OF_LOCAL_CARD : AutofillMetrics::OFFERING_UPLOAD_OF_NEW_CARD); + if (upload_request_.card.HasFirstAndLastName()) { + AutofillMetrics::LogSaveCardWithFirstAndLastNameOffered( + /*is_local=*/false); + } } else { - // If the upload details request failed, fall back to a local save. The - // reasoning here is as follows: - // - This will sometimes fail intermittently, in which case it might be - // better to not fall back, because sometimes offering upload and sometimes - // offering local save is a poor user experience. - // - However, in some cases, our local configuration limiting the feature to - // countries that Payments is known to support will not match Payments' own - // determination of what country the user is located in. In these cases, - // the upload details request will consistently fail and if we don't fall - // back to a local save then the user will never be offered any kind of - // credit card save. - - // Additional note: If the "send detected values" experiment is enabled, - // only offer to save locally if CVC + name + address were all found, as - // this signifies a legacy decision of "Payments doesn't want this card". - // We can revisit this decision in the future, but the reasoning here is as - // follows: - // - If any of them were not found, surfacing local save would begin to - // create a scenario where different card types or different checkout forms - // could reasonably surface different save dialogs to the user, and that - // would cause unnecessary confusion. - // - We already don't offer to save at all in these cases today, so this - // decision doesn't disable any upload chances, it just enables *less* - // upload chances. + // If the upload details request failed and we *know* we have all possible + // information (card number, expiration, cvc, name, and address), fall back + // to a local save. It indicates that "Payments doesn't want this card" or + // "Payments doesn't currently support this country", in which case the + // upload details request will consistently fail and if we don't fall back + // to a local save, the user will never be offered *any* kind of credit card + // save. (Note that this could intermittently backfire if there's a network + // breakdown or Payments outage, resulting in sometimes showing upload and + // sometimes offering local save, but such cases should be rare.) int detected_values = GetDetectedValues(); bool found_name_and_postal_code_and_cvc = (detected_values & DetectedValue::CARDHOLDER_NAME || detected_values & DetectedValue::ADDRESS_NAME) && detected_values & DetectedValue::POSTAL_CODE && detected_values & DetectedValue::CVC; - if (!IsAutofillUpstreamSendDetectedValuesExperimentEnabled() || - found_name_and_postal_code_and_cvc) { - if (observer_for_testing_) - observer_for_testing_->OnOfferLocalSave(); - client_->ConfirmSaveCreditCardLocally( - upload_request_.card, - base::BindRepeating( - base::IgnoreResult(&PersonalDataManager::SaveImportedCreditCard), - base::Unretained(personal_data_manager_), upload_request_.card)); - } + if (found_name_and_postal_code_and_cvc) + OfferCardLocalSave(upload_request_.card); upload_decision_metrics_ |= AutofillMetrics::UPLOAD_NOT_OFFERED_GET_UPLOAD_DETAILS_FAILED; } - // Assert that we've either detected the CVC or the "send detected values" - // experiment is enabled. - DCHECK(IsAutofillUpstreamSendDetectedValuesExperimentEnabled() || - (found_cvc_field_ && found_value_in_cvc_field_)); - LogCardUploadDecisions(upload_decision_metrics_); pending_upload_request_origin_ = url::Origin(); } @@ -394,17 +387,29 @@ void CreditCardSaveManager::SetProfilesForCreditCardUpload( if (verified_zip.empty() && !candidate_profiles.empty()) upload_decision_metrics_ |= AutofillMetrics::UPLOAD_NOT_OFFERED_NO_ZIP_CODE; - // Only set |upload_request->profiles| if upload is allowed (either all - // required data was found, or "send detected values" experiment is enabled). - if (!upload_decision_metrics_ || - IsAutofillUpstreamSendDetectedValuesExperimentEnabled()) { - upload_request->profiles.assign(candidate_profiles.begin(), - candidate_profiles.end()); - if (!has_modified_profile) - for (const AutofillProfile& profile : candidate_profiles) - UMA_HISTOGRAM_COUNTS_1000( - "Autofill.DaysSincePreviousUseAtSubmission.Profile", - (profile.use_date() - profile.previous_use_date()).InDays()); + // If the relevant feature is enabled, only send the country of the + // recently-used addresses. + if (base::FeatureList::IsEnabled( + features::kAutofillSendOnlyCountryInGetUploadDetails)) { + for (size_t i = 0; i < candidate_profiles.size(); i++) { + AutofillProfile country_only; + country_only.SetInfo( + ADDRESS_HOME_COUNTRY, + candidate_profiles[i].GetInfo(ADDRESS_HOME_COUNTRY, app_locale_), + app_locale_); + candidate_profiles[i] = std::move(country_only); + } + } + + // Set up |upload_request->profiles|. + upload_request->profiles.assign(candidate_profiles.begin(), + candidate_profiles.end()); + if (!has_modified_profile) { + for (const AutofillProfile& profile : candidate_profiles) { + UMA_HISTOGRAM_COUNTS_1000( + "Autofill.DaysSincePreviousUseAtSubmission.Profile", + (profile.use_date() - profile.previous_use_date()).InDays()); + } } } @@ -464,10 +469,34 @@ int CreditCardSaveManager::GetDetectedValues() const { prefs::kAutofillBillingCustomerNumber)) != 0) detected_values |= DetectedValue::HAS_GOOGLE_PAYMENTS_ACCOUNT; + // If one of the following is true, signal that cardholder name will be + // explicitly requested in the offer-to-save bubble: + // 1) Name is conflicting/missing, and the user does NOT have a Google + // Payments account + // 2) The AutofillUpstreamAlwaysRequestCardholderName experiment is enabled + // (should only ever be used by testers, never launched) + if ((!(detected_values & DetectedValue::CARDHOLDER_NAME) && + !(detected_values & DetectedValue::ADDRESS_NAME) && + !(detected_values & DetectedValue::HAS_GOOGLE_PAYMENTS_ACCOUNT) && + IsAutofillUpstreamEditableCardholderNameExperimentEnabled()) || + IsAutofillUpstreamAlwaysRequestCardholderNameExperimentEnabled()) { + detected_values |= DetectedValue::USER_PROVIDED_NAME; + } + return detected_values; } -void CreditCardSaveManager::OnUserDidAcceptUpload() { +void CreditCardSaveManager::OnUserDidAcceptUpload( + const base::string16& cardholder_name) { + // If cardholder name was explicitly requested for the user to enter/confirm, + // replace the name on |upload_request_.card| with the entered name. (Note + // that it is possible a name already existed on the card if conflicting names + // were found, which this intentionally overwrites.) + if (!cardholder_name.empty()) { + DCHECK(should_request_name_from_user_); + upload_request_.card.SetInfo(CREDIT_CARD_NAME_FULL, cardholder_name, + app_locale_); + } user_did_accept_upload_prompt_ = true; // Populating risk data and offering upload occur asynchronously. // If |risk_data| has already been loaded, send the upload card request. @@ -517,8 +546,8 @@ void CreditCardSaveManager::LogCardUploadDecisions( int upload_decision_metrics) { AutofillMetrics::LogCardUploadDecisionMetrics(upload_decision_metrics); AutofillMetrics::LogCardUploadDecisionsUkm( - client_->GetUkmRecorder(), pending_upload_request_origin_.GetURL(), - upload_decision_metrics); + client_->GetUkmRecorder(), client_->GetUkmSourceId(), + pending_upload_request_origin_.GetURL(), upload_decision_metrics); } } // namespace autofill |