| // Copyright 2013 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/extensions/api/preference/chrome_direct_setting_api.h" |
| |
| #include "base/bind.h" |
| #include "base/containers/hash_tables.h" |
| #include "base/lazy_instance.h" |
| #include "base/prefs/pref_change_registrar.h" |
| #include "base/prefs/pref_service.h" |
| #include "base/strings/stringprintf.h" |
| #include "chrome/browser/extensions/api/preference/preference_api_constants.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "extensions/browser/extension_registry.h" |
| |
| namespace extensions { |
| namespace chromedirectsetting { |
| |
| const char kOnPrefChangeFormat[] = |
| "types.private.ChromeDirectSetting.%s.onChange"; |
| |
| class PreferenceWhitelist { |
| public: |
| PreferenceWhitelist() { |
| // Note: DO NOT add any setting here that does not have a UI element in |
| // chrome://settings unless you write a component extension that is always |
| // installed. Otherwise, users may install your extension, the extension may |
| // toggle settings, and after the extension has been disabled/uninstalled |
| // the toggled setting remains in place. See http://crbug.com/164227#c157 . |
| whitelist_.insert("googlegeolocationaccess.enabled"); |
| // The following settings need to be checked and probably removed. See |
| // http://crbug.com/164227#c157 . |
| whitelist_.insert("spdy_proxy.enabled"); |
| whitelist_.insert("data_reduction.daily_original_length"); |
| whitelist_.insert("data_reduction.daily_received_length"); |
| whitelist_.insert("data_reduction.update_daily_lengths"); |
| whitelist_.insert("easy_unlock.proximity_required"); |
| } |
| |
| ~PreferenceWhitelist() {} |
| |
| bool IsPreferenceOnWhitelist(const std::string& pref_key){ |
| return whitelist_.find(pref_key) != whitelist_.end(); |
| } |
| |
| void RegisterEventListeners( |
| Profile* profile, |
| EventRouter::Observer* observer) { |
| for (base::hash_set<std::string>::iterator iter = whitelist_.begin(); |
| iter != whitelist_.end(); |
| iter++) { |
| std::string event_name = base::StringPrintf( |
| kOnPrefChangeFormat, |
| (*iter).c_str()); |
| EventRouter::Get(profile)->RegisterObserver(observer, event_name); |
| } |
| } |
| |
| void RegisterPropertyListeners( |
| Profile* profile, |
| PrefChangeRegistrar* registrar, |
| const base::Callback<void(const std::string&)>& callback) { |
| for (base::hash_set<std::string>::iterator iter = whitelist_.begin(); |
| iter != whitelist_.end(); |
| iter++) { |
| const char* pref_key = (*iter).c_str(); |
| std::string event_name = base::StringPrintf( |
| kOnPrefChangeFormat, |
| pref_key); |
| registrar->Add(pref_key, callback); |
| } |
| } |
| |
| private: |
| base::hash_set<std::string> whitelist_; |
| |
| DISALLOW_COPY_AND_ASSIGN(PreferenceWhitelist); |
| }; |
| |
| base::LazyInstance<PreferenceWhitelist> preference_whitelist = |
| LAZY_INSTANCE_INITIALIZER; |
| |
| static base::LazyInstance< |
| BrowserContextKeyedAPIFactory<ChromeDirectSettingAPI> > g_factory = |
| LAZY_INSTANCE_INITIALIZER; |
| |
| ChromeDirectSettingAPI::ChromeDirectSettingAPI(content::BrowserContext* context) |
| : profile_(Profile::FromBrowserContext(context)) { |
| preference_whitelist.Get().RegisterEventListeners(profile_, this); |
| } |
| |
| ChromeDirectSettingAPI::~ChromeDirectSettingAPI() {} |
| |
| // KeyedService implementation. |
| void ChromeDirectSettingAPI::Shutdown() {} |
| |
| // BrowserContextKeyedAPI implementation. |
| BrowserContextKeyedAPIFactory<ChromeDirectSettingAPI>* |
| ChromeDirectSettingAPI::GetFactoryInstance() { |
| return g_factory.Pointer(); |
| } |
| |
| // EventRouter::Observer implementation. |
| void ChromeDirectSettingAPI::OnListenerAdded(const EventListenerInfo& details) { |
| EventRouter::Get(profile_)->UnregisterObserver(this); |
| registrar_.Init(profile_->GetPrefs()); |
| preference_whitelist.Get().RegisterPropertyListeners( |
| profile_, |
| ®istrar_, |
| base::Bind(&ChromeDirectSettingAPI::OnPrefChanged, |
| base::Unretained(this), |
| registrar_.prefs())); |
| } |
| |
| bool ChromeDirectSettingAPI::IsPreferenceOnWhitelist( |
| const std::string& pref_key) { |
| return preference_whitelist.Get().IsPreferenceOnWhitelist(pref_key); |
| } |
| |
| ChromeDirectSettingAPI* ChromeDirectSettingAPI::Get( |
| content::BrowserContext* context) { |
| return BrowserContextKeyedAPIFactory<ChromeDirectSettingAPI>::Get(context); |
| } |
| |
| // BrowserContextKeyedAPI implementation. |
| const char* ChromeDirectSettingAPI::service_name() { |
| return "ChromeDirectSettingAPI"; |
| } |
| |
| void ChromeDirectSettingAPI::OnPrefChanged( |
| PrefService* pref_service, const std::string& pref_key) { |
| std::string event_name = base::StringPrintf(kOnPrefChangeFormat, |
| pref_key.c_str()); |
| EventRouter* router = EventRouter::Get(profile_); |
| if (router && router->HasEventListener(event_name)) { |
| const PrefService::Preference* preference = |
| profile_->GetPrefs()->FindPreference(pref_key.c_str()); |
| const base::Value* value = preference->GetValue(); |
| |
| scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue); |
| result->Set(preference_api_constants::kValue, value->DeepCopy()); |
| base::ListValue args; |
| args.Append(result.release()); |
| |
| for (const scoped_refptr<const extensions::Extension>& extension : |
| ExtensionRegistry::Get(profile_)->enabled_extensions()) { |
| const std::string& extension_id = extension->id(); |
| if (router->ExtensionHasEventListener(extension_id, event_name)) { |
| scoped_ptr<base::ListValue> args_copy(args.DeepCopy()); |
| scoped_ptr<Event> event(new Event(event_name, args_copy.Pass())); |
| router->DispatchEventToExtension(extension_id, event.Pass()); |
| } |
| } |
| } |
| } |
| |
| } // namespace chromedirectsetting |
| } // namespace extensions |