summaryrefslogtreecommitdiff
path: root/chromium/components/autofill/core/browser/credit_card_save_manager.cc
diff options
context:
space:
mode:
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.cc209
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