blob: f521b903a9850af031e913e39e5e981fa877d8e7 [file] [log] [blame]
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/autofill/payments/chrome_payments_autofill_client.h"
#include <optional>
#include <vector>
#include "base/check_deref.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/android/preferences/autofill/settings_navigation_helper.h"
#include "chrome/browser/autofill/autofill_offer_manager_factory.h"
#include "chrome/browser/autofill/iban_manager_factory.h"
#include "chrome/browser/autofill/merchant_promo_code_manager_factory.h"
#include "chrome/browser/keyboard_accessory/android/manual_filling_controller.h"
#include "chrome/browser/keyboard_accessory/android/manual_filling_controller_impl.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/signin/identity_manager_factory.h"
#include "chrome/browser/ui/autofill/payments/create_card_unmask_prompt_view.h"
#include "chrome/browser/ui/autofill/payments/credit_card_scanner_controller.h"
#include "chrome/browser/ui/autofill/payments/iban_bubble_controller_impl.h"
#include "chrome/browser/ui/autofill/payments/mandatory_reauth_bubble_controller_impl.h"
#include "chrome/browser/ui/autofill/payments/payments_view_factory.h"
#include "chrome/browser/ui/autofill/payments/virtual_card_enroll_bubble_controller_impl.h"
#include "chrome/browser/ui/autofill/risk_util.h"
#include "components/autofill/content/browser/content_autofill_client.h"
#include "components/autofill/content/browser/content_autofill_driver.h"
#include "components/autofill/core/browser/data_manager/payments/payments_data_manager.h"
#include "components/autofill/core/browser/data_manager/personal_data_manager.h"
#include "components/autofill/core/browser/data_model/payments/autofill_offer_data.h"
#include "components/autofill/core/browser/data_model/payments/bnpl_issuer.h"
#include "components/autofill/core/browser/data_model/payments/credit_card.h"
#include "components/autofill/core/browser/data_model/valuables/loyalty_card.h"
#include "components/autofill/core/browser/integrators/touch_to_fill/touch_to_fill_delegate.h"
#include "components/autofill/core/browser/metrics/payments/risk_data_metrics.h"
#include "components/autofill/core/browser/payments/autofill_error_dialog_context.h"
#include "components/autofill/core/browser/payments/autofill_offer_manager.h"
#include "components/autofill/core/browser/payments/card_unmask_challenge_option.h"
#include "components/autofill/core/browser/payments/credit_card_cvc_authenticator.h"
#include "components/autofill/core/browser/payments/credit_card_otp_authenticator.h"
#include "components/autofill/core/browser/payments/credit_card_risk_based_authenticator.h"
#include "components/autofill/core/browser/payments/iban_access_manager.h"
#include "components/autofill/core/browser/payments/mandatory_reauth_manager.h"
#include "components/autofill/core/browser/payments/offer_notification_options.h"
#include "components/autofill/core/browser/payments/otp_unmask_delegate.h"
#include "components/autofill/core/browser/payments/otp_unmask_result.h"
#include "components/autofill/core/browser/payments/payments_autofill_client.h"
#include "components/autofill/core/browser/payments/payments_network_interface.h"
#include "components/autofill/core/browser/payments/save_and_fill_manager.h"
#include "components/autofill/core/browser/payments/virtual_card_enrollment_manager.h"
#include "components/autofill/core/browser/single_field_fillers/payments/merchant_promo_code_manager.h"
#include "components/autofill/core/browser/suggestions/suggestion.h"
#include "components/autofill/core/browser/ui/payments/autofill_error_dialog_controller_impl.h"
#include "components/autofill/core/browser/ui/payments/autofill_progress_dialog_controller_impl.h"
#include "components/autofill/core/browser/ui/payments/bnpl_tos_controller_impl.h"
#include "components/autofill/core/browser/ui/payments/bnpl_tos_view.h"
#include "components/autofill/core/browser/ui/payments/bubble_show_options.h"
#include "components/autofill/core/browser/ui/payments/card_unmask_authentication_selection_dialog_controller_impl.h"
#include "components/autofill/core/browser/ui/payments/card_unmask_otp_input_dialog_controller_impl.h"
#include "components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.h"
#include "components/autofill/core/browser/ui/payments/card_unmask_prompt_view.h"
#include "components/autofill/core/browser/ui/payments/save_and_fill_dialog_controller_impl.h"
#include "components/autofill/core/browser/ui/payments/select_bnpl_issuer_dialog_controller_impl.h"
#include "components/autofill/core/browser/ui/payments/select_bnpl_issuer_view.h"
#include "components/autofill/core/common/autofill_payments_features.h"
#include "components/signin/public/identity_manager/account_info.h"
#include "components/signin/public/identity_manager/identity_manager.h"
#include "components/user_prefs/user_prefs.h"
#include "content/public/browser/page_navigator.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_observer.h"
#include "url/gurl.h"
#if BUILDFLAG(IS_ANDROID)
#include "chrome/browser/touch_to_fill/autofill/android/touch_to_fill_payment_method_controller.h"
#include "chrome/browser/touch_to_fill/autofill/android/touch_to_fill_payment_method_view_impl.h"
#include "chrome/browser/ui/android/autofill/autofill_cvc_save_message_delegate.h"
#include "chrome/browser/ui/android/autofill/autofill_save_card_bottom_sheet_bridge.h"
#include "chrome/browser/ui/android/autofill/autofill_save_card_delegate_android.h"
#include "chrome/browser/ui/android/autofill/autofill_save_iban_bottom_sheet_bridge.h"
#include "chrome/browser/ui/android/autofill/autofill_save_iban_delegate.h"
#include "chrome/browser/ui/android/autofill/card_expiration_date_fix_flow_view_android.h"
#include "chrome/browser/ui/android/autofill/card_name_fix_flow_view_android.h"
#include "chrome/browser/ui/android/tab_model/tab_model_list.h"
#include "chrome/browser/ui/autofill/autofill_snackbar_controller_impl.h"
#include "chrome/browser/ui/autofill/payments/autofill_message_controller.h"
#include "chrome/browser/ui/autofill/payments/autofill_message_model.h"
#include "chrome/browser/ui/autofill/payments/offer_notification_controller_android.h"
#include "components/autofill/core/browser/payments/autofill_save_iban_ui_info.h"
#include "components/autofill/core/browser/ui/payments/card_expiration_date_fix_flow_view.h"
#include "components/autofill/core/browser/ui/payments/card_name_fix_flow_view.h"
#include "components/webauthn/android/internal_authenticator_android.h"
#else // !BUILDFLAG(IS_ANDROID)
#include "chrome/browser/ui/autofill/payments/desktop_payments_window_manager.h"
#include "chrome/browser/ui/autofill/payments/filled_card_information_bubble_controller_impl.h"
#include "chrome/browser/ui/autofill/payments/offer_notification_bubble_controller_impl.h"
#include "chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl.h"
#include "chrome/browser/ui/autofill/payments/webauthn_dialog_controller_impl.h"
#include "chrome/browser/ui/autofill/payments/webauthn_dialog_state.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_window/public/browser_window_interface.h"
#include "chrome/browser/ui/promos/ios_promos_utils.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "components/autofill/core/common/autofill_payments_features.h"
// TODO(crbug.com/407105162): Remove nogncheck when crbug.com/40147906 is fixed.
#include "components/tabs/public/tab_interface.h" // nogncheck
#include "components/webauthn/content/browser/internal_authenticator_impl.h"
#endif // BUILDFLAG(IS_ANDROID)
// TODO(crbug.com/407106692): Refactor for Platform-Specific Code Separation.
namespace autofill::payments {
ChromePaymentsAutofillClient::ChromePaymentsAutofillClient(
ContentAutofillClient* client)
: content::WebContentsObserver(&client->GetWebContents()),
client_(CHECK_DEREF(client)) {}
ChromePaymentsAutofillClient::~ChromePaymentsAutofillClient() = default;
void ChromePaymentsAutofillClient::LoadRiskData(
base::OnceCallback<void(const std::string&)> callback) {
if (!risk_data_.empty() &&
base::FeatureList::IsEnabled(
features::kAutofillEnablePrefetchingRiskDataForRetrieval)) {
// Notify tests that the cached risk data was used and new risk data was not
// loaded, if the callback exists.
if (cached_risk_data_loaded_callback_for_testing_) {
std::move(cached_risk_data_loaded_callback_for_testing_).Run(risk_data_);
return;
}
std::move(callback).Run(risk_data_);
return;
}
risk_util::LoadRiskData(
0, web_contents(),
base::BindOnce(&ChromePaymentsAutofillClient::OnRiskDataLoaded,
weak_ptr_factory_.GetWeakPtr(), std::move(callback),
base::TimeTicks::Now()));
}
#if BUILDFLAG(IS_ANDROID)
AutofillSaveCardBottomSheetBridge*
ChromePaymentsAutofillClient::GetOrCreateAutofillSaveCardBottomSheetBridge() {
if (!autofill_save_card_bottom_sheet_bridge_) {
// During shutdown the window may be null. There is no need to show the
// bottom sheet during shutdown.
auto* window_android = web_contents()->GetTopLevelNativeWindow();
TabModel* tab_model =
TabModelList::GetTabModelForWebContents(web_contents());
if (window_android && tab_model) {
autofill_save_card_bottom_sheet_bridge_ =
std::make_unique<AutofillSaveCardBottomSheetBridge>(window_android,
tab_model);
}
}
return autofill_save_card_bottom_sheet_bridge_.get();
}
AutofillSaveIbanBottomSheetBridge*
ChromePaymentsAutofillClient::GetOrCreateAutofillSaveIbanBottomSheetBridge() {
if (!autofill_save_iban_bottom_sheet_bridge_) {
// During shutdown the window may be null. There is no need to show the
// bottom sheet during shutdown.
auto* window_android = web_contents()->GetTopLevelNativeWindow();
TabModel* tab_model =
TabModelList::GetTabModelForWebContents(web_contents());
if (window_android && tab_model) {
autofill_save_iban_bottom_sheet_bridge_ =
std::make_unique<AutofillSaveIbanBottomSheetBridge>(window_android,
tab_model);
}
}
return autofill_save_iban_bottom_sheet_bridge_.get();
}
void ChromePaymentsAutofillClient::ConfirmAccountNameFixFlow(
base::OnceCallback<void(const std::u16string&)> callback) {
CardNameFixFlowViewAndroid* card_name_fix_flow_view_android =
new CardNameFixFlowViewAndroid(&card_name_fix_flow_controller_,
web_contents());
card_name_fix_flow_controller_.Show(
card_name_fix_flow_view_android, GetAccountHolderName(),
/*upload_save_card_callback=*/std::move(callback));
}
void ChromePaymentsAutofillClient::ConfirmExpirationDateFixFlow(
const CreditCard& card,
base::OnceCallback<void(const std::u16string&, const std::u16string&)>
callback) {
CardExpirationDateFixFlowViewAndroid*
card_expiration_date_fix_flow_view_android =
new CardExpirationDateFixFlowViewAndroid(
&card_expiration_date_fix_flow_controller_, web_contents());
card_expiration_date_fix_flow_controller_.Show(
card_expiration_date_fix_flow_view_android, card,
/*upload_save_card_callback=*/std::move(callback));
}
#else // !BUILDFLAG(IS_ANDROID)
void ChromePaymentsAutofillClient::ShowWebauthnOfferDialog(
WebauthnDialogCallback offer_dialog_callback) {
WebauthnDialogControllerImpl::GetOrCreateForPage(
web_contents()->GetPrimaryPage())
->ShowOfferDialog(std::move(offer_dialog_callback));
}
void ChromePaymentsAutofillClient::ShowWebauthnVerifyPendingDialog(
WebauthnDialogCallback verify_pending_dialog_callback) {
WebauthnDialogControllerImpl::GetOrCreateForPage(
web_contents()->GetPrimaryPage())
->ShowVerifyPendingDialog(std::move(verify_pending_dialog_callback));
}
void ChromePaymentsAutofillClient::UpdateWebauthnOfferDialogWithError() {
WebauthnDialogControllerImpl* controller =
WebauthnDialogControllerImpl::GetForPage(
web_contents()->GetPrimaryPage());
if (controller) {
controller->UpdateDialog(WebauthnDialogState::kOfferError);
}
}
bool ChromePaymentsAutofillClient::CloseWebauthnDialog() {
WebauthnDialogControllerImpl* controller =
WebauthnDialogControllerImpl::GetForPage(
web_contents()->GetPrimaryPage());
if (controller) {
return controller->CloseDialog();
}
return false;
}
void ChromePaymentsAutofillClient::
HideVirtualCardEnrollBubbleAndIconIfVisible() {
VirtualCardEnrollBubbleControllerImpl::CreateForWebContents(web_contents());
VirtualCardEnrollBubbleControllerImpl* controller =
VirtualCardEnrollBubbleControllerImpl::FromWebContents(web_contents());
if (controller && controller->IsIconVisible()) {
controller->HideIconAndBubble();
}
}
#endif // BUILDFLAG(IS_ANDROID)
bool ChromePaymentsAutofillClient::HasCreditCardScanFeature() const {
return CreditCardScannerController::HasCreditCardScanFeature();
}
void ChromePaymentsAutofillClient::ScanCreditCard(
ChromePaymentsAutofillClient::CreditCardScanCallback callback) {
CreditCardScannerController::ScanCreditCard(web_contents(),
std::move(callback));
}
void ChromePaymentsAutofillClient::ShowSaveCreditCardLocally(
const CreditCard& card,
SaveCreditCardOptions options,
LocalSaveCardPromptCallback callback) {
#if BUILDFLAG(IS_ANDROID)
DCHECK(options.show_prompt);
AutofillSaveCardUiInfo ui_info =
AutofillSaveCardUiInfo::CreateForLocalSave(options, card);
auto save_card_delegate = std::make_unique<AutofillSaveCardDelegateAndroid>(
std::move(callback), options, web_contents());
// If a CVC is detected for an existing local card in the checkout form, the
// CVC save prompt is shown in a message.
if (options.card_save_type == CardSaveType::kCvcSaveOnly) {
autofill_cvc_save_message_delegate_ =
std::make_unique<AutofillCvcSaveMessageDelegate>(web_contents());
autofill_cvc_save_message_delegate_->ShowMessage(
ui_info, std::move(save_card_delegate));
return;
}
// Saving a new local card (may include CVC) via a bottom sheet.
if (auto* bridge = GetOrCreateAutofillSaveCardBottomSheetBridge()) {
bridge->RequestShowContent(ui_info, std::move(save_card_delegate));
}
#else // !BUILDFLAG(IS_ANDROID)
SaveCardBubbleControllerImpl::CreateForWebContents(web_contents());
SaveCardBubbleControllerImpl::FromWebContents(web_contents())
->OfferLocalSave(card, options, std::move(callback));
#endif // BUILDFLAG(IS_ANDROID)
}
void ChromePaymentsAutofillClient::ShowSaveCreditCardToCloud(
const CreditCard& card,
const LegalMessageLines& legal_message_lines,
SaveCreditCardOptions options,
UploadSaveCardPromptCallback callback) {
#if BUILDFLAG(IS_ANDROID)
DCHECK(options.show_prompt);
Profile* profile =
!web_contents()
? nullptr
: Profile::FromBrowserContext(web_contents()->GetBrowserContext());
signin::IdentityManager* identity_manager =
IdentityManagerFactory::GetForProfile(profile);
AccountInfo account_info = identity_manager->FindExtendedAccountInfo(
identity_manager->GetPrimaryAccountInfo(signin::ConsentLevel::kSignin));
AutofillSaveCardUiInfo ui_info = AutofillSaveCardUiInfo::CreateForUploadSave(
options, card, legal_message_lines, account_info);
auto save_card_delegate = std::make_unique<AutofillSaveCardDelegateAndroid>(
std::move(callback), options, web_contents());
// If a CVC is detected for an existing server card in the checkout form,
// the CVC save prompt is shown in a message.
if (options.card_save_type == CardSaveType::kCvcSaveOnly) {
autofill_cvc_save_message_delegate_ =
std::make_unique<AutofillCvcSaveMessageDelegate>(web_contents());
autofill_cvc_save_message_delegate_->ShowMessage(
ui_info, std::move(save_card_delegate));
return;
}
// For new cards, the save card prompt is shown in a bottom sheet.
if (auto* bridge = GetOrCreateAutofillSaveCardBottomSheetBridge()) {
bridge->RequestShowContent(ui_info, std::move(save_card_delegate));
}
#else
// Hide virtual card confirmation bubble showing for a different card.
HideVirtualCardEnrollBubbleAndIconIfVisible();
// Do lazy initialization of SaveCardBubbleControllerImpl.
SaveCardBubbleControllerImpl::CreateForWebContents(web_contents());
SaveCardBubbleControllerImpl::FromWebContents(web_contents())
->OfferUploadSave(card, legal_message_lines, options,
std::move(callback));
#endif
}
void ChromePaymentsAutofillClient::CreditCardUploadCompleted(
PaymentsRpcResult result,
std::optional<OnConfirmationClosedCallback>
on_confirmation_closed_callback) {
const bool card_saved = result == PaymentsRpcResult::kSuccess;
#if BUILDFLAG(IS_ANDROID)
if (auto* bridge = GetOrCreateAutofillSaveCardBottomSheetBridge()) {
bridge->Hide();
}
if (card_saved) {
if (on_confirmation_closed_callback) {
client_->GetAutofillSnackbarController()->ShowWithDurationAndCallback(
AutofillSnackbarType::kSaveCardSuccess,
kSaveCardConfirmationSnackbarDuration, base::DoNothing(),
std::move(on_confirmation_closed_callback));
} else {
client_->GetAutofillSnackbarController()->Show(
AutofillSnackbarType::kSaveCardSuccess, base::DoNothing());
}
} else if (result != PaymentsRpcResult::kClientSideTimeout) {
GetAutofillMessageController().Show(
AutofillMessageModel::CreateForSaveCardFailure());
}
#else // !BUILDFLAG(IS_ANDROID)
if (result == PaymentsRpcResult::kClientSideTimeout) {
HideSaveCardPrompt();
return;
}
if (SaveCardBubbleControllerImpl* controller =
SaveCardBubbleControllerImpl::FromWebContents(web_contents())) {
// Only attempt to show the iOS payment promo if the card was successfully
// uploaded and there is no VCN enroll flow callback, and still fallback to
// normal confirmation bubble if showing the promo fails.
if (card_saved && !on_confirmation_closed_callback) {
base::OnceClosure promo_will_show_callback =
controller->GetEndSaveCardPromptFlowCallback();
base::OnceClosure promo_not_shown_callback =
controller->GetShowConfirmationForCardSuccessfullySavedCallback();
Browser* browser = chrome::FindBrowserWithTab(web_contents());
if (!browser) {
std::move(promo_not_shown_callback).Run();
return;
}
ios_promos_utils::MaybeOverrideCardConfirmationBubbleWithIOSPaymentPromo(
browser, std::move(promo_will_show_callback),
std::move(promo_not_shown_callback));
return;
}
controller->ShowConfirmationBubbleView(
card_saved, std::move(on_confirmation_closed_callback));
}
#endif
}
void ChromePaymentsAutofillClient::HideSaveCardPrompt() {
#if !BUILDFLAG(IS_ANDROID)
SaveCardBubbleControllerImpl* controller =
SaveCardBubbleControllerImpl::FromWebContents(web_contents());
if (controller) {
controller->HideSaveCardBubble();
}
#endif
}
void ChromePaymentsAutofillClient::ShowVirtualCardEnrollDialog(
const VirtualCardEnrollmentFields& virtual_card_enrollment_fields,
base::OnceClosure accept_virtual_card_callback,
base::OnceClosure decline_virtual_card_callback) {
VirtualCardEnrollBubbleControllerImpl::CreateForWebContents(web_contents());
VirtualCardEnrollBubbleControllerImpl* controller =
VirtualCardEnrollBubbleControllerImpl::FromWebContents(web_contents());
DCHECK(controller);
controller->ShowBubble(virtual_card_enrollment_fields,
std::move(accept_virtual_card_callback),
std::move(decline_virtual_card_callback));
}
void ChromePaymentsAutofillClient::VirtualCardEnrollCompleted(
PaymentsRpcResult result) {
VirtualCardEnrollBubbleControllerImpl::CreateForWebContents(web_contents());
VirtualCardEnrollBubbleControllerImpl* controller =
VirtualCardEnrollBubbleControllerImpl::FromWebContents(web_contents());
if (controller) {
// Called by clank to close AutofillVCNEnrollBottomSheetBridge.
// TODO(crbug.com/350713949): Extract AutofillVCNEnrollBottomSheetBridge
// so the controller only needs to be called for desktop.
controller->ShowConfirmationBubbleView(result);
}
#if BUILDFLAG(IS_ANDROID)
if (result == PaymentsRpcResult::kSuccess) {
client_->GetAutofillSnackbarController()->Show(
AutofillSnackbarType::kVirtualCardEnrollSuccess, base::DoNothing());
} else if (controller && result != PaymentsRpcResult::kClientSideTimeout) {
GetAutofillMessageController().Show(
AutofillMessageModel::CreateForVirtualCardEnrollFailure(
/*card_label=*/controller->GetUiModel()
.enrollment_fields()
.credit_card.NetworkAndLastFourDigits()));
}
#endif
}
void ChromePaymentsAutofillClient::OnCardDataAvailable(
const FilledCardInformationBubbleOptions& options) {
#if BUILDFLAG(IS_ANDROID)
// Note that currently the snackbar is displayed only for virtual cards or
// cards enrolled in card info retrieval.
client_->GetAutofillSnackbarController()->Show(
options.filled_card.record_type() == CreditCard::RecordType::kVirtualCard
? AutofillSnackbarType::kVirtualCard
: AutofillSnackbarType::kCardInfoRetrieval,
base::BindOnce(
[](base::WeakPtr<content::WebContents> contents) {
if (!contents) {
return;
}
ManualFillingControllerImpl::GetOrCreate(contents.get())
->ShowAccessorySheetTab(
autofill::AccessoryTabType::CREDIT_CARDS);
},
web_contents()->GetWeakPtr()));
#else
FilledCardInformationBubbleControllerImpl::CreateForWebContents(
web_contents());
FilledCardInformationBubbleControllerImpl* controller =
FilledCardInformationBubbleControllerImpl::FromWebContents(
web_contents());
controller->ShowBubble(options);
#endif
}
void ChromePaymentsAutofillClient::ConfirmSaveIbanLocally(
const Iban& iban,
bool should_show_prompt,
SaveIbanPromptCallback callback) {
#if BUILDFLAG(IS_ANDROID)
// For new IBANs, the save IBAN prompt is shown in a bottom sheet.
if (auto* bridge = GetOrCreateAutofillSaveIbanBottomSheetBridge()) {
auto save_iban_delegate = std::make_unique<AutofillSaveIbanDelegate>(
std::move(callback), web_contents());
AutofillSaveIbanUiInfo ui_info = AutofillSaveIbanUiInfo::CreateForLocalSave(
iban.GetIdentifierStringForAutofillDisplay(
/*is_value_masked=*/false));
bridge->RequestShowContent(ui_info, std::move(save_iban_delegate));
}
#else
// Do lazy initialization of IbanBubbleControllerImpl.
IbanBubbleControllerImpl::CreateForWebContents(web_contents());
IbanBubbleControllerImpl::FromWebContents(web_contents())
->OfferLocalSave(iban, should_show_prompt, std::move(callback));
#endif
}
void ChromePaymentsAutofillClient::ConfirmUploadIbanToCloud(
const Iban& iban,
LegalMessageLines legal_message_lines,
bool should_show_prompt,
SaveIbanPromptCallback callback) {
#if BUILDFLAG(IS_ANDROID)
AutofillSaveIbanUiInfo ui_info = AutofillSaveIbanUiInfo::CreateForUploadSave(
iban.GetIdentifierStringForAutofillDisplay(
/*is_value_masked=*/false),
legal_message_lines);
// Upload a new IBAN to the server via a Bottom Sheet.
if (auto* bridge = GetOrCreateAutofillSaveIbanBottomSheetBridge()) {
bridge->RequestShowContent(
ui_info, std::make_unique<AutofillSaveIbanDelegate>(std::move(callback),
web_contents()));
}
#else
// Do lazy initialization of IbanBubbleControllerImpl.
IbanBubbleControllerImpl::CreateForWebContents(web_contents());
IbanBubbleControllerImpl::FromWebContents(web_contents())
->OfferUploadSave(iban, std::move(legal_message_lines),
should_show_prompt, std::move(callback));
#endif
}
void ChromePaymentsAutofillClient::IbanUploadCompleted(bool iban_saved,
bool hit_max_strikes) {
#if BUILDFLAG(IS_ANDROID)
if (auto* bridge = GetOrCreateAutofillSaveIbanBottomSheetBridge()) {
bridge->Hide();
}
if (iban_saved) {
client_->GetAutofillSnackbarController()->Show(
AutofillSnackbarType::kSaveServerIbanSuccess,
/*on_action_clicked_callback=*/base::DoNothing());
}
#else // BUILDFLAG(IS_ANDROID)
if (IbanBubbleControllerImpl* controller =
IbanBubbleControllerImpl::FromWebContents(web_contents())) {
controller->ShowConfirmationBubbleView(iban_saved, hit_max_strikes);
}
#endif
}
void ChromePaymentsAutofillClient::ShowAutofillProgressDialog(
AutofillProgressDialogType autofill_progress_dialog_type,
base::OnceClosure cancel_callback) {
autofill_progress_dialog_controller_ =
std::make_unique<AutofillProgressDialogControllerImpl>(
autofill_progress_dialog_type, std::move(cancel_callback));
autofill_progress_dialog_controller_->ShowDialog(
base::BindOnce(&CreateAndShowProgressDialog,
autofill_progress_dialog_controller_->GetWeakPtr(),
base::Unretained(web_contents())));
}
void ChromePaymentsAutofillClient::CloseAutofillProgressDialog(
bool show_confirmation_before_closing,
base::OnceClosure no_interactive_authentication_callback) {
DCHECK(autofill_progress_dialog_controller_);
autofill_progress_dialog_controller_->DismissDialog(
show_confirmation_before_closing,
std::move(no_interactive_authentication_callback));
}
void ChromePaymentsAutofillClient::ShowCardUnmaskOtpInputDialog(
CreditCard::RecordType card_type,
const CardUnmaskChallengeOption& challenge_option,
base::WeakPtr<OtpUnmaskDelegate> delegate) {
card_unmask_otp_input_dialog_controller_ =
std::make_unique<CardUnmaskOtpInputDialogControllerImpl>(
card_type, challenge_option, delegate);
card_unmask_otp_input_dialog_controller_->ShowDialog(
base::BindOnce(&CreateAndShowOtpInputDialog,
card_unmask_otp_input_dialog_controller_->GetWeakPtr(),
base::Unretained(web_contents())));
}
void ChromePaymentsAutofillClient::OnUnmaskOtpVerificationResult(
OtpUnmaskResult unmask_result) {
if (card_unmask_otp_input_dialog_controller_) {
card_unmask_otp_input_dialog_controller_->OnOtpVerificationResult(
unmask_result);
}
}
PaymentsNetworkInterface*
ChromePaymentsAutofillClient::GetPaymentsNetworkInterface() {
if (!payments_network_interface_) {
payments_network_interface_ = std::make_unique<PaymentsNetworkInterface>(
Profile::FromBrowserContext(web_contents()->GetBrowserContext())
->GetURLLoaderFactory(),
client_->GetIdentityManager(),
&client_->GetPersonalDataManager().payments_data_manager(),
Profile::FromBrowserContext(web_contents()->GetBrowserContext())
->IsOffTheRecord());
}
return payments_network_interface_.get();
}
void ChromePaymentsAutofillClient::ShowAutofillErrorDialog(
AutofillErrorDialogContext context) {
autofill_error_dialog_controller_ =
std::make_unique<AutofillErrorDialogControllerImpl>(std::move(context));
autofill_error_dialog_controller_->Show(
base::BindOnce(&CreateAndShowAutofillErrorDialog,
base::Unretained(autofill_error_dialog_controller_.get()),
base::Unretained(web_contents())));
}
PaymentsWindowManager*
ChromePaymentsAutofillClient::GetPaymentsWindowManager() {
#if !BUILDFLAG(IS_ANDROID)
if (!payments_window_manager_) {
payments_window_manager_ =
std::make_unique<DesktopPaymentsWindowManager>(&client_.get());
}
return payments_window_manager_.get();
#else
return nullptr;
#endif // !BUILDFLAG(IS_ANDROID)
}
void ChromePaymentsAutofillClient::ShowUnmaskPrompt(
const CreditCard& card,
const CardUnmaskPromptOptions& card_unmask_prompt_options,
base::WeakPtr<CardUnmaskDelegate> delegate) {
unmask_controller_ = std::make_unique<CardUnmaskPromptControllerImpl>(
user_prefs::UserPrefs::Get(client_->GetWebContents().GetBrowserContext()),
card, card_unmask_prompt_options, delegate);
unmask_controller_->ShowPrompt(base::BindOnce(
&CreateCardUnmaskPromptView, base::Unretained(unmask_controller_.get()),
base::Unretained(web_contents())));
}
void ChromePaymentsAutofillClient::ShowUnmaskAuthenticatorSelectionDialog(
const std::vector<CardUnmaskChallengeOption>& challenge_options,
base::OnceCallback<void(const std::string&)>
confirm_unmask_challenge_option_callback,
base::OnceClosure cancel_unmasking_closure) {
card_unmask_authentication_selection_controller_ =
std::make_unique<CardUnmaskAuthenticationSelectionDialogControllerImpl>(
challenge_options,
std::move(confirm_unmask_challenge_option_callback),
std::move(cancel_unmasking_closure));
card_unmask_authentication_selection_controller_->ShowDialog(
base::BindOnce(&CreateAndShowCardUnmaskAuthenticationSelectionDialog,
base::Unretained(web_contents())));
}
void ChromePaymentsAutofillClient::DismissUnmaskAuthenticatorSelectionDialog(
bool server_success) {
if (card_unmask_authentication_selection_controller_) {
card_unmask_authentication_selection_controller_
->DismissDialogUponServerProcessedAuthenticationMethodRequest(
server_success);
card_unmask_authentication_selection_controller_.reset();
}
}
// TODO(crbug.com/40186650): Refactor this for both CVC and Biometrics flows.
void ChromePaymentsAutofillClient::OnUnmaskVerificationResult(
PaymentsRpcResult result) {
if (unmask_controller_) {
unmask_controller_->OnVerificationResult(result);
}
#if BUILDFLAG(IS_ANDROID)
// For VCN-related errors, on Android we show a new error dialog instead of
// updating the CVC unmask prompt with the error message.
switch (result) {
case PaymentsRpcResult::kVcnRetrievalPermanentFailure:
ShowAutofillErrorDialog(
AutofillErrorDialogContext::WithVirtualCardPermanentOrTemporaryError(
/*is_permanent_error=*/true));
break;
case PaymentsRpcResult::kVcnRetrievalTryAgainFailure:
ShowAutofillErrorDialog(
AutofillErrorDialogContext::WithVirtualCardPermanentOrTemporaryError(
/*is_permanent_error=*/false));
break;
case PaymentsRpcResult::kSuccess:
case PaymentsRpcResult::kTryAgainFailure:
case PaymentsRpcResult::kPermanentFailure:
case PaymentsRpcResult::kNetworkError:
case PaymentsRpcResult::kClientSideTimeout:
// Do nothing
break;
case PaymentsRpcResult::kNone:
NOTREACHED();
}
#endif // BUILDFLAG(IS_ANDROID)
}
void ChromePaymentsAutofillClient::ShowBnplTos(
BnplTosModel bnpl_tos_model,
base::OnceClosure accept_callback,
base::OnceClosure cancel_callback) {
if (!bnpl_tos_controller_) {
bnpl_tos_controller_ =
std::make_unique<BnplTosControllerImpl>(&client_.get());
}
#if !BUILDFLAG(IS_ANDROID)
bnpl_tos_controller_->Show(
base::BindOnce(&CreateAndShowBnplTos, bnpl_tos_controller_->GetWeakPtr(),
base::Unretained(web_contents())),
std::move(bnpl_tos_model), std::move(accept_callback),
std::move(cancel_callback));
#endif
}
void ChromePaymentsAutofillClient::CloseBnplTos() {
if (!bnpl_tos_controller_) {
return;
}
bnpl_tos_controller_->Dismiss();
bnpl_tos_controller_.reset();
}
VirtualCardEnrollmentManager*
ChromePaymentsAutofillClient::GetVirtualCardEnrollmentManager() {
if (!virtual_card_enrollment_manager_) {
virtual_card_enrollment_manager_ =
std::make_unique<VirtualCardEnrollmentManager>(
&client_->GetPersonalDataManager().payments_data_manager(),
GetPaymentsNetworkInterface(), &client_.get());
}
return virtual_card_enrollment_manager_.get();
}
CreditCardCvcAuthenticator&
ChromePaymentsAutofillClient::GetCvcAuthenticator() {
if (!cvc_authenticator_) {
cvc_authenticator_ =
std::make_unique<CreditCardCvcAuthenticator>(&client_.get());
}
return *cvc_authenticator_;
}
CreditCardOtpAuthenticator*
ChromePaymentsAutofillClient::GetOtpAuthenticator() {
if (!otp_authenticator_) {
otp_authenticator_ =
std::make_unique<CreditCardOtpAuthenticator>(&client_.get());
}
return otp_authenticator_.get();
}
CreditCardRiskBasedAuthenticator*
ChromePaymentsAutofillClient::GetRiskBasedAuthenticator() {
if (!risk_based_authenticator_) {
risk_based_authenticator_ =
std::make_unique<CreditCardRiskBasedAuthenticator>(&client_.get());
}
return risk_based_authenticator_.get();
}
void ChromePaymentsAutofillClient::ShowMandatoryReauthOptInPrompt(
base::OnceClosure accept_mandatory_reauth_callback,
base::OnceClosure cancel_mandatory_reauth_callback,
base::RepeatingClosure close_mandatory_reauth_callback) {
MandatoryReauthBubbleControllerImpl::CreateForWebContents(web_contents());
MandatoryReauthBubbleControllerImpl::FromWebContents(web_contents())
->ShowBubble(std::move(accept_mandatory_reauth_callback),
std::move(cancel_mandatory_reauth_callback),
std::move(close_mandatory_reauth_callback));
}
IbanManager* ChromePaymentsAutofillClient::GetIbanManager() {
Profile* profile =
Profile::FromBrowserContext(web_contents()->GetBrowserContext());
return IbanManagerFactory::GetForProfile(profile);
}
IbanAccessManager* ChromePaymentsAutofillClient::GetIbanAccessManager() {
if (!iban_access_manager_) {
iban_access_manager_ = std::make_unique<IbanAccessManager>(&client_.get());
}
return iban_access_manager_.get();
}
void ChromePaymentsAutofillClient::ShowMandatoryReauthOptInConfirmation() {
#if BUILDFLAG(IS_ANDROID)
client_->GetAutofillSnackbarController()->Show(
AutofillSnackbarType::kMandatoryReauth,
base::BindOnce(
[](base::WeakPtr<content::WebContents> contents) {
if (contents) {
return;
}
// For mandatory reauth snackbar, we will show Android credit card
// settings page.
ShowAutofillCreditCardSettings(contents.get());
},
web_contents()->GetWeakPtr()));
#else
MandatoryReauthBubbleControllerImpl::CreateForWebContents(web_contents());
// TODO(crbug.com/4555994): Pass in the bubble type as a parameter so we
// enforce that the confirmation bubble is shown.
MandatoryReauthBubbleControllerImpl::FromWebContents(web_contents())
->ReshowBubble();
#endif
}
void ChromePaymentsAutofillClient::UpdateOfferNotification(
const AutofillOfferData& offer,
const OfferNotificationOptions& options) {
const CreditCard* card = offer.GetEligibleInstrumentIds().empty()
? nullptr
: client_->GetPersonalDataManager()
.payments_data_manager()
.GetCreditCardByInstrumentId(
offer.GetEligibleInstrumentIds()[0]);
if (offer.IsCardLinkedOffer() && !card) {
return;
}
#if BUILDFLAG(IS_ANDROID)
if (options.notification_has_been_shown) {
// For Android, if notification has been shown on this merchant, don't show
// it again.
return;
}
OfferNotificationControllerAndroid::CreateForWebContents(web_contents());
OfferNotificationControllerAndroid* controller =
OfferNotificationControllerAndroid::FromWebContents(web_contents());
controller->ShowIfNecessary(&offer, card);
#else
OfferNotificationBubbleControllerImpl::CreateForWebContents(web_contents());
OfferNotificationBubbleControllerImpl* controller =
OfferNotificationBubbleControllerImpl::FromWebContents(web_contents());
controller->ShowOfferNotificationIfApplicable(offer, card, options);
#endif
}
void ChromePaymentsAutofillClient::DismissOfferNotification() {
#if BUILDFLAG(IS_ANDROID)
OfferNotificationControllerAndroid::CreateForWebContents(web_contents());
OfferNotificationControllerAndroid* controller =
OfferNotificationControllerAndroid::FromWebContents(web_contents());
controller->Dismiss();
#else
if (auto* controller = OfferNotificationBubbleControllerImpl::FromWebContents(
web_contents())) {
controller->DismissNotification();
}
#endif
}
void ChromePaymentsAutofillClient::OpenPromoCodeOfferDetailsURL(
const GURL& url) {
web_contents()->OpenURL(
content::OpenURLParams(url, content::Referrer(),
WindowOpenDisposition::NEW_FOREGROUND_TAB,
ui::PageTransition::PAGE_TRANSITION_AUTO_TOPLEVEL,
/*is_renderer_initiated=*/false),
/*navigation_handle_callback=*/{});
}
MerchantPromoCodeManager*
ChromePaymentsAutofillClient::GetMerchantPromoCodeManager() {
Profile* profile =
Profile::FromBrowserContext(web_contents()->GetBrowserContext());
return MerchantPromoCodeManagerFactory::GetForProfile(profile);
}
AutofillOfferManager* ChromePaymentsAutofillClient::GetAutofillOfferManager() {
return AutofillOfferManagerFactory::GetForBrowserContext(
web_contents()->GetBrowserContext());
}
bool ChromePaymentsAutofillClient::ShowTouchToFillCreditCard(
base::WeakPtr<TouchToFillDelegate> delegate,
base::span<const autofill::CreditCard> cards_to_suggest,
base::span<const Suggestion> suggestions) {
#if BUILDFLAG(IS_ANDROID)
// Create the manual filling controller which will be used to show the
// unmasked virtual card details in the manual fallback.
ManualFillingController::GetOrCreate(web_contents())
->UpdateSourceAvailability(
ManualFillingController::FillingSource::CREDIT_CARD_FALLBACKS,
!cards_to_suggest.empty());
return touch_to_fill_payment_method_controller_.ShowCreditCards(
std::make_unique<TouchToFillPaymentMethodViewImpl>(web_contents()),
delegate, std::move(cards_to_suggest), std::move(suggestions));
#else
// Touch To Fill is not supported on Desktop.
NOTREACHED();
#endif
}
bool ChromePaymentsAutofillClient::ShowTouchToFillIban(
base::WeakPtr<TouchToFillDelegate> delegate,
base::span<const autofill::Iban> ibans_to_suggest) {
#if BUILDFLAG(IS_ANDROID)
return touch_to_fill_payment_method_controller_.ShowIbans(
std::make_unique<TouchToFillPaymentMethodViewImpl>(web_contents()),
delegate, std::move(ibans_to_suggest));
#else
// Touch To Fill is not supported on Desktop.
NOTREACHED();
#endif
}
bool ChromePaymentsAutofillClient::ShowTouchToFillLoyaltyCard(
base::WeakPtr<TouchToFillDelegate> delegate,
base::span<const autofill::LoyaltyCard> loyalty_cards_to_suggest) {
#if BUILDFLAG(IS_ANDROID)
return touch_to_fill_payment_method_controller_.ShowLoyaltyCards(
std::make_unique<TouchToFillPaymentMethodViewImpl>(web_contents()),
delegate, std::move(loyalty_cards_to_suggest));
#else
// Touch To Fill is not supported on Desktop.
NOTREACHED();
#endif
}
void ChromePaymentsAutofillClient::HideTouchToFillPaymentMethod() {
#if BUILDFLAG(IS_ANDROID)
touch_to_fill_payment_method_controller_.Hide();
#else
// Touch To Fill is not supported on Desktop.
NOTREACHED();
#endif
}
std::unique_ptr<webauthn::InternalAuthenticator>
ChromePaymentsAutofillClient::CreateCreditCardInternalAuthenticator(
AutofillDriver* driver) {
auto* cad = static_cast<ContentAutofillDriver*>(driver);
content::RenderFrameHost* rfh = cad->render_frame_host();
#if BUILDFLAG(IS_ANDROID)
return std::make_unique<webauthn::InternalAuthenticatorAndroid>(rfh);
#else
return std::make_unique<content::InternalAuthenticatorImpl>(rfh);
#endif
}
payments::MandatoryReauthManager*
ChromePaymentsAutofillClient::GetOrCreatePaymentsMandatoryReauthManager() {
if (!payments_mandatory_reauth_manager_) {
payments_mandatory_reauth_manager_ =
std::make_unique<payments::MandatoryReauthManager>(&client_.get());
}
return payments_mandatory_reauth_manager_.get();
}
PaymentsDataManager& ChromePaymentsAutofillClient::GetPaymentsDataManager() {
return client_->GetPersonalDataManager().payments_data_manager();
}
void ChromePaymentsAutofillClient::ShowCreditCardSaveAndFillDialog() {
#if !BUILDFLAG(IS_ANDROID)
if (!save_and_fill_dialog_controller_) {
save_and_fill_dialog_controller_ =
std::make_unique<SaveAndFillDialogControllerImpl>();
}
save_and_fill_dialog_controller_->ShowDialog(base::BindOnce(
&CreateAndShowSaveAndFillDialog,
save_and_fill_dialog_controller_->GetWeakPtr(), web_contents()));
#else
NOTIMPLEMENTED();
#endif // !BUILDFLAG(IS_ANDROID)
}
SaveAndFillManager* ChromePaymentsAutofillClient::GetSaveAndFillManager() {
#if BUILDFLAG(IS_ANDROID)
return nullptr;
#else
if (!save_and_fill_manager_) {
save_and_fill_manager_ =
std::make_unique<payments::SaveAndFillManager>(this);
}
return save_and_fill_manager_.get();
#endif // BUILDFLAG(IS_ANDROID)
}
void ChromePaymentsAutofillClient::ShowSelectBnplIssuerDialog(
std::vector<BnplIssuerContext> bnpl_issuer_context,
std::string app_locale,
base::OnceCallback<void(BnplIssuer)> selected_issuer_callback,
base::OnceClosure cancel_callback) {
#if !BUILDFLAG(IS_ANDROID)
select_bnpl_issuer_dialog_controller_ =
std::make_unique<SelectBnplIssuerDialogControllerImpl>();
select_bnpl_issuer_dialog_controller_->ShowDialog(
base::BindOnce(&CreateAndShowBnplIssuerSelectionDialog,
select_bnpl_issuer_dialog_controller_->GetWeakPtr(),
base::Unretained(web_contents())),
std::move(bnpl_issuer_context), std::move(app_locale),
std::move(selected_issuer_callback), std::move(cancel_callback));
#endif // !BUILDFLAG(IS_ANDROID)
}
void ChromePaymentsAutofillClient::DismissSelectBnplIssuerDialog() {
if (select_bnpl_issuer_dialog_controller_) {
select_bnpl_issuer_dialog_controller_->Dismiss();
select_bnpl_issuer_dialog_controller_.reset();
}
}
bool ChromePaymentsAutofillClient::IsTabModalPopupDeprecated() const {
#if !BUILDFLAG(IS_ANDROID)
tabs::TabInterface* const tab_interface =
tabs::TabInterface::MaybeGetFromContents(web_contents());
return tab_interface && tab_interface->GetBrowserWindowInterface()
->IsTabModalPopupDeprecated();
#else
return false;
#endif // !BUILDFLAG(IS_ANDROID)
}
#if BUILDFLAG(IS_ANDROID)
AutofillMessageController&
ChromePaymentsAutofillClient::GetAutofillMessageController() {
if (!autofill_message_controller_) {
autofill_message_controller_ =
std::make_unique<AutofillMessageController>(web_contents());
}
return *autofill_message_controller_;
}
TouchToFillPaymentMethodController&
ChromePaymentsAutofillClient::GetTouchToFillPaymentMethodController() {
return touch_to_fill_payment_method_controller_;
}
void ChromePaymentsAutofillClient::
SetAutofillSaveCardBottomSheetBridgeForTesting(
std::unique_ptr<AutofillSaveCardBottomSheetBridge>
autofill_save_card_bottom_sheet_bridge) {
autofill_save_card_bottom_sheet_bridge_ =
std::move(autofill_save_card_bottom_sheet_bridge);
}
void ChromePaymentsAutofillClient::
SetAutofillSaveIbanBottomSheetBridgeForTesting(
std::unique_ptr<AutofillSaveIbanBottomSheetBridge>
autofill_save_iban_bottom_sheet_bridge) {
autofill_save_iban_bottom_sheet_bridge_ =
std::move(autofill_save_iban_bottom_sheet_bridge);
}
void ChromePaymentsAutofillClient::SetAutofillMessageControllerForTesting(
std::unique_ptr<AutofillMessageController> autofill_message_controller) {
autofill_message_controller_ = std::move(autofill_message_controller);
}
#endif // #if BUILDFLAG(IS_ANDROID)
std::u16string ChromePaymentsAutofillClient::GetAccountHolderName() const {
if (!web_contents()) {
return std::u16string();
}
Profile* profile =
Profile::FromBrowserContext(web_contents()->GetBrowserContext());
if (!profile) {
return std::u16string();
}
signin::IdentityManager* identity_manager =
IdentityManagerFactory::GetForProfile(profile);
if (!identity_manager) {
return std::u16string();
}
AccountInfo primary_account_info = identity_manager->FindExtendedAccountInfo(
identity_manager->GetPrimaryAccountInfo(signin::ConsentLevel::kSignin));
return base::UTF8ToUTF16(primary_account_info.full_name);
}
void ChromePaymentsAutofillClient::SetRiskDataForTesting(
const std::string& risk_data) {
risk_data_ = risk_data;
}
void ChromePaymentsAutofillClient::SetCachedRiskDataLoadedCallbackForTesting(
base::OnceCallback<void(const std::string&)>
cached_risk_data_loaded_callback_for_testing) {
cached_risk_data_loaded_callback_for_testing_ =
std::move(cached_risk_data_loaded_callback_for_testing);
}
void ChromePaymentsAutofillClient::OnRiskDataLoaded(
base::OnceCallback<void(const std::string&)> callback,
base::TimeTicks start_time,
const std::string& risk_data) {
autofill_metrics::LogRiskDataLoadingLatency(base::TimeTicks::Now() -
start_time);
risk_data_ = risk_data;
std::move(callback).Run(risk_data_);
}
} // namespace autofill::payments