| // Copyright 2015 The Chromium Authors. All rights reserved. |
| // 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/save_card_bubble_controller_impl.h" |
| |
| #include <stddef.h> |
| #include <utility> |
| |
| #include "base/strings/utf_string_conversions.h" |
| #include "chrome/browser/autofill/legacy_strike_database_factory.h" |
| #include "chrome/browser/autofill/personal_data_manager_factory.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/signin/account_consistency_mode_manager.h" |
| #include "chrome/browser/signin/identity_manager_factory.h" |
| #include "chrome/browser/signin/signin_ui_util.h" |
| #include "chrome/browser/ssl/security_state_tab_helper.h" |
| #include "chrome/browser/sync/profile_sync_service_factory.h" |
| #include "chrome/browser/ui/autofill/popup_constants.h" |
| #include "chrome/browser/ui/autofill/save_card_bubble_view.h" |
| #include "chrome/browser/ui/autofill/save_card_ui.h" |
| #include "chrome/browser/ui/browser.h" |
| #include "chrome/browser/ui/browser_finder.h" |
| #include "chrome/browser/ui/browser_window.h" |
| #include "chrome/browser/ui/chrome_pages.h" |
| #include "chrome/browser/ui/location_bar/location_bar.h" |
| #include "chrome/browser/ui/sync/sync_promo_ui.h" |
| #include "chrome/common/url_constants.h" |
| #include "components/autofill/core/browser/autofill_experiments.h" |
| #include "components/autofill/core/browser/autofill_metrics.h" |
| #include "components/autofill/core/browser/legacy_strike_database.h" |
| #include "components/autofill/core/browser/personal_data_manager.h" |
| #include "components/autofill/core/common/autofill_clock.h" |
| #include "components/autofill/core/common/autofill_constants.h" |
| #include "components/autofill/core/common/autofill_features.h" |
| #include "components/autofill/core/common/autofill_prefs.h" |
| #include "components/browser_sync/profile_sync_service.h" |
| #include "components/prefs/pref_service.h" |
| #include "components/signin/core/browser/signin_buildflags.h" |
| #include "components/strings/grit/components_strings.h" |
| #include "components/user_prefs/user_prefs.h" |
| #include "content/public/browser/navigation_handle.h" |
| #include "services/identity/public/cpp/identity_manager.h" |
| #include "ui/base/l10n/l10n_util.h" |
| |
| namespace autofill { |
| |
| SaveCardBubbleControllerImpl::SaveCardBubbleControllerImpl( |
| content::WebContents* web_contents) |
| : content::WebContentsObserver(web_contents), |
| web_contents_(web_contents), |
| pref_service_( |
| user_prefs::UserPrefs::Get(web_contents->GetBrowserContext())), |
| weak_ptr_factory_(this) { |
| security_state::SecurityInfo security_info; |
| SecurityStateTabHelper::FromWebContents(web_contents) |
| ->GetSecurityInfo(&security_info); |
| security_level_ = security_info.security_level; |
| |
| personal_data_manager_ = |
| PersonalDataManagerFactory::GetInstance()->GetForProfile( |
| Profile::FromBrowserContext(web_contents->GetBrowserContext())); |
| } |
| |
| SaveCardBubbleControllerImpl::~SaveCardBubbleControllerImpl() { |
| if (save_card_bubble_view_) |
| save_card_bubble_view_->Hide(); |
| } |
| |
| void SaveCardBubbleControllerImpl::OfferLocalSave( |
| const CreditCard& card, |
| bool show_bubble, |
| base::OnceClosure save_card_callback) { |
| // Don't show the bubble if it's already visible. |
| if (save_card_bubble_view_) |
| return; |
| |
| is_upload_save_ = false; |
| is_reshow_ = false; |
| should_request_name_from_user_ = false; |
| show_bubble_ = show_bubble; |
| legal_message_lines_.clear(); |
| |
| card_ = card; |
| local_save_card_callback_ = std::move(save_card_callback); |
| current_bubble_type_ = BubbleType::LOCAL_SAVE; |
| if (show_bubble_) { |
| ShowBubble(); |
| AutofillMetrics::LogSaveCardPromptMetric( |
| AutofillMetrics::SAVE_CARD_PROMPT_SHOW_REQUESTED, is_upload_save_, |
| is_reshow_, should_request_name_from_user_, |
| should_request_expiration_date_from_user_, |
| pref_service_->GetInteger( |
| prefs::kAutofillAcceptSaveCreditCardPromptState), |
| GetSecurityLevel(), GetSyncState()); |
| } else { |
| ShowIconOnly(); |
| } |
| } |
| |
| void SaveCardBubbleControllerImpl::OfferUploadSave( |
| const CreditCard& card, |
| std::unique_ptr<base::DictionaryValue> legal_message, |
| bool should_request_name_from_user, |
| bool should_request_expiration_date_from_user, |
| bool show_bubble, |
| AutofillClient::UserAcceptedUploadCallback save_card_callback) { |
| // Don't show the bubble if it's already visible. |
| if (save_card_bubble_view_) |
| return; |
| |
| // Fetch the logged-in user's AccountInfo if it has not yet been done. |
| if (should_request_name_from_user && account_info_.IsEmpty()) |
| FetchAccountInfo(); |
| |
| is_upload_save_ = true; |
| is_reshow_ = false; |
| should_request_name_from_user_ = should_request_name_from_user; |
| should_request_expiration_date_from_user_ = |
| should_request_expiration_date_from_user; |
| show_bubble_ = show_bubble; |
| if (show_bubble_) { |
| // Can't move this into the other "if (show_bubble_)" below because an |
| // invalid legal message would skip it. |
| AutofillMetrics::LogSaveCardPromptMetric( |
| AutofillMetrics::SAVE_CARD_PROMPT_SHOW_REQUESTED, is_upload_save_, |
| is_reshow_, should_request_name_from_user_, |
| should_request_expiration_date_from_user_, |
| pref_service_->GetInteger( |
| prefs::kAutofillAcceptSaveCreditCardPromptState), |
| GetSecurityLevel(), GetSyncState()); |
| } |
| |
| if (!LegalMessageLine::Parse(*legal_message, &legal_message_lines_, |
| /*escape_apostrophes=*/true)) { |
| AutofillMetrics::LogSaveCardPromptMetric( |
| AutofillMetrics::SAVE_CARD_PROMPT_END_INVALID_LEGAL_MESSAGE, |
| is_upload_save_, is_reshow_, should_request_name_from_user_, |
| should_request_expiration_date_from_user_, |
| pref_service_->GetInteger( |
| prefs::kAutofillAcceptSaveCreditCardPromptState), |
| GetSecurityLevel(), GetSyncState()); |
| return; |
| } |
| |
| card_ = card; |
| upload_save_card_callback_ = std::move(save_card_callback); |
| current_bubble_type_ = BubbleType::UPLOAD_SAVE; |
| |
| if (show_bubble_) |
| ShowBubble(); |
| else |
| ShowIconOnly(); |
| } |
| |
| void SaveCardBubbleControllerImpl::ShowBubbleForSignInPromo() { |
| if (!ShouldShowSignInPromo()) |
| return; |
| |
| current_bubble_type_ = BubbleType::SIGN_IN_PROMO; |
| |
| // If DICe is disabled, then we need to know whether the user is signed in |
| // to determine whether or not to show a sign-in vs sync promo. |
| if (GetAccountInfo().IsEmpty()) |
| FetchAccountInfo(); |
| ShowBubble(); |
| } |
| |
| // Exists for testing purposes only. |
| void SaveCardBubbleControllerImpl::ShowBubbleForManageCardsForTesting( |
| const CreditCard& card) { |
| card_ = card; |
| current_bubble_type_ = BubbleType::MANAGE_CARDS; |
| ShowBubble(); |
| } |
| |
| void SaveCardBubbleControllerImpl::HideBubble() { |
| if (save_card_bubble_view_) { |
| save_card_bubble_view_->Hide(); |
| save_card_bubble_view_ = nullptr; |
| } |
| } |
| |
| void SaveCardBubbleControllerImpl::ReshowBubble() { |
| // Don't show the bubble if it's already visible. |
| if (save_card_bubble_view_) |
| return; |
| |
| is_reshow_ = true; |
| |
| if (current_bubble_type_ == BubbleType::LOCAL_SAVE || |
| current_bubble_type_ == BubbleType::UPLOAD_SAVE) { |
| AutofillMetrics::LogSaveCardPromptMetric( |
| AutofillMetrics::SAVE_CARD_PROMPT_SHOW_REQUESTED, is_upload_save_, |
| is_reshow_, should_request_name_from_user_, |
| should_request_expiration_date_from_user_, |
| pref_service_->GetInteger( |
| prefs::kAutofillAcceptSaveCreditCardPromptState), |
| GetSecurityLevel(), GetSyncState()); |
| } |
| |
| ShowBubble(); |
| } |
| |
| bool SaveCardBubbleControllerImpl::IsIconVisible() const { |
| // If there is no bubble to show, then there should be no icon. |
| return current_bubble_type_ != BubbleType::INACTIVE; |
| } |
| |
| SaveCardBubbleView* SaveCardBubbleControllerImpl::save_card_bubble_view() |
| const { |
| return save_card_bubble_view_; |
| } |
| |
| base::string16 SaveCardBubbleControllerImpl::GetWindowTitle() const { |
| switch (current_bubble_type_) { |
| case BubbleType::LOCAL_SAVE: |
| return l10n_util::GetStringUTF16( |
| IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_LOCAL); |
| case BubbleType::UPLOAD_SAVE: |
| return l10n_util::GetStringUTF16( |
| base::FeatureList::IsEnabled( |
| features::kAutofillSaveCardImprovedUserConsent) |
| ? IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_TO_CLOUD_V4 |
| : IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_TO_CLOUD_V3); |
| case BubbleType::SIGN_IN_PROMO: |
| #if BUILDFLAG(ENABLE_DICE_SUPPORT) |
| if (AccountConsistencyModeManager::IsDiceEnabledForProfile( |
| GetProfile())) { |
| return l10n_util::GetStringUTF16(IDS_AUTOFILL_SYNC_PROMO_MESSAGE); |
| } |
| #endif |
| return l10n_util::GetStringUTF16(IDS_AUTOFILL_CARD_SAVED); |
| case BubbleType::MANAGE_CARDS: |
| return l10n_util::GetStringUTF16(IDS_AUTOFILL_CARD_SAVED); |
| case BubbleType::INACTIVE: |
| NOTREACHED(); |
| return base::string16(); |
| } |
| } |
| |
| base::string16 SaveCardBubbleControllerImpl::GetExplanatoryMessage() const { |
| if (current_bubble_type_ != BubbleType::UPLOAD_SAVE) |
| return base::string16(); |
| |
| bool offer_to_save_on_device_message = |
| OfferStoreUnmaskedCards() && |
| !IsAutofillNoLocalSaveOnUploadSuccessExperimentEnabled(); |
| if (should_request_name_from_user_) { |
| return l10n_util::GetStringUTF16( |
| offer_to_save_on_device_message |
| ? IDS_AUTOFILL_SAVE_CARD_PROMPT_UPLOAD_EXPLANATION_V3_WITH_NAME_AND_DEVICE |
| : IDS_AUTOFILL_SAVE_CARD_PROMPT_UPLOAD_EXPLANATION_V3_WITH_NAME); |
| } |
| return l10n_util::GetStringUTF16( |
| offer_to_save_on_device_message |
| ? IDS_AUTOFILL_SAVE_CARD_PROMPT_UPLOAD_EXPLANATION_V3_WITH_DEVICE |
| : IDS_AUTOFILL_SAVE_CARD_PROMPT_UPLOAD_EXPLANATION_V3); |
| } |
| |
| const AccountInfo& SaveCardBubbleControllerImpl::GetAccountInfo() const { |
| return account_info_; |
| } |
| |
| Profile* SaveCardBubbleControllerImpl::GetProfile() const { |
| if (!web_contents()) |
| return nullptr; |
| return Profile::FromBrowserContext(web_contents()->GetBrowserContext()); |
| } |
| |
| const CreditCard& SaveCardBubbleControllerImpl::GetCard() const { |
| return card_; |
| } |
| |
| bool SaveCardBubbleControllerImpl::ShouldRequestNameFromUser() const { |
| return should_request_name_from_user_; |
| } |
| |
| bool SaveCardBubbleControllerImpl::ShouldRequestExpirationDateFromUser() const { |
| return should_request_expiration_date_from_user_; |
| } |
| |
| bool SaveCardBubbleControllerImpl::ShouldShowSignInPromo() const { |
| if (is_upload_save_ || !base::FeatureList::IsEnabled( |
| features::kAutofillSaveCardSignInAfterLocalSave)) |
| return false; |
| |
| const browser_sync::ProfileSyncService* sync_service = |
| ProfileSyncServiceFactory::GetForProfile(GetProfile()); |
| |
| return !sync_service || |
| sync_service->HasDisableReason( |
| browser_sync::ProfileSyncService::DISABLE_REASON_NOT_SIGNED_IN) || |
| sync_service->HasDisableReason( |
| browser_sync::ProfileSyncService::DISABLE_REASON_USER_CHOICE); |
| } |
| |
| bool SaveCardBubbleControllerImpl::CanAnimate() const { |
| return can_animate_; |
| } |
| |
| void SaveCardBubbleControllerImpl::OnSyncPromoAccepted( |
| const AccountInfo& account, |
| signin_metrics::AccessPoint access_point, |
| bool is_default_promo_account) { |
| DCHECK(current_bubble_type_ == BubbleType::SIGN_IN_PROMO || |
| current_bubble_type_ == BubbleType::MANAGE_CARDS); |
| Browser* browser = chrome::FindBrowserWithWebContents(web_contents()); |
| signin_ui_util::EnableSyncFromPromo(browser, account, access_point, |
| is_default_promo_account); |
| } |
| |
| void SaveCardBubbleControllerImpl::OnSaveButton( |
| const AutofillClient::UserProvidedCardDetails& user_provided_card_details) { |
| save_card_bubble_view_ = nullptr; |
| |
| switch (current_bubble_type_) { |
| case BubbleType::UPLOAD_SAVE: { |
| DCHECK(!upload_save_card_callback_.is_null()); |
| |
| base::string16 name_provided_by_user; |
| if (!user_provided_card_details.cardholder_name.empty()) { |
| // Log whether the name was changed by the user or simply accepted |
| // without edits. |
| AutofillMetrics::LogSaveCardCardholderNameWasEdited( |
| user_provided_card_details.cardholder_name != |
| base::UTF8ToUTF16(account_info_.full_name)); |
| // Trim the cardholder name provided by the user and send it in the |
| // callback so it can be included in the final request. |
| DCHECK(ShouldRequestNameFromUser()); |
| base::TrimWhitespace(user_provided_card_details.cardholder_name, |
| base::TRIM_ALL, &name_provided_by_user); |
| } |
| std::move(upload_save_card_callback_).Run(user_provided_card_details); |
| break; |
| } |
| case BubbleType::LOCAL_SAVE: |
| DCHECK(!local_save_card_callback_.is_null()); |
| // Show an animated card saved confirmation message next time |
| // UpdateIcon() is called. |
| can_animate_ = base::FeatureList::IsEnabled( |
| features::kAutofillSaveCardSignInAfterLocalSave); |
| |
| std::move(local_save_card_callback_).Run(); |
| break; |
| case BubbleType::MANAGE_CARDS: |
| AutofillMetrics::LogManageCardsPromptMetric( |
| AutofillMetrics::MANAGE_CARDS_DONE, is_upload_save_); |
| return; |
| case BubbleType::SIGN_IN_PROMO: |
| case BubbleType::INACTIVE: |
| NOTREACHED(); |
| } |
| |
| const BubbleType previous_bubble_type = current_bubble_type_; |
| current_bubble_type_ = BubbleType::INACTIVE; |
| |
| // If user just saved a card locally, the next bubble can either be a sign-in |
| // promo or a manage cards view. If we need to show a sign-in promo, that |
| // will be handled by OnAnimationEnded(), otherwise clicking the icon again |
| // will show the MANAGE_CARDS bubble, which is set here. |
| if (previous_bubble_type == BubbleType::LOCAL_SAVE && |
| base::FeatureList::IsEnabled( |
| features::kAutofillSaveCardSignInAfterLocalSave)) { |
| current_bubble_type_ = BubbleType::MANAGE_CARDS; |
| } |
| |
| if (previous_bubble_type == BubbleType::LOCAL_SAVE || |
| previous_bubble_type == BubbleType::UPLOAD_SAVE) { |
| AutofillMetrics::LogSaveCardPromptMetric( |
| AutofillMetrics::SAVE_CARD_PROMPT_END_ACCEPTED, is_upload_save_, |
| is_reshow_, should_request_name_from_user_, |
| should_request_expiration_date_from_user_, |
| pref_service_->GetInteger( |
| prefs::kAutofillAcceptSaveCreditCardPromptState), |
| GetSecurityLevel(), GetSyncState()); |
| pref_service_->SetInteger( |
| prefs::kAutofillAcceptSaveCreditCardPromptState, |
| prefs::PREVIOUS_SAVE_CREDIT_CARD_PROMPT_USER_DECISION_ACCEPTED); |
| } |
| } |
| |
| void SaveCardBubbleControllerImpl::OnCancelButton() { |
| // Should only be applicable for non-material UI, |
| // as Harmony dialogs do not have [No thanks] buttons. |
| const BubbleType previous_bubble_type = current_bubble_type_; |
| current_bubble_type_ = BubbleType::INACTIVE; |
| upload_save_card_callback_.Reset(); |
| local_save_card_callback_.Reset(); |
| |
| if (previous_bubble_type == BubbleType::LOCAL_SAVE || |
| previous_bubble_type == BubbleType::UPLOAD_SAVE) { |
| AutofillMetrics::LogSaveCardPromptMetric( |
| AutofillMetrics::SAVE_CARD_PROMPT_END_DENIED, is_upload_save_, |
| is_reshow_, should_request_name_from_user_, |
| should_request_expiration_date_from_user_, |
| pref_service_->GetInteger( |
| prefs::kAutofillAcceptSaveCreditCardPromptState), |
| GetSecurityLevel(), GetSyncState()); |
| pref_service_->SetInteger( |
| prefs::kAutofillAcceptSaveCreditCardPromptState, |
| prefs::PREVIOUS_SAVE_CREDIT_CARD_PROMPT_USER_DECISION_DENIED); |
| if (show_bubble_ && |
| base::FeatureList::IsEnabled( |
| features::kAutofillSaveCreditCardUsesStrikeSystem)) { |
| // If save was cancelled and the bubble was actually shown (NOT just the |
| // icon), count that as a strike against offering save in the future. |
| LegacyStrikeDatabase* strike_database = GetLegacyStrikeDatabase(); |
| strike_database->AddStrike( |
| strike_database->GetKeyForCreditCardSave( |
| base::UTF16ToUTF8(card_.LastFourDigits())), |
| base::BindRepeating( |
| &SaveCardBubbleControllerImpl::OnStrikeChangeComplete, |
| weak_ptr_factory_.GetWeakPtr())); |
| } |
| } |
| } |
| |
| void SaveCardBubbleControllerImpl::OnLegalMessageLinkClicked(const GURL& url) { |
| OpenUrl(url); |
| AutofillMetrics::LogSaveCardPromptMetric( |
| AutofillMetrics::SAVE_CARD_PROMPT_DISMISS_CLICK_LEGAL_MESSAGE, |
| is_upload_save_, is_reshow_, should_request_name_from_user_, |
| should_request_expiration_date_from_user_, |
| pref_service_->GetInteger( |
| prefs::kAutofillAcceptSaveCreditCardPromptState), |
| GetSecurityLevel(), GetSyncState()); |
| } |
| |
| void SaveCardBubbleControllerImpl::OnManageCardsClicked() { |
| DCHECK(current_bubble_type_ == BubbleType::MANAGE_CARDS); |
| |
| AutofillMetrics::LogManageCardsPromptMetric( |
| AutofillMetrics::MANAGE_CARDS_MANAGE_CARDS, is_upload_save_); |
| |
| ShowPaymentsSettingsPage(); |
| } |
| |
| void SaveCardBubbleControllerImpl::ShowPaymentsSettingsPage() { |
| chrome::ShowSettingsSubPage( |
| chrome::FindBrowserWithWebContents(web_contents()), |
| chrome::kPaymentsSubPage); |
| } |
| |
| void SaveCardBubbleControllerImpl::OnBubbleClosed() { |
| save_card_bubble_view_ = nullptr; |
| // Sign-in promo should only be shown once, so if it was displayed presently, |
| // reopening the bubble will show the card management bubble. |
| if (current_bubble_type_ == BubbleType::SIGN_IN_PROMO) |
| current_bubble_type_ = BubbleType::MANAGE_CARDS; |
| UpdateIcon(); |
| if (observer_for_testing_) |
| observer_for_testing_->OnBubbleClosed(); |
| } |
| |
| void SaveCardBubbleControllerImpl::OnAnimationEnded() { |
| // Do not repeat the animation next time UpdateIcon() is called, unless |
| // explicitly set somewhere else. |
| can_animate_ = false; |
| |
| // We do not want to show the promo if the user clicked on the icon and the |
| // manage cards bubble started to show. |
| if (!save_card_bubble_view_) |
| ShowBubbleForSignInPromo(); |
| } |
| |
| const LegalMessageLines& SaveCardBubbleControllerImpl::GetLegalMessageLines() |
| const { |
| return legal_message_lines_; |
| } |
| |
| bool SaveCardBubbleControllerImpl::IsUploadSave() const { |
| return is_upload_save_; |
| } |
| |
| BubbleType SaveCardBubbleControllerImpl::GetBubbleType() const { |
| return current_bubble_type_; |
| } |
| |
| void SaveCardBubbleControllerImpl::DidFinishNavigation( |
| content::NavigationHandle* navigation_handle) { |
| if (!navigation_handle->IsInMainFrame() || !navigation_handle->HasCommitted()) |
| return; |
| |
| // Nothing to do if there's no bubble available. |
| if (current_bubble_type_ == BubbleType::INACTIVE) |
| return; |
| |
| // Don't react to same-document (fragment) navigations. |
| if (navigation_handle->IsSameDocument()) |
| return; |
| |
| // Don't do anything if a navigation occurs before a user could reasonably |
| // interact with the bubble. |
| const base::TimeDelta elapsed_time = |
| AutofillClock::Now() - bubble_shown_timestamp_; |
| if (elapsed_time < kCardBubbleSurviveNavigationTime) |
| return; |
| |
| // Otherwise, get rid of the bubble and icon. |
| const BubbleType previous_bubble_type = current_bubble_type_; |
| current_bubble_type_ = BubbleType::INACTIVE; |
| |
| upload_save_card_callback_.Reset(); |
| local_save_card_callback_.Reset(); |
| bool bubble_was_visible = save_card_bubble_view_; |
| if (bubble_was_visible) { |
| save_card_bubble_view_->Hide(); |
| OnBubbleClosed(); |
| } else { |
| UpdateIcon(); |
| } |
| |
| if (previous_bubble_type == BubbleType::LOCAL_SAVE || |
| previous_bubble_type == BubbleType::UPLOAD_SAVE) { |
| AutofillMetrics::LogSaveCardPromptMetric( |
| bubble_was_visible |
| ? AutofillMetrics::SAVE_CARD_PROMPT_END_NAVIGATION_SHOWING |
| : AutofillMetrics::SAVE_CARD_PROMPT_END_NAVIGATION_HIDDEN, |
| is_upload_save_, is_reshow_, should_request_name_from_user_, |
| should_request_expiration_date_from_user_, |
| pref_service_->GetInteger( |
| prefs::kAutofillAcceptSaveCreditCardPromptState), |
| GetSecurityLevel(), GetSyncState()); |
| if (base::FeatureList::IsEnabled( |
| features::kAutofillSaveCreditCardUsesStrikeSystem) && |
| show_bubble_) { |
| // If the save offer was ignored and the bubble was actually shown (NOT |
| // just the icon), count that as a strike against offering save in the |
| // future. |
| LegacyStrikeDatabase* strike_database = GetLegacyStrikeDatabase(); |
| strike_database->AddStrike( |
| strike_database->GetKeyForCreditCardSave( |
| base::UTF16ToUTF8(card_.LastFourDigits())), |
| base::BindRepeating( |
| &SaveCardBubbleControllerImpl::OnStrikeChangeComplete, |
| weak_ptr_factory_.GetWeakPtr())); |
| } |
| } |
| } |
| |
| void SaveCardBubbleControllerImpl::OnVisibilityChanged( |
| content::Visibility visibility) { |
| if (visibility == content::Visibility::HIDDEN) |
| HideBubble(); |
| } |
| |
| void SaveCardBubbleControllerImpl::WebContentsDestroyed() { |
| HideBubble(); |
| } |
| |
| void SaveCardBubbleControllerImpl::FetchAccountInfo() { |
| Profile* profile = GetProfile(); |
| if (!profile) |
| return; |
| auto* identity_manager = IdentityManagerFactory::GetForProfile(profile); |
| if (!identity_manager) |
| return; |
| account_info_ = identity_manager->GetPrimaryAccountInfo(); |
| } |
| |
| LegacyStrikeDatabase* SaveCardBubbleControllerImpl::GetLegacyStrikeDatabase() { |
| Profile* profile = GetProfile(); |
| // No need to return a LegacyStrikeDatabase in incognito mode. We don't allow |
| // saving of Autofill data while in incognito, so an incognito code path |
| // should never get this far. |
| DCHECK(profile && !profile->IsOffTheRecord()); |
| return LegacyStrikeDatabaseFactory::GetForProfile(profile); |
| } |
| |
| void SaveCardBubbleControllerImpl::ShowBubble() { |
| DCHECK(current_bubble_type_ != BubbleType::INACTIVE); |
| // Upload save callback should not be null for UPLOAD_SAVE state. |
| DCHECK(!(upload_save_card_callback_.is_null() && |
| current_bubble_type_ == BubbleType::UPLOAD_SAVE)); |
| // Local save callback should not be null for LOCAL_SAVE state. |
| DCHECK(!(local_save_card_callback_.is_null() && |
| current_bubble_type_ == BubbleType::LOCAL_SAVE)); |
| DCHECK(!save_card_bubble_view_); |
| |
| // Need to create location bar icon before bubble, otherwise bubble will be |
| // unanchored. |
| UpdateIcon(); |
| |
| Browser* browser = chrome::FindBrowserWithWebContents(web_contents()); |
| save_card_bubble_view_ = browser->window()->ShowSaveCreditCardBubble( |
| web_contents(), this, is_reshow_); |
| DCHECK(save_card_bubble_view_); |
| |
| // Update icon after creating |save_card_bubble_view_| so that icon will show |
| // its "toggled on" state. |
| UpdateIcon(); |
| |
| bubble_shown_timestamp_ = AutofillClock::Now(); |
| |
| switch (current_bubble_type_) { |
| case BubbleType::UPLOAD_SAVE: |
| case BubbleType::LOCAL_SAVE: |
| AutofillMetrics::LogSaveCardPromptMetric( |
| AutofillMetrics::SAVE_CARD_PROMPT_SHOWN, is_upload_save_, is_reshow_, |
| should_request_name_from_user_, |
| should_request_expiration_date_from_user_, |
| pref_service_->GetInteger( |
| prefs::kAutofillAcceptSaveCreditCardPromptState), |
| GetSecurityLevel(), GetSyncState()); |
| break; |
| case BubbleType::MANAGE_CARDS: |
| AutofillMetrics::LogManageCardsPromptMetric( |
| AutofillMetrics::MANAGE_CARDS_SHOWN, is_upload_save_); |
| break; |
| case BubbleType::SIGN_IN_PROMO: |
| break; |
| case BubbleType::INACTIVE: |
| NOTREACHED(); |
| } |
| |
| if (observer_for_testing_) { |
| observer_for_testing_->OnBubbleShown(); |
| } |
| } |
| |
| void SaveCardBubbleControllerImpl::ShowIconOnly() { |
| DCHECK(current_bubble_type_ != BubbleType::INACTIVE); |
| // Upload save callback should not be null for UPLOAD_SAVE state. |
| DCHECK(!(upload_save_card_callback_.is_null() && |
| current_bubble_type_ == BubbleType::UPLOAD_SAVE)); |
| // Local save callback should not be null for LOCAL_SAVE state. |
| DCHECK(!(local_save_card_callback_.is_null() && |
| current_bubble_type_ == BubbleType::LOCAL_SAVE)); |
| DCHECK(!save_card_bubble_view_); |
| |
| // Show the icon only. The bubble can still be displayed if the user |
| // explicitly clicks the icon. |
| UpdateIcon(); |
| |
| bubble_shown_timestamp_ = AutofillClock::Now(); |
| |
| switch (current_bubble_type_) { |
| case BubbleType::UPLOAD_SAVE: |
| case BubbleType::LOCAL_SAVE: |
| AutofillMetrics::LogSaveCardPromptMetric( |
| AutofillMetrics::SAVE_CARD_ICON_SHOWN_WITHOUT_PROMPT, is_upload_save_, |
| is_reshow_, should_request_name_from_user_, |
| should_request_expiration_date_from_user_, |
| pref_service_->GetInteger( |
| prefs::kAutofillAcceptSaveCreditCardPromptState), |
| GetSecurityLevel(), GetSyncState()); |
| break; |
| case BubbleType::MANAGE_CARDS: |
| case BubbleType::SIGN_IN_PROMO: |
| case BubbleType::INACTIVE: |
| NOTREACHED(); |
| } |
| } |
| |
| void SaveCardBubbleControllerImpl::UpdateIcon() { |
| Browser* browser = chrome::FindBrowserWithWebContents(web_contents()); |
| if (!browser) |
| return; |
| LocationBar* location_bar = browser->window()->GetLocationBar(); |
| location_bar->UpdateSaveCreditCardIcon(); |
| } |
| |
| void SaveCardBubbleControllerImpl::OpenUrl(const GURL& url) { |
| web_contents()->OpenURL(content::OpenURLParams( |
| url, content::Referrer(), WindowOpenDisposition::NEW_FOREGROUND_TAB, |
| ui::PAGE_TRANSITION_LINK, false)); |
| } |
| |
| void SaveCardBubbleControllerImpl::OnStrikeChangeComplete( |
| const int num_strikes) { |
| if (observer_for_testing_) |
| observer_for_testing_->OnSCBCStrikeChangeComplete(); |
| } |
| |
| security_state::SecurityLevel SaveCardBubbleControllerImpl::GetSecurityLevel() |
| const { |
| return security_level_; |
| } |
| |
| AutofillSyncSigninState SaveCardBubbleControllerImpl::GetSyncState() const { |
| return personal_data_manager_->GetSyncSigninState(); |
| } |
| |
| } // namespace autofill |