1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/ui/autofill/generated_credit_card_bubble_controller.h"
9 #include "base/logging.h"
10 #include "base/prefs/pref_service.h"
11 #include "base/strings/string_split.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "chrome/browser/profiles/profile.h"
14 #include "chrome/browser/ui/autofill/generated_credit_card_bubble_view.h"
15 #include "chrome/browser/ui/autofill/tab_autofill_manager_delegate.h"
16 #include "chrome/browser/ui/browser_finder.h"
17 #include "chrome/browser/ui/browser_navigator.h"
18 #include "chrome/browser/ui/browser_window.h"
19 #include "chrome/browser/ui/omnibox/location_bar.h"
20 #include "chrome/browser/ui/tabs/tab_strip_model.h"
21 #include "chrome/common/pref_names.h"
22 #include "components/user_prefs/pref_registry_syncable.h"
23 #include "content/public/browser/navigation_details.h"
24 #include "content/public/browser/navigation_entry.h"
25 #include "content/public/browser/web_contents.h"
26 #include "grit/generated_resources.h"
27 #include "grit/theme_resources.h"
28 #include "ui/base/l10n/l10n_util.h"
29 #include "ui/base/resource/resource_bundle.h"
31 DEFINE_WEB_CONTENTS_USER_DATA_KEY(
32 autofill::GeneratedCreditCardBubbleController
);
38 static const int kMaxGeneratedCardTimesToShow
= INT_MAX
;
39 static const base::char16 kRangeSeparator
= '|';
40 static const char kWalletGeneratedCardLearnMoreLink
[] =
41 "http://support.google.com/wallet/bin/answer.py?hl=en&answer=2740044";
43 GeneratedCreditCardBubbleController
* GetOrCreate(content::WebContents
* wc
) {
44 GeneratedCreditCardBubbleController::CreateForWebContents(wc
);
45 return GeneratedCreditCardBubbleController::FromWebContents(wc
);
50 bool TextRange::operator==(const TextRange
& other
) const {
51 return other
.range
== range
&& other
.is_link
== is_link
;
54 GeneratedCreditCardBubbleController::GeneratedCreditCardBubbleController(
55 content::WebContents
* web_contents
)
56 : WebContentsObserver(web_contents
),
57 web_contents_(web_contents
),
58 title_text_(l10n_util::GetStringUTF16(
59 IDS_AUTOFILL_GENERATED_CREDIT_CARD_BUBBLE_TITLE
)),
60 should_show_anchor_(true),
61 weak_ptr_factory_(this) {}
63 GeneratedCreditCardBubbleController::~GeneratedCreditCardBubbleController() {
64 // In the case that the tab is closed, the controller can be deleted while
65 // bubble is showing. Always calling |Hide()| ensures that the bubble closes.
70 void GeneratedCreditCardBubbleController::RegisterUserPrefs(
71 user_prefs::PrefRegistrySyncable
* registry
) {
72 registry
->RegisterIntegerPref(
73 ::prefs::kAutofillGeneratedCardBubbleTimesShown
,
75 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF
);
79 void GeneratedCreditCardBubbleController::Show(
80 content::WebContents
* contents
,
81 const base::string16
& fronting_card_name
,
82 const base::string16
& backing_card_name
) {
83 GetOrCreate(contents
)->SetupAndShow(fronting_card_name
, backing_card_name
);
86 void GeneratedCreditCardBubbleController::DidNavigateMainFrame(
87 const content::LoadCommittedDetails
& details
,
88 const content::FrameNavigateParams
& params
) {
92 // Don't destory the bubble due to reloads, form submits, or redirects right
93 // after the dialog succeeds. Merchants often navigate to a confirmation page.
94 content::PageTransition transition
= details
.entry
->GetTransitionType();
95 if (transition
== content::PAGE_TRANSITION_FORM_SUBMIT
||
96 transition
== content::PAGE_TRANSITION_RELOAD
||
97 content::PageTransitionIsRedirect(transition
)) {
101 should_show_anchor_
= false;
103 web_contents()->RemoveUserData(UserDataKey());
104 // |this| is now deleted.
107 bool GeneratedCreditCardBubbleController::IsHiding() const {
108 return bubble_
&& bubble_
->IsHiding();
111 gfx::Image
GeneratedCreditCardBubbleController::AnchorIcon() const {
112 if (!should_show_anchor_
)
114 return ui::ResourceBundle::GetSharedInstance().GetImageNamed(IDR_WALLET_ICON
);
117 const base::string16
& GeneratedCreditCardBubbleController::TitleText() const {
121 const base::string16
& GeneratedCreditCardBubbleController::ContentsText()
123 return contents_text_
;
126 const std::vector
<TextRange
>& GeneratedCreditCardBubbleController::
127 ContentsTextRanges() const {
128 return contents_text_ranges_
;
131 void GeneratedCreditCardBubbleController::OnAnchorClicked() {
135 void GeneratedCreditCardBubbleController::OnLinkClicked() {
136 // Open a new tab to the Online Wallet help link.
137 chrome::NavigateParams
params(
138 chrome::FindBrowserWithWebContents(web_contents()),
139 GURL(kWalletGeneratedCardLearnMoreLink
),
140 content::PAGE_TRANSITION_AUTO_BOOKMARK
);
141 params
.disposition
= NEW_FOREGROUND_TAB
;
142 chrome::Navigate(¶ms
);
147 base::WeakPtr
<GeneratedCreditCardBubbleController
>
148 GeneratedCreditCardBubbleController::GetWeakPtr() {
149 return weak_ptr_factory_
.GetWeakPtr();
152 base::WeakPtr
<GeneratedCreditCardBubbleView
>
153 GeneratedCreditCardBubbleController::CreateBubble() {
154 return GeneratedCreditCardBubbleView::Create(GetWeakPtr());
157 base::WeakPtr
<GeneratedCreditCardBubbleView
>
158 GeneratedCreditCardBubbleController::bubble() {
162 bool GeneratedCreditCardBubbleController::CanShow() const {
163 Browser
* browser
= chrome::FindBrowserWithWebContents(web_contents());
164 return web_contents() == browser
->tab_strip_model()->GetActiveWebContents();
167 bool GeneratedCreditCardBubbleController::ShouldDisplayBubbleInitially() const {
168 Profile
* profile
= Profile::FromBrowserContext(
169 web_contents_
->GetBrowserContext());
170 int times_shown
= profile
->GetPrefs()->GetInteger(
171 ::prefs::kAutofillGeneratedCardBubbleTimesShown
);
172 return times_shown
< kMaxGeneratedCardTimesToShow
;
175 void GeneratedCreditCardBubbleController::SetupAndShow(
176 const base::string16
& fronting_card_name
,
177 const base::string16
& backing_card_name
) {
178 DCHECK(!fronting_card_name
.empty());
179 DCHECK(!backing_card_name
.empty());
181 fronting_card_name_
= fronting_card_name
;
182 backing_card_name_
= backing_card_name
;
184 // Clear any generated state or from the last |SetupAndShow()| call.
185 contents_text_
.clear();
186 contents_text_ranges_
.clear();
188 base::string16 to_split
= l10n_util::GetStringFUTF16(
189 IDS_AUTOFILL_GENERATED_CREDIT_CARD_BUBBLE_CONTENTS
,
193 // Split the full text on '|' to highlight certain parts. For example, "sly"
194 // and "jumped" would be bolded in "The |sly| fox |jumped| over the lazy dog".
195 std::vector
<base::string16
> pieces
;
196 base::SplitStringDontTrim(to_split
, kRangeSeparator
, &pieces
);
198 while (!pieces
.empty()) {
199 base::string16 piece
= pieces
.front();
201 // Every second piece should be bolded. Because |base::SplitString*()|
202 // leaves an empty "" even if '|' is the first character, this is guaranteed
203 // to work for "|highlighting| starts here". Ignore empty pieces because
204 // there's nothing to highlight.
205 if (!piece
.empty() && pieces
.size() % 2 == 0) {
206 const size_t start
= contents_text_
.size();
208 bold_text
.range
= gfx::Range(start
, start
+ piece
.size());
209 bold_text
.is_link
= false;
210 contents_text_ranges_
.push_back(bold_text
);
213 // Append the piece whether it's bolded or not and move on to the next one.
214 contents_text_
.append(piece
);
215 pieces
.erase(pieces
.begin(), pieces
.begin() + 1);
218 // Add a "Learn more" link at the end of the header text if it's a generated
220 base::string16 learn_more
= l10n_util::GetStringUTF16(IDS_LEARN_MORE
);
221 contents_text_
.append(base::ASCIIToUTF16(" ") + learn_more
);
222 const size_t header_size
= contents_text_
.size();
224 end_link
.range
= gfx::Range(header_size
- learn_more
.size(), header_size
);
225 end_link
.is_link
= true;
226 contents_text_ranges_
.push_back(end_link
);
230 if (ShouldDisplayBubbleInitially())
234 void GeneratedCreditCardBubbleController::Show(bool was_anchor_click
) {
240 bubble_
= CreateBubble();
242 // TODO(dbeam): Make a bubble on all applicable platforms.
248 if (!was_anchor_click
) {
249 // If the bubble was an automatically created "you generated a card" bubble,
250 // count it as a show. If the user clicked the omnibox icon, don't count it.
251 PrefService
* prefs
= Profile::FromBrowserContext(
252 web_contents()->GetBrowserContext())->GetPrefs();
253 prefs
->SetInteger(::prefs::kAutofillGeneratedCardBubbleTimesShown
,
254 prefs
->GetInteger(::prefs::kAutofillGeneratedCardBubbleTimesShown
) + 1);
258 void GeneratedCreditCardBubbleController::UpdateAnchor() {
259 Browser
* browser
= chrome::FindBrowserWithWebContents(web_contents());
260 if (browser
&& browser
->window() && browser
->window()->GetLocationBar())
261 browser
->window()->GetLocationBar()->UpdateGeneratedCreditCardView();
264 void GeneratedCreditCardBubbleController::Hide() {
265 if (bubble_
&& !bubble_
->IsHiding())
269 } // namespace autofill