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_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" 23 24namespace extensions { 25 26namespace { 27 28base::LazyInstance<BrowserContextKeyedAPIFactory<SettingsOverridesAPI> > 29 g_factory = LAZY_INSTANCE_INITIALIZER; 30 31const char kManyStartupPagesWarning[] = "* specifies more than 1 startup URL. " 32 "All but the first will be ignored."; 33 34using api::manifest_types::ChromeSettingsOverrides; 35 36std::string SubstituteInstallParam(std::string str, 37 const std::string& install_parameter) { 38 ReplaceSubstringsAfterOffset(&str, 0, "__PARAM__", install_parameter); 39 return str; 40} 41 42// Find the prepopulated search engine with the given id. 43bool GetPrepopulatedSearchProvider(PrefService* prefs, 44 int prepopulated_id, 45 TemplateURLData* data) { 46 DCHECK(data); 47 size_t default_index; 48 ScopedVector<TemplateURLData> engines = 49 TemplateURLPrepopulateData::GetPrepopulatedEngines(prefs, &default_index); 50 for (ScopedVector<TemplateURLData>::iterator i = engines.begin(); 51 i != engines.end(); 52 ++i) { 53 if ((*i)->prepopulate_id == prepopulated_id) { 54 *data = **i; 55 return true; 56 } 57 } 58 return false; 59} 60 61TemplateURLData ConvertSearchProvider( 62 PrefService* prefs, 63 const ChromeSettingsOverrides::Search_provider& search_provider, 64 const std::string& install_parameter) { 65 TemplateURLData data; 66 if (search_provider.prepopulated_id) { 67 if (!GetPrepopulatedSearchProvider(prefs, *search_provider.prepopulated_id, 68 &data)) { 69 VLOG(1) << "Settings Overrides API can't recognize prepopulated_id=" 70 << *search_provider.prepopulated_id; 71 } 72 } 73 74 if (search_provider.name) 75 data.short_name = 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, 79 install_parameter)); 80 if (search_provider.suggest_url) { 81 data.suggestions_url = 82 SubstituteInstallParam(*search_provider.suggest_url, install_parameter); 83 } 84 if (search_provider.instant_url) { 85 data.instant_url = 86 SubstituteInstallParam(*search_provider.instant_url, install_parameter); 87 } 88 if (search_provider.image_url) { 89 data.image_url = 90 SubstituteInstallParam(*search_provider.image_url, install_parameter); 91 } 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, 102 install_parameter)); 103 } 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); 108 } 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)); 118 } 119 } 120 return data; 121} 122 123} // namespace 124 125SettingsOverridesAPI::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_)); 130} 131 132SettingsOverridesAPI::~SettingsOverridesAPI() { 133} 134 135BrowserContextKeyedAPIFactory<SettingsOverridesAPI>* 136SettingsOverridesAPI::GetFactoryInstance() { 137 return g_factory.Pointer(); 138} 139 140void SettingsOverridesAPI::SetPref(const std::string& extension_id, 141 const std::string& pref_key, 142 base::Value* value) { 143 PreferenceAPI* prefs = PreferenceAPI::Get(profile_); 144 if (!prefs) 145 return; // Expected in unit tests. 146 prefs->SetExtensionControlledPref(extension_id, 147 pref_key, 148 kExtensionPrefsScopeRegular, 149 value); 150} 151 152void SettingsOverridesAPI::UnsetPref(const std::string& extension_id, 153 const std::string& pref_key) { 154 PreferenceAPI* prefs = PreferenceAPI::Get(profile_); 155 if (!prefs) 156 return; // Expected in unit tests. 157 prefs->RemoveExtensionControlledPref( 158 extension_id, 159 pref_key, 160 kExtensionPrefsScopeRegular); 161} 162 163void SettingsOverridesAPI::OnExtensionLoaded( 164 content::BrowserContext* browser_context, 165 const Extension* extension) { 166 const SettingsOverrides* settings = SettingsOverrides::Get(extension); 167 if (settings) { 168 std::string install_parameter = 169 ExtensionPrefs::Get(profile_)->GetInstallParam(extension->id()); 170 if (settings->homepage) { 171 SetPref(extension->id(), 172 prefs::kHomePage, 173 new base::StringValue(SubstituteInstallParam( 174 settings->homepage->spec(), install_parameter))); 175 SetPref(extension->id(), 176 prefs::kHomePageIsNewTabPage, 177 new base::FundamentalValue(false)); 178 } 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); 187 } 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))); 191 SetPref( 192 extension->id(), prefs::kURLsToRestoreOnStartup, url_list.release()); 193 } 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)); 202 } else { 203 UnsetPref(extension->id(), prefs::kDefaultSearchProviderEnabled); 204 } 205 DCHECK(url_service_); 206 if (url_service_->loaded()) { 207 RegisterSearchProvider(extension); 208 } else { 209 if (!template_url_sub_) { 210 template_url_sub_ = url_service_->RegisterOnLoadedCallback( 211 base::Bind(&SettingsOverridesAPI::OnTemplateURLsLoaded, 212 base::Unretained(this))); 213 } 214 url_service_->Load(); 215 pending_extensions_.insert(extension); 216 } 217 } 218 } 219} 220void SettingsOverridesAPI::OnExtensionUnloaded( 221 content::BrowserContext* browser_context, 222 const Extension* extension, 223 UnloadedExtensionInfo::Reason reason) { 224 const SettingsOverrides* settings = SettingsOverrides::Get(extension); 225 if (settings) { 226 if (settings->homepage) { 227 UnsetPref(extension->id(), prefs::kHomePage); 228 UnsetPref(extension->id(), prefs::kHomePageIsNewTabPage); 229 } 230 if (!settings->startup_pages.empty()) { 231 UnsetPref(extension->id(), prefs::kRestoreOnStartup); 232 UnsetPref(extension->id(), prefs::kURLsToRestoreOnStartup); 233 } 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); 239 } else { 240 pending_extensions_.erase(extension); 241 } 242 } 243 } 244} 245 246void SettingsOverridesAPI::Shutdown() { 247 template_url_sub_.reset(); 248} 249 250void 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()); 256 } 257 pending_extensions_.clear(); 258} 259 260void SettingsOverridesAPI::RegisterSearchProvider( 261 const Extension* extension) const { 262 DCHECK(url_service_); 263 DCHECK(extension); 264 const SettingsOverrides* settings = SettingsOverrides::Get(extension); 265 DCHECK(settings); 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()); 278} 279 280template <> 281void BrowserContextKeyedAPIFactory< 282 SettingsOverridesAPI>::DeclareFactoryDependencies() { 283 DependsOn(ExtensionPrefsFactory::GetInstance()); 284 DependsOn(PreferenceAPI::GetFactoryInstance()); 285 DependsOn(TemplateURLServiceFactory::GetInstance()); 286} 287 288} // namespace extensions 289