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. 4 5#include "chrome/browser/extensions/api/settings_overrides/settings_overrides_api.h" 6 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.h" 13#include "chrome/browser/search_engines/template_url_prepopulate_data.h" 14#include "chrome/browser/search_engines/template_url_service_factory.h" 15#include "chrome/common/extensions/manifest_handlers/settings_overrides_handler.h" 16#include "chrome/common/pref_names.h" 17#include "extensions/browser/extension_prefs.h" 18#include "extensions/browser/extension_prefs_factory.h" 19#include "extensions/browser/extension_registry.h" 20#include "extensions/common/error_utils.h" 21#include "extensions/common/manifest_constants.h" 22 23namespace extensions { 24 25namespace { 26 27base::LazyInstance<BrowserContextKeyedAPIFactory<SettingsOverridesAPI> > 28 g_factory = LAZY_INSTANCE_INITIALIZER; 29 30const char kManyStartupPagesWarning[] = "* specifies more than 1 startup URL. " 31 "All but the first will be ignored."; 32 33using api::manifest_types::ChromeSettingsOverrides; 34 35std::string SubstituteInstallParam(std::string str, 36 const std::string& install_parameter) { 37 ReplaceSubstringsAfterOffset(&str, 0, "__PARAM__", install_parameter); 38 return str; 39} 40 41// Find the prepopulated search engine with the given id. 42bool GetPrepopulatedSearchProvider(PrefService* prefs, 43 int prepopulated_id, 44 TemplateURLData* data) { 45 DCHECK(data); 46 size_t default_index; 47 ScopedVector<TemplateURLData> engines = 48 TemplateURLPrepopulateData::GetPrepopulatedEngines(prefs, &default_index); 49 for (ScopedVector<TemplateURLData>::iterator i = engines.begin(); 50 i != engines.end(); 51 ++i) { 52 if ((*i)->prepopulate_id == prepopulated_id) { 53 *data = **i; 54 return true; 55 } 56 } 57 return false; 58} 59 60TemplateURLData ConvertSearchProvider( 61 PrefService* prefs, 62 const ChromeSettingsOverrides::Search_provider& search_provider, 63 const std::string& install_parameter) { 64 TemplateURLData data; 65 if (search_provider.prepopulated_id) { 66 if (!GetPrepopulatedSearchProvider(prefs, *search_provider.prepopulated_id, 67 &data)) { 68 VLOG(1) << "Settings Overrides API can't recognize prepopulated_id=" 69 << *search_provider.prepopulated_id; 70 } 71 } 72 73 if (search_provider.name) 74 data.short_name = base::UTF8ToUTF16(*search_provider.name); 75 if (search_provider.keyword) 76 data.SetKeyword(base::UTF8ToUTF16(*search_provider.keyword)); 77 data.SetURL(SubstituteInstallParam(search_provider.search_url, 78 install_parameter)); 79 if (search_provider.suggest_url) { 80 data.suggestions_url = 81 SubstituteInstallParam(*search_provider.suggest_url, install_parameter); 82 } 83 if (search_provider.instant_url) { 84 data.instant_url = 85 SubstituteInstallParam(*search_provider.instant_url, install_parameter); 86 } 87 if (search_provider.image_url) { 88 data.image_url = 89 SubstituteInstallParam(*search_provider.image_url, install_parameter); 90 } 91 if (search_provider.search_url_post_params) 92 data.search_url_post_params = *search_provider.search_url_post_params; 93 if (search_provider.suggest_url_post_params) 94 data.suggestions_url_post_params = *search_provider.suggest_url_post_params; 95 if (search_provider.instant_url_post_params) 96 data.instant_url_post_params = *search_provider.instant_url_post_params; 97 if (search_provider.image_url_post_params) 98 data.image_url_post_params = *search_provider.image_url_post_params; 99 if (search_provider.favicon_url) { 100 data.favicon_url = GURL(SubstituteInstallParam(*search_provider.favicon_url, 101 install_parameter)); 102 } 103 data.safe_for_autoreplace = false; 104 if (search_provider.encoding) { 105 data.input_encodings.clear(); 106 data.input_encodings.push_back(*search_provider.encoding); 107 } 108 data.date_created = base::Time(); 109 data.last_modified = base::Time(); 110 data.prepopulate_id = 0; 111 if (search_provider.alternate_urls) { 112 data.alternate_urls.clear(); 113 for (size_t i = 0; i < search_provider.alternate_urls->size(); ++i) { 114 if (!search_provider.alternate_urls->at(i).empty()) 115 data.alternate_urls.push_back(SubstituteInstallParam( 116 search_provider.alternate_urls->at(i), install_parameter)); 117 } 118 } 119 return data; 120} 121 122} // namespace 123 124SettingsOverridesAPI::SettingsOverridesAPI(content::BrowserContext* context) 125 : profile_(Profile::FromBrowserContext(context)), 126 url_service_(TemplateURLServiceFactory::GetForProfile(profile_)), 127 extension_registry_observer_(this) { 128 extension_registry_observer_.Add(ExtensionRegistry::Get(profile_)); 129} 130 131SettingsOverridesAPI::~SettingsOverridesAPI() { 132} 133 134BrowserContextKeyedAPIFactory<SettingsOverridesAPI>* 135SettingsOverridesAPI::GetFactoryInstance() { 136 return g_factory.Pointer(); 137} 138 139void SettingsOverridesAPI::SetPref(const std::string& extension_id, 140 const std::string& pref_key, 141 base::Value* value) { 142 PreferenceAPI* prefs = PreferenceAPI::Get(profile_); 143 if (!prefs) 144 return; // Expected in unit tests. 145 prefs->SetExtensionControlledPref(extension_id, 146 pref_key, 147 kExtensionPrefsScopeRegular, 148 value); 149} 150 151void SettingsOverridesAPI::UnsetPref(const std::string& extension_id, 152 const std::string& pref_key) { 153 PreferenceAPI* prefs = PreferenceAPI::Get(profile_); 154 if (!prefs) 155 return; // Expected in unit tests. 156 prefs->RemoveExtensionControlledPref( 157 extension_id, 158 pref_key, 159 kExtensionPrefsScopeRegular); 160} 161 162void SettingsOverridesAPI::OnExtensionLoaded( 163 content::BrowserContext* browser_context, 164 const Extension* extension) { 165 const SettingsOverrides* settings = SettingsOverrides::Get(extension); 166 if (settings) { 167 std::string install_parameter = 168 ExtensionPrefs::Get(profile_)->GetInstallParam(extension->id()); 169 if (settings->homepage) { 170 SetPref(extension->id(), 171 prefs::kHomePage, 172 new base::StringValue(SubstituteInstallParam( 173 settings->homepage->spec(), install_parameter))); 174 SetPref(extension->id(), 175 prefs::kHomePageIsNewTabPage, 176 new base::FundamentalValue(false)); 177 } 178 if (!settings->startup_pages.empty()) { 179 SetPref(extension->id(), 180 prefs::kRestoreOnStartup, 181 new base::FundamentalValue(SessionStartupPref::kPrefValueURLs)); 182 if (settings->startup_pages.size() > 1) { 183 VLOG(1) << extensions::ErrorUtils::FormatErrorMessage( 184 kManyStartupPagesWarning, 185 manifest_keys::kSettingsOverride); 186 } 187 scoped_ptr<base::ListValue> url_list(new base::ListValue); 188 url_list->Append(new base::StringValue(SubstituteInstallParam( 189 settings->startup_pages[0].spec(), install_parameter))); 190 SetPref( 191 extension->id(), prefs::kURLsToRestoreOnStartup, url_list.release()); 192 } 193 if (settings->search_engine) { 194 // Bring the preference to the correct state. Before this code set it 195 // to "true" for all search engines. Thus, we should overwrite it for 196 // all search engines. 197 if (settings->search_engine->is_default) { 198 SetPref(extension->id(), 199 prefs::kDefaultSearchProviderEnabled, 200 new base::FundamentalValue(true)); 201 } else { 202 UnsetPref(extension->id(), prefs::kDefaultSearchProviderEnabled); 203 } 204 DCHECK(url_service_); 205 if (url_service_->loaded()) { 206 RegisterSearchProvider(extension); 207 } else { 208 if (!template_url_sub_) { 209 template_url_sub_ = url_service_->RegisterOnLoadedCallback( 210 base::Bind(&SettingsOverridesAPI::OnTemplateURLsLoaded, 211 base::Unretained(this))); 212 } 213 url_service_->Load(); 214 pending_extensions_.insert(extension); 215 } 216 } 217 } 218} 219void SettingsOverridesAPI::OnExtensionUnloaded( 220 content::BrowserContext* browser_context, 221 const Extension* extension, 222 UnloadedExtensionInfo::Reason reason) { 223 const SettingsOverrides* settings = SettingsOverrides::Get(extension); 224 if (settings) { 225 if (settings->homepage) { 226 UnsetPref(extension->id(), prefs::kHomePage); 227 UnsetPref(extension->id(), prefs::kHomePageIsNewTabPage); 228 } 229 if (!settings->startup_pages.empty()) { 230 UnsetPref(extension->id(), prefs::kRestoreOnStartup); 231 UnsetPref(extension->id(), prefs::kURLsToRestoreOnStartup); 232 } 233 if (settings->search_engine) { 234 DCHECK(url_service_); 235 if (url_service_->loaded()) 236 url_service_->RemoveExtensionControlledTURL(extension->id()); 237 else 238 pending_extensions_.erase(extension); 239 } 240 } 241} 242 243void SettingsOverridesAPI::Shutdown() { 244 template_url_sub_.reset(); 245} 246 247void SettingsOverridesAPI::OnTemplateURLsLoaded() { 248 // Register search providers for pending extensions. 249 template_url_sub_.reset(); 250 for (PendingExtensions::const_iterator i(pending_extensions_.begin()); 251 i != pending_extensions_.end(); ++i) { 252 RegisterSearchProvider(*i); 253 } 254 pending_extensions_.clear(); 255} 256 257void SettingsOverridesAPI::RegisterSearchProvider( 258 const Extension* extension) const { 259 DCHECK(url_service_); 260 DCHECK(extension); 261 const SettingsOverrides* settings = SettingsOverrides::Get(extension); 262 DCHECK(settings); 263 DCHECK(settings->search_engine); 264 scoped_ptr<AssociatedExtensionInfo> info(new AssociatedExtensionInfo); 265 info->extension_id = extension->id(); 266 info->wants_to_be_default_engine = settings->search_engine->is_default; 267 ExtensionPrefs* prefs = ExtensionPrefs::Get(profile_); 268 info->install_time = prefs->GetInstallTime(extension->id()); 269 std::string install_parameter = prefs->GetInstallParam(extension->id()); 270 TemplateURLData data = ConvertSearchProvider( 271 profile_->GetPrefs(), *settings->search_engine, install_parameter); 272 data.show_in_default_list = info->wants_to_be_default_engine; 273 url_service_->AddExtensionControlledTURL(new TemplateURL(data), info.Pass()); 274} 275 276template <> 277void BrowserContextKeyedAPIFactory< 278 SettingsOverridesAPI>::DeclareFactoryDependencies() { 279 DependsOn(ExtensionPrefsFactory::GetInstance()); 280 DependsOn(PreferenceAPI::GetFactoryInstance()); 281 DependsOn(TemplateURLServiceFactory::GetInstance()); 282} 283 284} // namespace extensions 285