blob: 36d8ced0ffc8f24a365967815e654ec1993bd14a [file] [log] [blame]
// Copyright 2013 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/generated_credit_card_bubble_controller.h"
#include <climits>
#include "base/logging.h"
#include "base/prefs/pref_service.h"
#include "base/strings/string_split.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/autofill/generated_credit_card_bubble_view.h"
#include "chrome/browser/ui/autofill/tab_autofill_manager_delegate.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_navigator.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/omnibox/location_bar.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/common/pref_names.h"
#include "components/user_prefs/pref_registry_syncable.h"
#include "content/public/browser/navigation_details.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/web_contents.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
DEFINE_WEB_CONTENTS_USER_DATA_KEY(
autofill::GeneratedCreditCardBubbleController);
namespace autofill {
namespace {
static const int kMaxGeneratedCardTimesToShow = INT_MAX;
static const base::char16 kRangeSeparator = '|';
static const char kWalletGeneratedCardLearnMoreLink[] =
"http://support.google.com/wallet/bin/answer.py?hl=en&answer=2740044";
GeneratedCreditCardBubbleController* GetOrCreate(content::WebContents* wc) {
GeneratedCreditCardBubbleController::CreateForWebContents(wc);
return GeneratedCreditCardBubbleController::FromWebContents(wc);
}
} // namespace
bool TextRange::operator==(const TextRange& other) const {
return other.range == range && other.is_link == is_link;
}
GeneratedCreditCardBubbleController::GeneratedCreditCardBubbleController(
content::WebContents* web_contents)
: WebContentsObserver(web_contents),
web_contents_(web_contents),
title_text_(l10n_util::GetStringUTF16(
IDS_AUTOFILL_GENERATED_CREDIT_CARD_BUBBLE_TITLE)),
should_show_anchor_(true),
weak_ptr_factory_(this) {}
GeneratedCreditCardBubbleController::~GeneratedCreditCardBubbleController() {
// In the case that the tab is closed, the controller can be deleted while
// bubble is showing. Always calling |Hide()| ensures that the bubble closes.
Hide();
}
// static
void GeneratedCreditCardBubbleController::RegisterUserPrefs(
user_prefs::PrefRegistrySyncable* registry) {
registry->RegisterIntegerPref(
::prefs::kAutofillGeneratedCardBubbleTimesShown,
0,
user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
}
// static
void GeneratedCreditCardBubbleController::Show(
content::WebContents* contents,
const base::string16& fronting_card_name,
const base::string16& backing_card_name) {
GetOrCreate(contents)->SetupAndShow(fronting_card_name, backing_card_name);
}
void GeneratedCreditCardBubbleController::DidNavigateMainFrame(
const content::LoadCommittedDetails& details,
const content::FrameNavigateParams& params) {
if (details.entry &&
!content::PageTransitionIsRedirect(details.entry->GetTransitionType())) {
should_show_anchor_ = false;
UpdateAnchor();
web_contents()->RemoveUserData(UserDataKey());
// |this| is now deleted.
}
}
bool GeneratedCreditCardBubbleController::IsHiding() const {
return bubble_ && bubble_->IsHiding();
}
gfx::Image GeneratedCreditCardBubbleController::AnchorIcon() const {
if (!should_show_anchor_)
return gfx::Image();
return ui::ResourceBundle::GetSharedInstance().GetImageNamed(IDR_WALLET_ICON);
}
const base::string16& GeneratedCreditCardBubbleController::TitleText() const {
return title_text_;
}
const base::string16& GeneratedCreditCardBubbleController::ContentsText()
const {
return contents_text_;
}
const std::vector<TextRange>& GeneratedCreditCardBubbleController::
ContentsTextRanges() const {
return contents_text_ranges_;
}
void GeneratedCreditCardBubbleController::OnAnchorClicked() {
Show(true);
}
void GeneratedCreditCardBubbleController::OnLinkClicked() {
// Open a new tab to the Online Wallet help link.
chrome::NavigateParams params(
chrome::FindBrowserWithWebContents(web_contents()),
GURL(kWalletGeneratedCardLearnMoreLink),
content::PAGE_TRANSITION_AUTO_BOOKMARK);
params.disposition = NEW_FOREGROUND_TAB;
chrome::Navigate(&params);
Hide();
}
base::WeakPtr<GeneratedCreditCardBubbleController>
GeneratedCreditCardBubbleController::GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
base::WeakPtr<GeneratedCreditCardBubbleView>
GeneratedCreditCardBubbleController::CreateBubble() {
return GeneratedCreditCardBubbleView::Create(GetWeakPtr());
}
base::WeakPtr<GeneratedCreditCardBubbleView>
GeneratedCreditCardBubbleController::bubble() {
return bubble_;
}
bool GeneratedCreditCardBubbleController::CanShow() const {
Browser* browser = chrome::FindBrowserWithWebContents(web_contents());
return web_contents() == browser->tab_strip_model()->GetActiveWebContents();
}
bool GeneratedCreditCardBubbleController::ShouldDisplayBubbleInitially() const {
Profile* profile = Profile::FromBrowserContext(
web_contents_->GetBrowserContext());
int times_shown = profile->GetPrefs()->GetInteger(
::prefs::kAutofillGeneratedCardBubbleTimesShown);
return times_shown < kMaxGeneratedCardTimesToShow;
}
void GeneratedCreditCardBubbleController::SetupAndShow(
const base::string16& fronting_card_name,
const base::string16& backing_card_name) {
DCHECK(!fronting_card_name.empty());
DCHECK(!backing_card_name.empty());
fronting_card_name_ = fronting_card_name;
backing_card_name_ = backing_card_name;
// Clear any generated state or from the last |SetupAndShow()| call.
contents_text_.clear();
contents_text_ranges_.clear();
base::string16 to_split = l10n_util::GetStringFUTF16(
IDS_AUTOFILL_GENERATED_CREDIT_CARD_BUBBLE_CONTENTS,
fronting_card_name_,
backing_card_name_);
// Split the full text on '|' to highlight certain parts. For example, "sly"
// and "jumped" would be bolded in "The |sly| fox |jumped| over the lazy dog".
std::vector<base::string16> pieces;
base::SplitStringDontTrim(to_split, kRangeSeparator, &pieces);
while (!pieces.empty()) {
base::string16 piece = pieces.front();
// Every second piece should be bolded. Because |base::SplitString*()|
// leaves an empty "" even if '|' is the first character, this is guaranteed
// to work for "|highlighting| starts here". Ignore empty pieces because
// there's nothing to highlight.
if (!piece.empty() && pieces.size() % 2 == 0) {
const size_t start = contents_text_.size();
TextRange bold_text;
bold_text.range = ui::Range(start, start + piece.size());
bold_text.is_link = false;
contents_text_ranges_.push_back(bold_text);
}
// Append the piece whether it's bolded or not and move on to the next one.
contents_text_.append(piece);
pieces.erase(pieces.begin(), pieces.begin() + 1);
}
// Add a "Learn more" link at the end of the header text if it's a generated
// card bubble.
base::string16 learn_more = l10n_util::GetStringUTF16(IDS_LEARN_MORE);
contents_text_.append(ASCIIToUTF16(" ") + learn_more);
const size_t header_size = contents_text_.size();
TextRange end_link;
end_link.range = ui::Range(header_size - learn_more.size(), header_size);
end_link.is_link = true;
contents_text_ranges_.push_back(end_link);
UpdateAnchor();
if (ShouldDisplayBubbleInitially())
Show(false);
}
void GeneratedCreditCardBubbleController::Show(bool was_anchor_click) {
Hide();
if (!CanShow())
return;
bubble_ = CreateBubble();
if (!bubble_) {
// TODO(dbeam): Make a bubble on all applicable platforms.
return;
}
bubble_->Show();
if (!was_anchor_click) {
// If the bubble was an automatically created "you generated a card" bubble,
// count it as a show. If the user clicked the omnibox icon, don't count it.
PrefService* prefs = Profile::FromBrowserContext(
web_contents()->GetBrowserContext())->GetPrefs();
prefs->SetInteger(::prefs::kAutofillGeneratedCardBubbleTimesShown,
prefs->GetInteger(::prefs::kAutofillGeneratedCardBubbleTimesShown) + 1);
}
}
void GeneratedCreditCardBubbleController::UpdateAnchor() {
Browser* browser = chrome::FindBrowserWithWebContents(web_contents());
if (browser && browser->window() && browser->window()->GetLocationBar())
browser->window()->GetLocationBar()->UpdateGeneratedCreditCardView();
}
void GeneratedCreditCardBubbleController::Hide() {
if (bubble_ && !bubble_->IsHiding())
bubble_->Hide();
}
} // namespace autofill