blob: e408bda219c48601f29d36483ae4b1f2105d4a9a [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/autofill/core/browser/iban_manager.h"
#include "base/containers/contains.h"
#include "components/autofill/core/browser/autofill_optimization_guide.h"
#include "components/autofill/core/browser/autofill_suggestion_generator.h"
#include "components/autofill/core/browser/browser_autofill_manager.h"
#include "components/autofill/core/browser/metrics/payments/iban_metrics.h"
#include "components/autofill/core/browser/personal_data_manager.h"
#include "components/autofill/core/browser/suggestions_context.h"
#include "components/autofill/core/common/autofill_clock.h"
namespace autofill {
IbanManager::IbanManager(PersonalDataManager* personal_data_manager)
: personal_data_manager_(personal_data_manager) {}
IbanManager::~IbanManager() = default;
bool IbanManager::OnGetSingleFieldSuggestions(
AutofillSuggestionTriggerSource trigger_source,
const FormFieldData& field,
const AutofillClient& client,
base::WeakPtr<SuggestionsHandler> handler,
const SuggestionsContext& context) {
// The field is eligible only if it's focused on an IBAN field.
AutofillField* focused_field = context.focused_field;
bool field_is_eligible =
focused_field && focused_field->Type().GetStorableType() == IBAN_VALUE;
if (!field_is_eligible) {
return false;
}
if (!personal_data_manager_ ||
!personal_data_manager_->IsAutofillPaymentMethodsEnabled()) {
return false;
}
std::vector<Iban*> ibans = personal_data_manager_->GetLocalIbans();
if (ibans.empty()) {
return false;
}
// AutofillOptimizationGuide will not be present on unsupported platforms.
if (auto* autofill_optimization_guide =
client.GetAutofillOptimizationGuide()) {
if (autofill_optimization_guide->ShouldBlockSingleFieldSuggestions(
client.GetLastCommittedPrimaryMainFrameOrigin().GetURL(),
focused_field)) {
autofill_metrics::LogIbanSuggestionBlockListStatusMetric(
autofill_metrics::IbanSuggestionBlockListStatus::kBlocked);
return false;
}
autofill_metrics::LogIbanSuggestionBlockListStatusMetric(
autofill_metrics::IbanSuggestionBlockListStatus::kAllowed);
} else {
autofill_metrics::LogIbanSuggestionBlockListStatusMetric(
autofill_metrics::IbanSuggestionBlockListStatus::
kBlocklistIsNotAvailable);
}
// Rank the IBANs by ranking score (see AutoFillDataModel for details).
base::ranges::sort(ibans, [comparison_time = AutofillClock::Now()](
const Iban* iban0, const Iban* iban1) {
return iban0->HasGreaterRankingThan(iban1, comparison_time);
});
SendIbanSuggestions(ibans, QueryHandler(field.global_id(), trigger_source,
field.value, handler));
return true;
}
base::WeakPtr<IbanManager> IbanManager::GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
void IbanManager::UmaRecorder::OnIbanSuggestionsShown(
FieldGlobalId field_global_id) {
// Log metrics related to the IBAN-related suggestions in the popup.
autofill_metrics::LogIndividualIbanSuggestionsEvent(
autofill_metrics::IbanSuggestionsEvent::kIbanSuggestionsShown);
if (most_recent_suggestions_shown_field_global_id_ != field_global_id) {
autofill_metrics::LogIndividualIbanSuggestionsEvent(
autofill_metrics::IbanSuggestionsEvent::kIbanSuggestionsShownOnce);
}
most_recent_suggestions_shown_field_global_id_ = field_global_id;
}
void IbanManager::UmaRecorder::OnIbanSuggestionSelected() {
// We log every time the IBAN suggestion is selected.
autofill_metrics::LogIndividualIbanSuggestionsEvent(
autofill_metrics::IbanSuggestionsEvent::kIbanSuggestionSelected);
if (most_recent_suggestion_selected_field_global_id_ !=
most_recent_suggestions_shown_field_global_id_) {
autofill_metrics::LogIndividualIbanSuggestionsEvent(
autofill_metrics::IbanSuggestionsEvent::kIbanSuggestionSelectedOnce);
}
most_recent_suggestion_selected_field_global_id_ =
most_recent_suggestions_shown_field_global_id_;
}
void IbanManager::SendIbanSuggestions(const std::vector<Iban*>& ibans,
const QueryHandler& query_handler) {
if (!query_handler.handler_) {
// Either the handler has been destroyed, or it is invalid.
return;
}
// If the input box content equals any of the available IBANs, then
// assume the IBAN has been filled, and don't show any suggestions.
// Note: this |prefix_| is actually the value of form and we are comparing
// the value with the full IBAN value. However, once we land
// MASKED_SERVER_IBANs and Chrome doesn't know the whole value, we'll have
// check 'prefix'(E.g., the first ~5 characters).
if (base::Contains(ibans, query_handler.prefix_, &Iban::value)) {
// Return empty suggestions to query handler. This will result in no
// suggestions being displayed.
query_handler.handler_->OnSuggestionsReturned(
query_handler.field_id_, query_handler.trigger_source_, {});
return;
}
// Only return IBAN-based suggestions whose prefix match `prefix_`.
std::vector<const Iban*> suggested_ibans;
suggested_ibans.reserve(ibans.size());
for (const auto* iban : ibans) {
if (base::StartsWith(iban->value(), query_handler.prefix_)) {
suggested_ibans.push_back(iban);
}
}
if (suggested_ibans.empty()) {
return;
}
// Return suggestions to query handler.
query_handler.handler_->OnSuggestionsReturned(
query_handler.field_id_, query_handler.trigger_source_,
AutofillSuggestionGenerator::GetSuggestionsForIbans(suggested_ibans));
uma_recorder_.OnIbanSuggestionsShown(query_handler.field_id_);
}
void IbanManager::OnSingleFieldSuggestionSelected(const std::u16string& value,
PopupItemId popup_item_id) {
uma_recorder_.OnIbanSuggestionSelected();
}
} // namespace autofill