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/extensions/extension_toolbar_model.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/ui/browser.h"
16 #include "chrome/browser/ui/browser_finder.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 "grit/components_strings.h"
22 #include "ui/base/l10n/l10n_util.h"
24 namespace extensions
{
27 // How many extensions to show in the bubble (max).
28 const int kMaxExtensionsToShow
= 7;
31 ////////////////////////////////////////////////////////////////////////////////
32 // ExtensionMessageBubbleController::Delegate
34 ExtensionMessageBubbleController::Delegate::Delegate(Profile
* profile
)
38 ExtensionMessageBubbleController::Delegate::~Delegate() {
41 void ExtensionMessageBubbleController::Delegate::RestrictToSingleExtension(
42 const std::string
& extension_id
) {
43 NOTIMPLEMENTED(); // Derived classes that need this should implement.
46 base::string16
ExtensionMessageBubbleController::Delegate::GetLearnMoreLabel()
48 return l10n_util::GetStringUTF16(IDS_LEARN_MORE
);
51 bool ExtensionMessageBubbleController::Delegate::HasBubbleInfoBeenAcknowledged(
52 const std::string
& extension_id
) {
53 std::string pref_name
= get_acknowledged_flag_pref_name();
54 if (pref_name
.empty())
56 bool pref_state
= false;
57 extensions::ExtensionPrefs
* prefs
= extensions::ExtensionPrefs::Get(profile_
);
58 prefs
->ReadPrefAsBoolean(extension_id
, pref_name
, &pref_state
);
62 void ExtensionMessageBubbleController::Delegate::SetBubbleInfoBeenAcknowledged(
63 const std::string
& extension_id
,
65 std::string pref_name
= get_acknowledged_flag_pref_name();
66 if (pref_name
.empty())
68 extensions::ExtensionPrefs
* prefs
= extensions::ExtensionPrefs::Get(profile_
);
69 prefs
->UpdateExtensionPref(extension_id
,
71 value
? new base::FundamentalValue(value
) : NULL
);
74 Profile
* ExtensionMessageBubbleController::Delegate::profile() const {
79 ExtensionMessageBubbleController::Delegate::get_acknowledged_flag_pref_name()
81 return acknowledged_pref_name_
;
85 ExtensionMessageBubbleController::Delegate::set_acknowledged_flag_pref_name(
86 std::string pref_name
) {
87 acknowledged_pref_name_
= pref_name
;
90 ////////////////////////////////////////////////////////////////////////////////
91 // ExtensionMessageBubbleController
93 ExtensionMessageBubbleController::ExtensionMessageBubbleController(
94 Delegate
* delegate
, Profile
* profile
)
96 user_action_(ACTION_BOUNDARY
),
99 did_highlight_(false) {
102 ExtensionMessageBubbleController::~ExtensionMessageBubbleController() {
105 std::vector
<base::string16
>
106 ExtensionMessageBubbleController::GetExtensionList() {
107 ExtensionIdList
* list
= GetOrCreateExtensionList();
109 return std::vector
<base::string16
>();
111 ExtensionRegistry
* registry
= ExtensionRegistry::Get(profile_
);
112 std::vector
<base::string16
> return_value
;
113 for (ExtensionIdList::const_iterator it
= list
->begin();
114 it
!= list
->end(); ++it
) {
115 const Extension
* extension
=
116 registry
->GetExtensionById(*it
, ExtensionRegistry::EVERYTHING
);
118 return_value
.push_back(base::UTF8ToUTF16(extension
->name()));
120 return_value
.push_back(
121 base::ASCIIToUTF16(std::string("(unknown name) ") + *it
));
122 // TODO(finnur): Add this as a string to the grd, for next milestone.
128 base::string16
ExtensionMessageBubbleController::GetExtensionListForDisplay() {
129 if (!delegate_
->ShouldShowExtensionList())
130 return base::string16();
132 std::vector
<base::string16
> extension_list
= GetExtensionList();
133 if (extension_list
.size() > kMaxExtensionsToShow
) {
134 int old_size
= extension_list
.size();
135 extension_list
.erase(extension_list
.begin() + kMaxExtensionsToShow
,
136 extension_list
.end());
137 extension_list
.push_back(delegate_
->GetOverflowText(base::IntToString16(
138 old_size
- kMaxExtensionsToShow
)));
140 const base::char16 bullet_point
= 0x2022;
141 base::string16 prefix
= bullet_point
+ base::ASCIIToUTF16(" ");
142 for (base::string16
& str
: extension_list
)
143 str
.insert(0, prefix
);
144 return base::JoinString(extension_list
, base::ASCIIToUTF16("\n"));
147 const ExtensionIdList
& ExtensionMessageBubbleController::GetExtensionIdList() {
148 return *GetOrCreateExtensionList();
151 bool ExtensionMessageBubbleController::CloseOnDeactivate() { return false; }
153 void ExtensionMessageBubbleController::HighlightExtensionsIfNecessary() {
154 if (delegate_
->ShouldHighlightExtensions() && !did_highlight_
) {
155 did_highlight_
= true;
156 const ExtensionIdList
& extension_ids
= GetExtensionIdList();
157 DCHECK(!extension_ids
.empty());
158 ExtensionToolbarModel::Get(profile_
)->HighlightExtensions(
159 extension_ids
, ExtensionToolbarModel::HIGHLIGHT_WARNING
);
163 void ExtensionMessageBubbleController::Show(ExtensionMessageBubble
* bubble
) {
167 void ExtensionMessageBubbleController::OnBubbleAction() {
168 DCHECK_EQ(ACTION_BOUNDARY
, user_action_
);
169 user_action_
= ACTION_EXECUTE
;
171 delegate_
->LogAction(ACTION_EXECUTE
);
172 delegate_
->PerformAction(*GetOrCreateExtensionList());
177 void ExtensionMessageBubbleController::OnBubbleDismiss() {
178 // OnBubbleDismiss() can be called twice when we receive multiple
179 // "OnWidgetDestroying" notifications (this can at least happen when we close
180 // a window with a notification open). Handle this gracefully.
181 if (user_action_
!= ACTION_BOUNDARY
) {
182 DCHECK(user_action_
== ACTION_DISMISS
);
186 user_action_
= ACTION_DISMISS
;
188 delegate_
->LogAction(ACTION_DISMISS
);
193 void ExtensionMessageBubbleController::OnLinkClicked() {
194 DCHECK_EQ(ACTION_BOUNDARY
, user_action_
);
195 user_action_
= ACTION_LEARN_MORE
;
197 delegate_
->LogAction(ACTION_LEARN_MORE
);
199 chrome::FindBrowserWithProfile(profile_
, chrome::GetActiveDesktop());
202 content::OpenURLParams(delegate_
->GetLearnMoreUrl(),
205 ui::PAGE_TRANSITION_LINK
,
211 void ExtensionMessageBubbleController::AcknowledgeExtensions() {
212 ExtensionIdList
* list
= GetOrCreateExtensionList();
213 for (ExtensionIdList::const_iterator it
= list
->begin();
214 it
!= list
->end(); ++it
)
215 delegate_
->AcknowledgeExtension(*it
, user_action_
);
218 ExtensionIdList
* ExtensionMessageBubbleController::GetOrCreateExtensionList() {
220 scoped_ptr
<const ExtensionSet
> extension_set(
221 ExtensionRegistry::Get(profile_
)->GenerateInstalledExtensionsSet());
222 for (ExtensionSet::const_iterator it
= extension_set
->begin();
223 it
!= extension_set
->end(); ++it
) {
224 std::string id
= (*it
)->id();
225 if (!delegate_
->ShouldIncludeExtension(id
))
227 extension_list_
.push_back(id
);
230 delegate_
->LogExtensionCount(extension_list_
.size());
234 return &extension_list_
;
237 void ExtensionMessageBubbleController::OnClose() {
238 AcknowledgeExtensions();
240 ExtensionToolbarModel::Get(profile_
)->StopHighlighting();
243 } // namespace extensions