1 // Copyright (c) 2014 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/settings_api_bubble_controller.h"
7 #include "base/metrics/histogram.h"
8 #include "chrome/browser/extensions/extension_service.h"
9 #include "chrome/browser/extensions/settings_api_helpers.h"
10 #include "chrome/browser/profiles/profile.h"
11 #include "chrome/browser/ui/startup/startup_browser_creator.h"
12 #include "chrome/common/extensions/manifest_handlers/settings_overrides_handler.h"
13 #include "chrome/common/url_constants.h"
14 #include "extensions/browser/extension_registry.h"
15 #include "extensions/browser/extension_system.h"
16 #include "grit/chromium_strings.h"
17 #include "grit/generated_resources.h"
18 #include "ui/base/l10n/l10n_util.h"
20 using extensions::ExtensionMessageBubbleController
;
21 using extensions::SettingsApiBubbleController
;
22 using extensions::SettingsOverrides
;
26 ////////////////////////////////////////////////////////////////////////////////
27 // SettingsApiBubbleDelegate
29 class SettingsApiBubbleDelegate
30 : public extensions::ExtensionMessageBubbleController::Delegate
{
32 explicit SettingsApiBubbleDelegate(ExtensionService
* service
,
34 extensions::SettingsApiOverrideType type
);
35 virtual ~SettingsApiBubbleDelegate();
37 // ExtensionMessageBubbleController::Delegate methods.
38 virtual bool ShouldIncludeExtension(const std::string
& extension_id
) OVERRIDE
;
39 virtual void AcknowledgeExtension(
40 const std::string
& extension_id
,
41 extensions::ExtensionMessageBubbleController::BubbleAction user_action
)
43 virtual void PerformAction(const extensions::ExtensionIdList
& list
) OVERRIDE
;
44 virtual base::string16
GetTitle() const OVERRIDE
;
45 virtual base::string16
GetMessageBody() const OVERRIDE
;
46 virtual base::string16
GetOverflowText(
47 const base::string16
& overflow_count
) const OVERRIDE
;
48 virtual base::string16
GetLearnMoreLabel() const OVERRIDE
;
49 virtual GURL
GetLearnMoreUrl() const OVERRIDE
;
50 virtual base::string16
GetActionButtonLabel() const OVERRIDE
;
51 virtual base::string16
GetDismissButtonLabel() const OVERRIDE
;
52 virtual bool ShouldShowExtensionList() const OVERRIDE
;
53 virtual void LogExtensionCount(size_t count
) OVERRIDE
;
54 virtual void LogAction(
55 extensions::ExtensionMessageBubbleController::BubbleAction action
)
59 // Our extension service. Weak, not owned by us.
60 ExtensionService
* service_
;
62 // A weak pointer to the profile we are associated with. Not owned by us.
65 // The type of settings override this bubble will report on. This can be, for
66 // example, a bubble to notify the user that the search engine has been
67 // changed by an extension (or homepage/startup pages/etc).
68 extensions::SettingsApiOverrideType type_
;
70 // The ID of the extension we are showing the bubble for.
71 std::string extension_id_
;
73 DISALLOW_COPY_AND_ASSIGN(SettingsApiBubbleDelegate
);
76 SettingsApiBubbleDelegate::SettingsApiBubbleDelegate(
77 ExtensionService
* service
,
79 extensions::SettingsApiOverrideType type
)
80 : service_(service
), profile_(profile
), type_(type
) {}
82 SettingsApiBubbleDelegate::~SettingsApiBubbleDelegate() {}
84 bool SettingsApiBubbleDelegate::ShouldIncludeExtension(
85 const std::string
& extension_id
) {
86 using extensions::ExtensionRegistry
;
87 ExtensionRegistry
* registry
= ExtensionRegistry::Get(profile_
);
88 const extensions::Extension
* extension
=
89 registry
->GetExtensionById(extension_id
, ExtensionRegistry::ENABLED
);
91 return false; // The extension provided is no longer enabled.
93 extensions::ExtensionPrefs
* prefs
= extensions::ExtensionPrefs::Get(profile_
);
94 if (prefs
->HasSettingsApiBubbleBeenAcknowledged(extension_id
))
97 const extensions::Extension
* override
= NULL
;
99 case extensions::BUBBLE_TYPE_HOME_PAGE
:
100 override
= extensions::OverridesHomepage(profile_
, NULL
);
102 case extensions::BUBBLE_TYPE_STARTUP_PAGES
:
103 override
= extensions::OverridesStartupPages(profile_
, NULL
);
105 case extensions::BUBBLE_TYPE_SEARCH_ENGINE
:
106 override
= extensions::OverridesSearchEngine(profile_
, NULL
);
110 if (!override
|| override
->id() != extension
->id())
113 extension_id_
= extension_id
;
117 void SettingsApiBubbleDelegate::AcknowledgeExtension(
118 const std::string
& extension_id
,
119 ExtensionMessageBubbleController::BubbleAction user_action
) {
120 if (user_action
!= ExtensionMessageBubbleController::ACTION_EXECUTE
) {
121 extensions::ExtensionPrefs
* prefs
=
122 extensions::ExtensionPrefs::Get(profile_
);
123 prefs
->SetSettingsApiBubbleBeenAcknowledged(extension_id
, true);
127 void SettingsApiBubbleDelegate::PerformAction(
128 const extensions::ExtensionIdList
& list
) {
129 for (size_t i
= 0; i
< list
.size(); ++i
) {
130 service_
->DisableExtension(list
[i
],
131 extensions::Extension::DISABLE_USER_ACTION
);
135 base::string16
SettingsApiBubbleDelegate::GetTitle() const {
137 case extensions::BUBBLE_TYPE_HOME_PAGE
:
138 return l10n_util::GetStringUTF16(
139 IDS_EXTENSIONS_SETTINGS_API_TITLE_HOME_PAGE_BUBBLE
);
140 case extensions::BUBBLE_TYPE_STARTUP_PAGES
:
141 return l10n_util::GetStringUTF16(
142 IDS_EXTENSIONS_SETTINGS_API_TITLE_STARTUP_PAGES_BUBBLE
);
143 case extensions::BUBBLE_TYPE_SEARCH_ENGINE
:
144 return l10n_util::GetStringUTF16(
145 IDS_EXTENSIONS_SETTINGS_API_TITLE_SEARCH_ENGINE_BUBBLE
);
148 return base::string16();
151 base::string16
SettingsApiBubbleDelegate::GetMessageBody() const {
152 using extensions::ExtensionRegistry
;
153 ExtensionRegistry
* registry
= ExtensionRegistry::Get(profile_
);
154 const extensions::Extension
* extension
=
155 registry
->GetExtensionById(extension_id_
, ExtensionRegistry::ENABLED
);
156 const SettingsOverrides
* settings
=
157 extension
? SettingsOverrides::Get(extension
) : NULL
;
158 if (!extension
|| !settings
) {
160 return base::string16();
163 bool home_change
= settings
->homepage
!= NULL
;
164 bool startup_change
= !settings
->startup_pages
.empty();
165 bool search_change
= settings
->search_engine
!= NULL
;
169 case extensions::BUBBLE_TYPE_HOME_PAGE
:
170 body
= l10n_util::GetStringUTF16(
171 IDS_EXTENSIONS_SETTINGS_API_FIRST_LINE_HOME_PAGE
);
172 if (startup_change
&& search_change
) {
173 body
+= l10n_util::GetStringUTF16(
174 IDS_EXTENSIONS_SETTINGS_API_SECOND_LINE_START_AND_SEARCH
);
175 } else if (startup_change
) {
176 body
+= l10n_util::GetStringUTF16(
177 IDS_EXTENSIONS_SETTINGS_API_SECOND_LINE_START_PAGES
);
178 } else if (search_change
) {
179 body
+= l10n_util::GetStringUTF16(
180 IDS_EXTENSIONS_SETTINGS_API_SECOND_LINE_SEARCH_ENGINE
);
183 case extensions::BUBBLE_TYPE_STARTUP_PAGES
:
184 body
= l10n_util::GetStringUTF16(
185 IDS_EXTENSIONS_SETTINGS_API_FIRST_LINE_START_PAGES
);
186 if (home_change
&& search_change
) {
187 body
+= l10n_util::GetStringUTF16(
188 IDS_EXTENSIONS_SETTINGS_API_SECOND_LINE_HOME_AND_SEARCH
);
189 } else if (home_change
) {
190 body
+= l10n_util::GetStringUTF16(
191 IDS_EXTENSIONS_SETTINGS_API_SECOND_LINE_HOME_PAGE
);
192 } else if (search_change
) {
193 body
+= l10n_util::GetStringUTF16(
194 IDS_EXTENSIONS_SETTINGS_API_SECOND_LINE_SEARCH_ENGINE
);
197 case extensions::BUBBLE_TYPE_SEARCH_ENGINE
:
198 body
= l10n_util::GetStringUTF16(
199 IDS_EXTENSIONS_SETTINGS_API_FIRST_LINE_SEARCH_ENGINE
);
200 if (startup_change
&& home_change
) {
201 body
+= l10n_util::GetStringUTF16(
202 IDS_EXTENSIONS_SETTINGS_API_SECOND_LINE_START_AND_HOME
);
203 } else if (startup_change
) {
204 body
+= l10n_util::GetStringUTF16(
205 IDS_EXTENSIONS_SETTINGS_API_SECOND_LINE_START_PAGES
);
206 } else if (home_change
) {
207 body
+= l10n_util::GetStringUTF16(
208 IDS_EXTENSIONS_SETTINGS_API_SECOND_LINE_HOME_PAGE
);
213 body
+= l10n_util::GetStringUTF16(
214 IDS_EXTENSIONS_SETTINGS_API_THIRD_LINE_CONFIRMATION
);
218 base::string16
SettingsApiBubbleDelegate::GetOverflowText(
219 const base::string16
& overflow_count
) const {
220 // Does not have more than one extension in the list at a time.
222 return base::string16();
225 base::string16
SettingsApiBubbleDelegate::GetLearnMoreLabel() const {
226 return l10n_util::GetStringUTF16(IDS_LEARN_MORE
);
229 GURL
SettingsApiBubbleDelegate::GetLearnMoreUrl() const {
230 return GURL(chrome::kSettingsApiLearnMoreURL
);
233 base::string16
SettingsApiBubbleDelegate::GetActionButtonLabel() const {
234 return l10n_util::GetStringUTF16(
235 IDS_EXTENSIONS_SETTINGS_API_RESTORE_SETTINGS
);
238 base::string16
SettingsApiBubbleDelegate::GetDismissButtonLabel() const {
239 return l10n_util::GetStringUTF16(IDS_EXTENSIONS_SETTINGS_API_KEEP_CHANGES
);
242 bool SettingsApiBubbleDelegate::ShouldShowExtensionList() const {
246 void SettingsApiBubbleDelegate::LogExtensionCount(size_t count
) {
247 UMA_HISTOGRAM_COUNTS_100("SettingsApiBubble.ExtensionCount", count
);
250 void SettingsApiBubbleDelegate::LogAction(
251 ExtensionMessageBubbleController::BubbleAction action
) {
252 UMA_HISTOGRAM_ENUMERATION("SettingsApiBubble.UserSelection",
254 ExtensionMessageBubbleController::ACTION_BOUNDARY
);
259 namespace extensions
{
261 ////////////////////////////////////////////////////////////////////////////////
262 // SettingsApiBubbleController
264 SettingsApiBubbleController::SettingsApiBubbleController(
266 SettingsApiOverrideType type
)
267 : ExtensionMessageBubbleController(
268 new SettingsApiBubbleDelegate(
269 ExtensionSystem::Get(profile
)->extension_service(),
276 SettingsApiBubbleController::~SettingsApiBubbleController() {}
278 bool SettingsApiBubbleController::ShouldShow(const std::string
& extension_id
) {
279 extensions::ExtensionPrefs
* prefs
= extensions::ExtensionPrefs::Get(profile_
);
280 if (prefs
->HasSettingsApiBubbleBeenAcknowledged(extension_id
))
283 if (!delegate()->ShouldIncludeExtension(extension_id
))
286 // If the browser is showing the 'Chrome crashed' infobar, it won't be showing
287 // the startup pages, so there's no point in showing the bubble now.
288 if (type_
== BUBBLE_TYPE_STARTUP_PAGES
)
289 return profile_
->GetLastSessionExitType() != Profile::EXIT_CRASHED
;
294 bool SettingsApiBubbleController::CloseOnDeactivate() {
295 // Startup bubbles tend to get lost in the focus storm that happens on
296 // startup. Other types should dismiss on focus loss.
297 return type_
!= BUBBLE_TYPE_STARTUP_PAGES
;
300 } // namespace extensions