blob: 016dd3a3f8db3af4575bd022dd8b43472524b216 [file] [log] [blame]
// 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 "chrome/browser/profiles/profile.h"
#include "chrome/browser/signin/account_tracker_service_factory.h"
#include "chrome/browser/signin/signin_manager_factory.h"
#include "chrome/browser/ssl/security_state_tab_helper.h"
#include "chrome/browser/ui/autofill/popup_constants.h"
#include "chrome/browser/ui/autofill/save_card_bubble_view.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/location_bar/location_bar.h"
#include "components/autofill/core/browser/autofill_experiments.h"
#include "components/autofill/core/browser/autofill_metrics.h"
#include "components/autofill/core/common/autofill_pref_names.h"
#include "components/prefs/pref_service.h"
#include "components/signin/core/browser/account_tracker_service.h"
#include "components/signin/core/browser/signin_manager_base.h"
#include "components/strings/grit/components_strings.h"
#include "components/user_prefs/user_prefs.h"
#include "content/public/browser/navigation_handle.h"
#include "ui/base/l10n/l10n_util.h"
DEFINE_WEB_CONTENTS_USER_DATA_KEY(autofill::SaveCardBubbleControllerImpl);
namespace autofill {
SaveCardBubbleControllerImpl::SaveCardBubbleControllerImpl(
content::WebContents* web_contents)
: content::WebContentsObserver(web_contents),
web_contents_(web_contents),
save_card_bubble_view_(nullptr),
pref_service_(
user_prefs::UserPrefs::Get(web_contents->GetBrowserContext())) {
security_state::SecurityInfo security_info;
SecurityStateTabHelper::FromWebContents(web_contents)
->GetSecurityInfo(&security_info);
security_level_ = security_info.security_level;
}
SaveCardBubbleControllerImpl::~SaveCardBubbleControllerImpl() {
if (save_card_bubble_view_)
save_card_bubble_view_->Hide();
}
void SaveCardBubbleControllerImpl::ShowBubbleForLocalSave(
const CreditCard& card,
const base::Closure& save_card_callback) {
// Don't show the bubble if it's already visible.
if (save_card_bubble_view_)
return;
is_uploading_ = false;
is_reshow_ = false;
should_request_name_from_user_ = false;
legal_message_lines_.clear();
AutofillMetrics::LogSaveCardPromptMetric(
AutofillMetrics::SAVE_CARD_PROMPT_SHOW_REQUESTED, is_uploading_,
is_reshow_, should_request_name_from_user_,
pref_service_->GetInteger(
prefs::kAutofillAcceptSaveCreditCardPromptState),
GetSecurityLevel());
card_ = card;
local_save_card_callback_ = save_card_callback;
ShowBubble();
}
void SaveCardBubbleControllerImpl::ShowBubbleForUpload(
const CreditCard& card,
std::unique_ptr<base::DictionaryValue> legal_message,
bool should_request_name_from_user,
base::OnceCallback<void(const base::string16&)> 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_uploading_ = true;
is_reshow_ = false;
should_request_name_from_user_ = should_request_name_from_user;
AutofillMetrics::LogSaveCardPromptMetric(
AutofillMetrics::SAVE_CARD_PROMPT_SHOW_REQUESTED, is_uploading_,
is_reshow_, should_request_name_from_user_,
pref_service_->GetInteger(
prefs::kAutofillAcceptSaveCreditCardPromptState),
GetSecurityLevel());
if (!LegalMessageLine::Parse(*legal_message, &legal_message_lines_,
/*escape_apostrophes=*/true)) {
AutofillMetrics::LogSaveCardPromptMetric(
AutofillMetrics::SAVE_CARD_PROMPT_END_INVALID_LEGAL_MESSAGE,
is_uploading_, is_reshow_, should_request_name_from_user_,
pref_service_->GetInteger(
prefs::kAutofillAcceptSaveCreditCardPromptState),
GetSecurityLevel());
return;
}
card_ = card;
upload_save_card_callback_ = std::move(save_card_callback);
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;
AutofillMetrics::LogSaveCardPromptMetric(
AutofillMetrics::SAVE_CARD_PROMPT_SHOW_REQUESTED, is_uploading_,
is_reshow_, should_request_name_from_user_,
pref_service_->GetInteger(
prefs::kAutofillAcceptSaveCreditCardPromptState),
GetSecurityLevel());
ShowBubble();
}
bool SaveCardBubbleControllerImpl::IsIconVisible() const {
return !upload_save_card_callback_.is_null() ||
!local_save_card_callback_.is_null();
}
SaveCardBubbleView* SaveCardBubbleControllerImpl::save_card_bubble_view()
const {
return save_card_bubble_view_;
}
base::string16 SaveCardBubbleControllerImpl::GetWindowTitle() const {
return l10n_util::GetStringUTF16(
IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_TO_CLOUD_V3);
}
base::string16 SaveCardBubbleControllerImpl::GetExplanatoryMessage() const {
if (is_uploading_) {
if (should_request_name_from_user_) {
return l10n_util::GetStringUTF16(
IDS_AUTOFILL_SAVE_CARD_PROMPT_UPLOAD_EXPLANATION_V3_WITH_NAME);
}
return l10n_util::GetStringUTF16(
IsAutofillUpstreamUpdatePromptExplanationExperimentEnabled()
? IDS_AUTOFILL_SAVE_CARD_PROMPT_UPLOAD_EXPLANATION_V3
: IDS_AUTOFILL_SAVE_CARD_PROMPT_UPLOAD_EXPLANATION_V2);
}
return base::string16();
}
const AccountInfo& SaveCardBubbleControllerImpl::GetAccountInfo() const {
return account_info_;
}
const CreditCard& SaveCardBubbleControllerImpl::GetCard() const {
return card_;
}
bool SaveCardBubbleControllerImpl::ShouldRequestNameFromUser() const {
return should_request_name_from_user_;
}
void SaveCardBubbleControllerImpl::OnSaveButton(
const base::string16& cardholder_name) {
if (!upload_save_card_callback_.is_null()) {
base::string16 name_provided_by_user;
if (!cardholder_name.empty()) {
// 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(cardholder_name, base::TRIM_ALL,
&name_provided_by_user);
}
std::move(upload_save_card_callback_).Run(name_provided_by_user);
} else {
DCHECK(!local_save_card_callback_.is_null());
local_save_card_callback_.Run();
local_save_card_callback_.Reset();
}
AutofillMetrics::LogSaveCardPromptMetric(
AutofillMetrics::SAVE_CARD_PROMPT_END_ACCEPTED, is_uploading_, is_reshow_,
should_request_name_from_user_,
pref_service_->GetInteger(
prefs::kAutofillAcceptSaveCreditCardPromptState),
GetSecurityLevel());
pref_service_->SetInteger(
prefs::kAutofillAcceptSaveCreditCardPromptState,
prefs::PREVIOUS_SAVE_CREDIT_CARD_PROMPT_USER_DECISION_ACCEPTED);
}
void SaveCardBubbleControllerImpl::OnCancelButton() {
upload_save_card_callback_.Reset();
local_save_card_callback_.Reset();
AutofillMetrics::LogSaveCardPromptMetric(
AutofillMetrics::SAVE_CARD_PROMPT_END_DENIED, is_uploading_, is_reshow_,
should_request_name_from_user_,
pref_service_->GetInteger(
prefs::kAutofillAcceptSaveCreditCardPromptState),
GetSecurityLevel());
pref_service_->SetInteger(
prefs::kAutofillAcceptSaveCreditCardPromptState,
prefs::PREVIOUS_SAVE_CREDIT_CARD_PROMPT_USER_DECISION_DENIED);
}
void SaveCardBubbleControllerImpl::OnLegalMessageLinkClicked(const GURL& url) {
OpenUrl(url);
AutofillMetrics::LogSaveCardPromptMetric(
AutofillMetrics::SAVE_CARD_PROMPT_DISMISS_CLICK_LEGAL_MESSAGE,
is_uploading_, is_reshow_, should_request_name_from_user_,
pref_service_->GetInteger(
prefs::kAutofillAcceptSaveCreditCardPromptState),
GetSecurityLevel());
}
void SaveCardBubbleControllerImpl::OnBubbleClosed() {
save_card_bubble_view_ = nullptr;
UpdateIcon();
}
const LegalMessageLines& SaveCardBubbleControllerImpl::GetLegalMessageLines()
const {
return legal_message_lines_;
}
base::TimeDelta SaveCardBubbleControllerImpl::Elapsed() const {
return timer_->Elapsed();
}
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 (upload_save_card_callback_.is_null() &&
local_save_card_callback_.is_null()) {
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.
if (Elapsed() < kCardBubbleSurviveNavigationTime)
return;
// Otherwise, get rid of the bubble and icon.
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();
}
AutofillMetrics::LogSaveCardPromptMetric(
bubble_was_visible
? AutofillMetrics::SAVE_CARD_PROMPT_END_NAVIGATION_SHOWING
: AutofillMetrics::SAVE_CARD_PROMPT_END_NAVIGATION_HIDDEN,
is_uploading_, is_reshow_, should_request_name_from_user_,
pref_service_->GetInteger(
prefs::kAutofillAcceptSaveCreditCardPromptState),
GetSecurityLevel());
}
void SaveCardBubbleControllerImpl::OnVisibilityChanged(
content::Visibility visibility) {
if (visibility == content::Visibility::HIDDEN)
HideBubble();
}
void SaveCardBubbleControllerImpl::WebContentsDestroyed() {
HideBubble();
}
void SaveCardBubbleControllerImpl::FetchAccountInfo() {
Profile* profile =
Profile::FromBrowserContext(web_contents_->GetBrowserContext());
if (!profile)
return;
SigninManagerBase* signin_manager =
SigninManagerFactory::GetForProfile(profile);
AccountTrackerService* account_tracker =
AccountTrackerServiceFactory::GetForProfile(profile);
if (!signin_manager || !account_tracker)
return;
account_info_ = account_tracker->GetAccountInfo(
signin_manager->GetAuthenticatedAccountId());
}
void SaveCardBubbleControllerImpl::ShowBubble() {
DCHECK(!upload_save_card_callback_.is_null() ||
!local_save_card_callback_.is_null());
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();
timer_.reset(new base::ElapsedTimer());
AutofillMetrics::LogSaveCardPromptMetric(
AutofillMetrics::SAVE_CARD_PROMPT_SHOWN, is_uploading_, is_reshow_,
should_request_name_from_user_,
pref_service_->GetInteger(
prefs::kAutofillAcceptSaveCreditCardPromptState),
GetSecurityLevel());
}
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));
}
security_state::SecurityLevel SaveCardBubbleControllerImpl::GetSecurityLevel()
const {
return security_level_;
}
} // namespace autofill