1 // Copyright (c) 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/extensions/extension_message_bubble_controller.h"
8 #include "base/metrics/histogram.h"
9 #include "base/strings/string_number_conversions.h"
10 #include "base/strings/string_util.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "chrome/browser/extensions/extension_message_bubble.h"
13 #include "chrome/browser/profiles/profile.h"
14 #include "chrome/browser/ui/browser.h"
15 #include "chrome/browser/ui/browser_finder.h"
16 #include "chrome/browser/ui/toolbar/toolbar_actions_model.h"
17 #include "chrome/common/url_constants.h"
18 #include "content/public/browser/user_metrics.h"
19 #include "extensions/browser/extension_prefs.h"
20 #include "extensions/browser/extension_registry.h"
21 #include "extensions/browser/extension_system.h"
22 #include "grit/components_strings.h"
23 #include "ui/base/l10n/l10n_util.h"
25 namespace extensions
{
28 // How many extensions to show in the bubble (max).
29 const int kMaxExtensionsToShow
= 7;
31 // Whether or not to ignore the learn more link navigation for testing.
32 bool g_should_ignore_learn_more_for_testing
= false;
35 ////////////////////////////////////////////////////////////////////////////////
36 // ExtensionMessageBubbleController::Delegate
38 ExtensionMessageBubbleController::Delegate::Delegate(Profile
* profile
)
40 service_(ExtensionSystem::Get(profile
)->extension_service()),
41 registry_(ExtensionRegistry::Get(profile
)) {
44 ExtensionMessageBubbleController::Delegate::~Delegate() {
47 void ExtensionMessageBubbleController::Delegate::RestrictToSingleExtension(
48 const std::string
& extension_id
) {
49 NOTIMPLEMENTED(); // Derived classes that need this should implement.
52 base::string16
ExtensionMessageBubbleController::Delegate::GetLearnMoreLabel()
54 return l10n_util::GetStringUTF16(IDS_LEARN_MORE
);
57 bool ExtensionMessageBubbleController::Delegate::HasBubbleInfoBeenAcknowledged(
58 const std::string
& extension_id
) {
59 std::string pref_name
= get_acknowledged_flag_pref_name();
60 if (pref_name
.empty())
62 bool pref_state
= false;
63 extensions::ExtensionPrefs
* prefs
= extensions::ExtensionPrefs::Get(profile_
);
64 prefs
->ReadPrefAsBoolean(extension_id
, pref_name
, &pref_state
);
68 void ExtensionMessageBubbleController::Delegate::SetBubbleInfoBeenAcknowledged(
69 const std::string
& extension_id
,
71 std::string pref_name
= get_acknowledged_flag_pref_name();
72 if (pref_name
.empty())
74 extensions::ExtensionPrefs
* prefs
= extensions::ExtensionPrefs::Get(profile_
);
75 prefs
->UpdateExtensionPref(extension_id
,
77 value
? new base::FundamentalValue(value
) : NULL
);
81 ExtensionMessageBubbleController::Delegate::get_acknowledged_flag_pref_name()
83 return acknowledged_pref_name_
;
87 ExtensionMessageBubbleController::Delegate::set_acknowledged_flag_pref_name(
88 std::string pref_name
) {
89 acknowledged_pref_name_
= pref_name
;
92 ////////////////////////////////////////////////////////////////////////////////
93 // ExtensionMessageBubbleController
95 ExtensionMessageBubbleController::ExtensionMessageBubbleController(
99 user_action_(ACTION_BOUNDARY
),
102 did_highlight_(false) {
105 ExtensionMessageBubbleController::~ExtensionMessageBubbleController() {
108 Profile
* ExtensionMessageBubbleController::profile() {
109 return browser_
->profile();
112 std::vector
<base::string16
>
113 ExtensionMessageBubbleController::GetExtensionList() {
114 ExtensionIdList
* list
= GetOrCreateExtensionList();
116 return std::vector
<base::string16
>();
118 ExtensionRegistry
* registry
= ExtensionRegistry::Get(profile());
119 std::vector
<base::string16
> return_value
;
120 for (ExtensionIdList::const_iterator it
= list
->begin();
121 it
!= list
->end(); ++it
) {
122 const Extension
* extension
=
123 registry
->GetExtensionById(*it
, ExtensionRegistry::EVERYTHING
);
125 return_value
.push_back(base::UTF8ToUTF16(extension
->name()));
127 return_value
.push_back(
128 base::ASCIIToUTF16(std::string("(unknown name) ") + *it
));
129 // TODO(finnur): Add this as a string to the grd, for next milestone.
135 base::string16
ExtensionMessageBubbleController::GetExtensionListForDisplay() {
136 if (!delegate_
->ShouldShowExtensionList())
137 return base::string16();
139 std::vector
<base::string16
> extension_list
= GetExtensionList();
140 if (extension_list
.size() > kMaxExtensionsToShow
) {
141 int old_size
= extension_list
.size();
142 extension_list
.erase(extension_list
.begin() + kMaxExtensionsToShow
,
143 extension_list
.end());
144 extension_list
.push_back(delegate_
->GetOverflowText(base::IntToString16(
145 old_size
- kMaxExtensionsToShow
)));
147 const base::char16 bullet_point
= 0x2022;
148 base::string16 prefix
= bullet_point
+ base::ASCIIToUTF16(" ");
149 for (base::string16
& str
: extension_list
)
150 str
.insert(0, prefix
);
151 return base::JoinString(extension_list
, base::ASCIIToUTF16("\n"));
154 const ExtensionIdList
& ExtensionMessageBubbleController::GetExtensionIdList() {
155 return *GetOrCreateExtensionList();
158 bool ExtensionMessageBubbleController::CloseOnDeactivate() { return false; }
160 void ExtensionMessageBubbleController::HighlightExtensionsIfNecessary() {
161 if (delegate_
->ShouldHighlightExtensions() && !did_highlight_
) {
162 did_highlight_
= true;
163 const ExtensionIdList
& extension_ids
= GetExtensionIdList();
164 DCHECK(!extension_ids
.empty());
165 ToolbarActionsModel::Get(profile())->HighlightActions(
166 extension_ids
, ToolbarActionsModel::HIGHLIGHT_WARNING
);
170 void ExtensionMessageBubbleController::Show(ExtensionMessageBubble
* bubble
) {
174 void ExtensionMessageBubbleController::OnBubbleAction() {
175 DCHECK_EQ(ACTION_BOUNDARY
, user_action_
);
176 user_action_
= ACTION_EXECUTE
;
178 delegate_
->LogAction(ACTION_EXECUTE
);
179 delegate_
->PerformAction(*GetOrCreateExtensionList());
184 void ExtensionMessageBubbleController::OnBubbleDismiss() {
185 // OnBubbleDismiss() can be called twice when we receive multiple
186 // "OnWidgetDestroying" notifications (this can at least happen when we close
187 // a window with a notification open). Handle this gracefully.
188 if (user_action_
!= ACTION_BOUNDARY
) {
189 DCHECK(user_action_
== ACTION_DISMISS
);
193 user_action_
= ACTION_DISMISS
;
195 delegate_
->LogAction(ACTION_DISMISS
);
200 void ExtensionMessageBubbleController::OnLinkClicked() {
201 DCHECK_EQ(ACTION_BOUNDARY
, user_action_
);
202 user_action_
= ACTION_LEARN_MORE
;
204 delegate_
->LogAction(ACTION_LEARN_MORE
);
205 if (!g_should_ignore_learn_more_for_testing
) {
207 content::OpenURLParams(delegate_
->GetLearnMoreUrl(),
210 ui::PAGE_TRANSITION_LINK
,
217 void ExtensionMessageBubbleController::set_should_ignore_learn_more_for_testing(
218 bool should_ignore
) {
219 g_should_ignore_learn_more_for_testing
= should_ignore
;
222 void ExtensionMessageBubbleController::AcknowledgeExtensions() {
223 ExtensionIdList
* list
= GetOrCreateExtensionList();
224 for (ExtensionIdList::const_iterator it
= list
->begin();
225 it
!= list
->end(); ++it
)
226 delegate_
->AcknowledgeExtension(*it
, user_action_
);
229 ExtensionIdList
* ExtensionMessageBubbleController::GetOrCreateExtensionList() {
231 scoped_ptr
<const ExtensionSet
> extension_set(
232 ExtensionRegistry::Get(profile())->GenerateInstalledExtensionsSet());
233 for (ExtensionSet::const_iterator it
= extension_set
->begin();
234 it
!= extension_set
->end(); ++it
) {
235 std::string id
= (*it
)->id();
236 if (!delegate_
->ShouldIncludeExtension(id
))
238 extension_list_
.push_back(id
);
241 delegate_
->LogExtensionCount(extension_list_
.size());
245 return &extension_list_
;
248 void ExtensionMessageBubbleController::OnClose() {
249 AcknowledgeExtensions();
251 ToolbarActionsModel::Get(profile())->StopHighlighting();
254 } // namespace extensions