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/extensions/api/settings_overrides/settings_overrides_api.h"
7 #include "base/lazy_instance.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "chrome/browser/extensions/api/preference/preference_api.h"
10 #include "chrome/browser/prefs/session_startup_pref.h"
11 #include "chrome/browser/profiles/profile.h"
12 #include "chrome/browser/search_engines/template_url_service_factory.h"
13 #include "chrome/common/extensions/manifest_handlers/settings_overrides_handler.h"
14 #include "chrome/common/pref_names.h"
15 #include "components/search_engines/search_engines_pref_names.h"
16 #include "components/search_engines/template_url.h"
17 #include "components/search_engines/template_url_prepopulate_data.h"
18 #include "extensions/browser/extension_prefs.h"
19 #include "extensions/browser/extension_prefs_factory.h"
20 #include "extensions/browser/extension_registry.h"
21 #include "extensions/common/error_utils.h"
22 #include "extensions/common/manifest_constants.h"
24 namespace extensions
{
28 base::LazyInstance
<BrowserContextKeyedAPIFactory
<SettingsOverridesAPI
> >
29 g_factory
= LAZY_INSTANCE_INITIALIZER
;
31 const char kManyStartupPagesWarning
[] = "* specifies more than 1 startup URL. "
32 "All but the first will be ignored.";
34 using api::manifest_types::ChromeSettingsOverrides
;
36 std::string
SubstituteInstallParam(std::string str
,
37 const std::string
& install_parameter
) {
38 base::ReplaceSubstringsAfterOffset(&str
, 0, "__PARAM__", install_parameter
);
42 // Find the prepopulated search engine with the given id.
43 bool GetPrepopulatedSearchProvider(PrefService
* prefs
,
45 TemplateURLData
* data
) {
48 ScopedVector
<TemplateURLData
> engines
=
49 TemplateURLPrepopulateData::GetPrepopulatedEngines(prefs
, &default_index
);
50 for (ScopedVector
<TemplateURLData
>::iterator i
= engines
.begin();
53 if ((*i
)->prepopulate_id
== prepopulated_id
) {
61 TemplateURLData
ConvertSearchProvider(
63 const ChromeSettingsOverrides::Search_provider
& search_provider
,
64 const std::string
& install_parameter
) {
66 if (search_provider
.prepopulated_id
) {
67 if (!GetPrepopulatedSearchProvider(prefs
, *search_provider
.prepopulated_id
,
69 VLOG(1) << "Settings Overrides API can't recognize prepopulated_id="
70 << *search_provider
.prepopulated_id
;
74 if (search_provider
.name
)
75 data
.SetShortName(base::UTF8ToUTF16(*search_provider
.name
));
76 if (search_provider
.keyword
)
77 data
.SetKeyword(base::UTF8ToUTF16(*search_provider
.keyword
));
78 data
.SetURL(SubstituteInstallParam(search_provider
.search_url
,
80 if (search_provider
.suggest_url
) {
81 data
.suggestions_url
=
82 SubstituteInstallParam(*search_provider
.suggest_url
, install_parameter
);
84 if (search_provider
.instant_url
) {
86 SubstituteInstallParam(*search_provider
.instant_url
, install_parameter
);
88 if (search_provider
.image_url
) {
90 SubstituteInstallParam(*search_provider
.image_url
, install_parameter
);
92 if (search_provider
.search_url_post_params
)
93 data
.search_url_post_params
= *search_provider
.search_url_post_params
;
94 if (search_provider
.suggest_url_post_params
)
95 data
.suggestions_url_post_params
= *search_provider
.suggest_url_post_params
;
96 if (search_provider
.instant_url_post_params
)
97 data
.instant_url_post_params
= *search_provider
.instant_url_post_params
;
98 if (search_provider
.image_url_post_params
)
99 data
.image_url_post_params
= *search_provider
.image_url_post_params
;
100 if (search_provider
.favicon_url
) {
101 data
.favicon_url
= GURL(SubstituteInstallParam(*search_provider
.favicon_url
,
104 data
.safe_for_autoreplace
= false;
105 if (search_provider
.encoding
) {
106 data
.input_encodings
.clear();
107 data
.input_encodings
.push_back(*search_provider
.encoding
);
109 data
.date_created
= base::Time();
110 data
.last_modified
= base::Time();
111 data
.prepopulate_id
= 0;
112 if (search_provider
.alternate_urls
) {
113 data
.alternate_urls
.clear();
114 for (size_t i
= 0; i
< search_provider
.alternate_urls
->size(); ++i
) {
115 if (!search_provider
.alternate_urls
->at(i
).empty())
116 data
.alternate_urls
.push_back(SubstituteInstallParam(
117 search_provider
.alternate_urls
->at(i
), install_parameter
));
125 SettingsOverridesAPI::SettingsOverridesAPI(content::BrowserContext
* context
)
126 : profile_(Profile::FromBrowserContext(context
)),
127 url_service_(TemplateURLServiceFactory::GetForProfile(profile_
)),
128 extension_registry_observer_(this) {
129 extension_registry_observer_
.Add(ExtensionRegistry::Get(profile_
));
132 SettingsOverridesAPI::~SettingsOverridesAPI() {
135 BrowserContextKeyedAPIFactory
<SettingsOverridesAPI
>*
136 SettingsOverridesAPI::GetFactoryInstance() {
137 return g_factory
.Pointer();
140 void SettingsOverridesAPI::SetPref(const std::string
& extension_id
,
141 const std::string
& pref_key
,
142 base::Value
* value
) {
143 PreferenceAPI
* prefs
= PreferenceAPI::Get(profile_
);
145 return; // Expected in unit tests.
146 prefs
->SetExtensionControlledPref(extension_id
,
148 kExtensionPrefsScopeRegular
,
152 void SettingsOverridesAPI::UnsetPref(const std::string
& extension_id
,
153 const std::string
& pref_key
) {
154 PreferenceAPI
* prefs
= PreferenceAPI::Get(profile_
);
156 return; // Expected in unit tests.
157 prefs
->RemoveExtensionControlledPref(
160 kExtensionPrefsScopeRegular
);
163 void SettingsOverridesAPI::OnExtensionLoaded(
164 content::BrowserContext
* browser_context
,
165 const Extension
* extension
) {
166 const SettingsOverrides
* settings
= SettingsOverrides::Get(extension
);
168 std::string install_parameter
=
169 ExtensionPrefs::Get(profile_
)->GetInstallParam(extension
->id());
170 if (settings
->homepage
) {
171 SetPref(extension
->id(),
173 new base::StringValue(SubstituteInstallParam(
174 settings
->homepage
->spec(), install_parameter
)));
175 SetPref(extension
->id(),
176 prefs::kHomePageIsNewTabPage
,
177 new base::FundamentalValue(false));
179 if (!settings
->startup_pages
.empty()) {
180 SetPref(extension
->id(),
181 prefs::kRestoreOnStartup
,
182 new base::FundamentalValue(SessionStartupPref::kPrefValueURLs
));
183 if (settings
->startup_pages
.size() > 1) {
184 VLOG(1) << extensions::ErrorUtils::FormatErrorMessage(
185 kManyStartupPagesWarning
,
186 manifest_keys::kSettingsOverride
);
188 scoped_ptr
<base::ListValue
> url_list(new base::ListValue
);
189 url_list
->Append(new base::StringValue(SubstituteInstallParam(
190 settings
->startup_pages
[0].spec(), install_parameter
)));
192 extension
->id(), prefs::kURLsToRestoreOnStartup
, url_list
.release());
194 if (settings
->search_engine
) {
195 // Bring the preference to the correct state. Before this code set it
196 // to "true" for all search engines. Thus, we should overwrite it for
197 // all search engines.
198 if (settings
->search_engine
->is_default
) {
199 SetPref(extension
->id(),
200 prefs::kDefaultSearchProviderEnabled
,
201 new base::FundamentalValue(true));
203 UnsetPref(extension
->id(), prefs::kDefaultSearchProviderEnabled
);
205 DCHECK(url_service_
);
206 if (url_service_
->loaded()) {
207 RegisterSearchProvider(extension
);
209 if (!template_url_sub_
) {
210 template_url_sub_
= url_service_
->RegisterOnLoadedCallback(
211 base::Bind(&SettingsOverridesAPI::OnTemplateURLsLoaded
,
212 base::Unretained(this)));
214 url_service_
->Load();
215 pending_extensions_
.insert(extension
);
220 void SettingsOverridesAPI::OnExtensionUnloaded(
221 content::BrowserContext
* browser_context
,
222 const Extension
* extension
,
223 UnloadedExtensionInfo::Reason reason
) {
224 const SettingsOverrides
* settings
= SettingsOverrides::Get(extension
);
226 if (settings
->homepage
) {
227 UnsetPref(extension
->id(), prefs::kHomePage
);
228 UnsetPref(extension
->id(), prefs::kHomePageIsNewTabPage
);
230 if (!settings
->startup_pages
.empty()) {
231 UnsetPref(extension
->id(), prefs::kRestoreOnStartup
);
232 UnsetPref(extension
->id(), prefs::kURLsToRestoreOnStartup
);
234 if (settings
->search_engine
) {
235 DCHECK(url_service_
);
236 if (url_service_
->loaded()) {
237 url_service_
->RemoveExtensionControlledTURL(
238 extension
->id(), TemplateURL::NORMAL_CONTROLLED_BY_EXTENSION
);
240 pending_extensions_
.erase(extension
);
246 void SettingsOverridesAPI::Shutdown() {
247 template_url_sub_
.reset();
250 void SettingsOverridesAPI::OnTemplateURLsLoaded() {
251 // Register search providers for pending extensions.
252 template_url_sub_
.reset();
253 for (PendingExtensions::const_iterator
i(pending_extensions_
.begin());
254 i
!= pending_extensions_
.end(); ++i
) {
255 RegisterSearchProvider(i
->get());
257 pending_extensions_
.clear();
260 void SettingsOverridesAPI::RegisterSearchProvider(
261 const Extension
* extension
) const {
262 DCHECK(url_service_
);
264 const SettingsOverrides
* settings
= SettingsOverrides::Get(extension
);
266 DCHECK(settings
->search_engine
);
267 scoped_ptr
<TemplateURL::AssociatedExtensionInfo
> info(
268 new TemplateURL::AssociatedExtensionInfo(
269 TemplateURL::NORMAL_CONTROLLED_BY_EXTENSION
, extension
->id()));
270 info
->wants_to_be_default_engine
= settings
->search_engine
->is_default
;
271 ExtensionPrefs
* prefs
= ExtensionPrefs::Get(profile_
);
272 info
->install_time
= prefs
->GetInstallTime(extension
->id());
273 std::string install_parameter
= prefs
->GetInstallParam(extension
->id());
274 TemplateURLData data
= ConvertSearchProvider(
275 profile_
->GetPrefs(), *settings
->search_engine
, install_parameter
);
276 data
.show_in_default_list
= info
->wants_to_be_default_engine
;
277 url_service_
->AddExtensionControlledTURL(new TemplateURL(data
), info
.Pass());
281 void BrowserContextKeyedAPIFactory
<
282 SettingsOverridesAPI
>::DeclareFactoryDependencies() {
283 DependsOn(ExtensionPrefsFactory::GetInstance());
284 DependsOn(PreferenceAPI::GetFactoryInstance());
285 DependsOn(TemplateURLServiceFactory::GetInstance());
288 } // namespace extensions