settings_overrides_api.cc revision f2477e01787aa58f445919b809d89e252beef54f
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/chrome_notification_types.h"
10#include "chrome/browser/extensions/api/preference/preference_api.h"
11#include "chrome/browser/extensions/extension_prefs.h"
12#include "chrome/browser/extensions/extension_prefs_factory.h"
13#include "chrome/browser/prefs/session_startup_pref.h"
14#include "chrome/browser/search_engines/template_url.h"
15#include "chrome/browser/search_engines/template_url_service_factory.h"
16#include "chrome/common/extensions/manifest_handlers/settings_overrides_handler.h"
17#include "chrome/common/pref_names.h"
18#include "content/public/browser/notification_details.h"
19#include "content/public/browser/notification_source.h"
20#include "extensions/common/error_utils.h"
21#include "extensions/common/manifest_constants.h"
22
23namespace extensions {
24
25namespace {
26base::LazyInstance<ProfileKeyedAPIFactory<SettingsOverridesAPI> >
27    g_factory = LAZY_INSTANCE_INITIALIZER;
28
29const char kManyStartupPagesWarning[] = "* specifies more than 1 startup URL. "
30    "All but the first will be ignored.";
31
32using api::manifest_types::ChromeSettingsOverrides;
33
34TemplateURLData ConvertSearchProvider(
35    const ChromeSettingsOverrides::Search_provider& search_provider) {
36  TemplateURLData data;
37
38  data.short_name = UTF8ToUTF16(search_provider.name);
39  data.SetKeyword(UTF8ToUTF16(search_provider.keyword));
40  data.SetURL(search_provider.search_url);
41  if (search_provider.suggest_url)
42    data.suggestions_url = *search_provider.suggest_url;
43  if (search_provider.instant_url)
44    data.instant_url = *search_provider.instant_url;
45  if (search_provider.image_url)
46    data.image_url = *search_provider.image_url;
47  if (search_provider.search_url_post_params)
48    data.search_url_post_params = *search_provider.search_url_post_params;
49  if (search_provider.suggest_url_post_params)
50    data.suggestions_url_post_params = *search_provider.suggest_url_post_params;
51  if (search_provider.instant_url_post_params)
52    data.instant_url_post_params = *search_provider.instant_url_post_params;
53  if (search_provider.image_url_post_params)
54    data.image_url_post_params = *search_provider.image_url_post_params;
55  data.favicon_url = GURL(search_provider.favicon_url);
56  data.show_in_default_list = true;
57  data.safe_for_autoreplace = false;
58  data.input_encodings.push_back(search_provider.encoding);
59  data.date_created = base::Time();
60  data.last_modified = base::Time();
61  data.prepopulate_id = 0;
62  if (search_provider.alternate_urls) {
63    for (size_t i = 0; i < search_provider.alternate_urls->size(); ++i) {
64      if (!search_provider.alternate_urls->at(i).empty())
65        data.alternate_urls.push_back(search_provider.alternate_urls->at(i));
66    }
67  }
68  return data;
69}
70}  // namespace
71
72SettingsOverridesAPI::SettingsOverridesAPI(Profile* profile)
73    : profile_(profile),
74      url_service_(TemplateURLServiceFactory::GetForProfile(profile)) {
75  DCHECK(profile);
76  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED,
77                 content::Source<Profile>(profile));
78  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED,
79                 content::Source<Profile>(profile));
80}
81
82SettingsOverridesAPI::~SettingsOverridesAPI() {
83}
84
85ProfileKeyedAPIFactory<SettingsOverridesAPI>*
86    SettingsOverridesAPI::GetFactoryInstance() {
87  return &g_factory.Get();
88}
89
90void SettingsOverridesAPI::SetPref(const std::string& extension_id,
91                                   const std::string& pref_key,
92                                   base::Value* value) {
93  PreferenceAPI::Get(profile_)->SetExtensionControlledPref(
94      extension_id,
95      pref_key,
96      kExtensionPrefsScopeRegular,
97      value);
98}
99
100void SettingsOverridesAPI::UnsetPref(const std::string& extension_id,
101                                     const std::string& pref_key) {
102  PreferenceAPI::Get(profile_)->RemoveExtensionControlledPref(
103      extension_id,
104      pref_key,
105      kExtensionPrefsScopeRegular);
106}
107
108void SettingsOverridesAPI::Observe(
109    int type,
110    const content::NotificationSource& source,
111    const content::NotificationDetails& details) {
112  switch (type) {
113    case chrome::NOTIFICATION_EXTENSION_LOADED: {
114      const Extension* extension =
115          content::Details<const Extension>(details).ptr();
116      const SettingsOverrides* settings =
117          SettingsOverrides::Get(extension);
118      if (settings) {
119        if (settings->homepage) {
120          SetPref(extension->id(), prefs::kHomePage,
121                  new base::StringValue(settings->homepage->spec()));
122          SetPref(extension->id(), prefs::kHomePageIsNewTabPage,
123                  new base::FundamentalValue(false));
124        }
125        if (!settings->startup_pages.empty()) {
126          SetPref(extension->id(), prefs::kRestoreOnStartup,
127                  new base::FundamentalValue(
128                      SessionStartupPref::kPrefValueURLs));
129          if (settings->startup_pages.size() > 1) {
130            VLOG(1) << extensions::ErrorUtils::FormatErrorMessage(
131                kManyStartupPagesWarning, manifest_keys::kSettingsOverride);
132          }
133          scoped_ptr<ListValue> url_list(new ListValue);
134          url_list->Append(new StringValue(settings->startup_pages[0].spec()));
135          SetPref(extension->id(), prefs::kURLsToRestoreOnStartup,
136                  url_list.release());
137        }
138        if (settings->search_engine) {
139          SetPref(extension->id(), prefs::kDefaultSearchProviderEnabled,
140                  new base::FundamentalValue(true));
141          DCHECK(url_service_);
142          if (url_service_->loaded()) {
143            RegisterSearchProvider(extension);
144          } else {
145            if (!template_url_sub_) {
146              template_url_sub_ = url_service_->RegisterOnLoadedCallback(
147                  base::Bind(&SettingsOverridesAPI::OnTemplateURLsLoaded,
148                             base::Unretained(this)));
149            }
150            url_service_->Load();
151            pending_extensions_.insert(extension);
152          }
153        }
154      }
155      break;
156    }
157    case chrome::NOTIFICATION_EXTENSION_UNLOADED: {
158      const Extension* extension =
159          content::Details<UnloadedExtensionInfo>(details)->extension;
160      const SettingsOverrides* settings = SettingsOverrides::Get(extension);
161      if (settings) {
162        if (settings->homepage) {
163          UnsetPref(extension->id(), prefs::kHomePage);
164          UnsetPref(extension->id(), prefs::kHomePageIsNewTabPage);
165        }
166        if (!settings->startup_pages.empty()) {
167          UnsetPref(extension->id(), prefs::kRestoreOnStartup);
168          UnsetPref(extension->id(), prefs::kURLsToRestoreOnStartup);
169        }
170        if (settings->search_engine) {
171          UnsetPref(extension->id(), prefs::kDefaultSearchProviderEnabled);
172          DCHECK(url_service_);
173          if (url_service_->loaded())
174            url_service_->RemoveExtensionControlledTURL(extension->id());
175          else
176            pending_extensions_.erase(extension);
177        }
178      }
179      break;
180    }
181    default: {
182      NOTREACHED();
183      break;
184    }
185  }
186}
187
188void SettingsOverridesAPI::Shutdown() {
189  template_url_sub_.reset();
190}
191
192void SettingsOverridesAPI::OnTemplateURLsLoaded() {
193  // Register search providers for pending extensions.
194  template_url_sub_.reset();
195  for (PendingExtensions::const_iterator i(pending_extensions_.begin());
196       i != pending_extensions_.end(); ++i) {
197    RegisterSearchProvider(*i);
198  }
199  pending_extensions_.clear();
200}
201
202void SettingsOverridesAPI::RegisterSearchProvider(
203    const Extension* extension) const {
204  DCHECK(url_service_);
205  DCHECK(extension);
206  const SettingsOverrides* settings = SettingsOverrides::Get(extension);
207  DCHECK(settings);
208  DCHECK(settings->search_engine);
209  scoped_ptr<AssociatedExtensionInfo> info(new AssociatedExtensionInfo);
210  info->extension_id = extension->id();
211  info->wants_to_be_default_engine = settings->search_engine->is_default;
212  info->install_time =
213      ExtensionPrefs::Get(profile_)->GetInstallTime(extension->id());
214  TemplateURLData data = ConvertSearchProvider(*settings->search_engine);
215  url_service_->AddExtensionControlledTURL(new TemplateURL(profile_, data),
216                                           info.Pass());
217}
218
219template <>
220void ProfileKeyedAPIFactory<SettingsOverridesAPI>::
221    DeclareFactoryDependencies() {
222  DependsOn(ExtensionPrefsFactory::GetInstance());
223  DependsOn(PreferenceAPI::GetFactoryInstance());
224  DependsOn(TemplateURLServiceFactory::GetInstance());
225}
226
227}  // namespace extensions
228