Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / extensions / api / preference / chrome_direct_setting_api.cc
blob20030ae66395018504a087e9a9352fd8649130fe
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/preference/chrome_direct_setting_api.h"
7 #include "base/bind.h"
8 #include "base/containers/hash_tables.h"
9 #include "base/lazy_instance.h"
10 #include "base/prefs/pref_change_registrar.h"
11 #include "base/prefs/pref_service.h"
12 #include "base/strings/stringprintf.h"
13 #include "chrome/browser/extensions/api/preference/preference_api_constants.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "extensions/browser/extension_registry.h"
17 namespace extensions {
18 namespace chromedirectsetting {
20 const char kOnPrefChangeFormat[] =
21 "types.private.ChromeDirectSetting.%s.onChange";
23 class PreferenceWhitelist {
24 public:
25 PreferenceWhitelist() {
26 // Note: DO NOT add any setting here that does not have a UI element in
27 // chrome://settings unless you write a component extension that is always
28 // installed. Otherwise, users may install your extension, the extension may
29 // toggle settings, and after the extension has been disabled/uninstalled
30 // the toggled setting remains in place. See http://crbug.com/164227#c157 .
31 whitelist_.insert("googlegeolocationaccess.enabled");
32 // The following settings need to be checked and probably removed. See
33 // http://crbug.com/164227#c157 .
34 whitelist_.insert("data_reduction.update_daily_lengths");
35 whitelist_.insert("easy_unlock.proximity_required");
38 ~PreferenceWhitelist() {}
40 bool IsPreferenceOnWhitelist(const std::string& pref_key){
41 return whitelist_.find(pref_key) != whitelist_.end();
44 void RegisterEventListeners(
45 Profile* profile,
46 EventRouter::Observer* observer) {
47 for (base::hash_set<std::string>::iterator iter = whitelist_.begin();
48 iter != whitelist_.end();
49 iter++) {
50 std::string event_name = base::StringPrintf(
51 kOnPrefChangeFormat,
52 (*iter).c_str());
53 EventRouter::Get(profile)->RegisterObserver(observer, event_name);
57 void RegisterPropertyListeners(
58 Profile* profile,
59 PrefChangeRegistrar* registrar,
60 const base::Callback<void(const std::string&)>& callback) {
61 for (base::hash_set<std::string>::iterator iter = whitelist_.begin();
62 iter != whitelist_.end();
63 iter++) {
64 const char* pref_key = (*iter).c_str();
65 std::string event_name = base::StringPrintf(
66 kOnPrefChangeFormat,
67 pref_key);
68 registrar->Add(pref_key, callback);
72 private:
73 base::hash_set<std::string> whitelist_;
75 DISALLOW_COPY_AND_ASSIGN(PreferenceWhitelist);
78 base::LazyInstance<PreferenceWhitelist> preference_whitelist =
79 LAZY_INSTANCE_INITIALIZER;
81 static base::LazyInstance<
82 BrowserContextKeyedAPIFactory<ChromeDirectSettingAPI> > g_factory =
83 LAZY_INSTANCE_INITIALIZER;
85 ChromeDirectSettingAPI::ChromeDirectSettingAPI(content::BrowserContext* context)
86 : profile_(Profile::FromBrowserContext(context)) {
87 preference_whitelist.Get().RegisterEventListeners(profile_, this);
90 ChromeDirectSettingAPI::~ChromeDirectSettingAPI() {}
92 // KeyedService implementation.
93 void ChromeDirectSettingAPI::Shutdown() {}
95 // BrowserContextKeyedAPI implementation.
96 BrowserContextKeyedAPIFactory<ChromeDirectSettingAPI>*
97 ChromeDirectSettingAPI::GetFactoryInstance() {
98 return g_factory.Pointer();
101 // EventRouter::Observer implementation.
102 void ChromeDirectSettingAPI::OnListenerAdded(const EventListenerInfo& details) {
103 EventRouter::Get(profile_)->UnregisterObserver(this);
104 registrar_.Init(profile_->GetPrefs());
105 preference_whitelist.Get().RegisterPropertyListeners(
106 profile_,
107 &registrar_,
108 base::Bind(&ChromeDirectSettingAPI::OnPrefChanged,
109 base::Unretained(this),
110 registrar_.prefs()));
113 bool ChromeDirectSettingAPI::IsPreferenceOnWhitelist(
114 const std::string& pref_key) {
115 return preference_whitelist.Get().IsPreferenceOnWhitelist(pref_key);
118 ChromeDirectSettingAPI* ChromeDirectSettingAPI::Get(
119 content::BrowserContext* context) {
120 return BrowserContextKeyedAPIFactory<ChromeDirectSettingAPI>::Get(context);
123 // BrowserContextKeyedAPI implementation.
124 const char* ChromeDirectSettingAPI::service_name() {
125 return "ChromeDirectSettingAPI";
128 void ChromeDirectSettingAPI::OnPrefChanged(
129 PrefService* pref_service, const std::string& pref_key) {
130 std::string event_name = base::StringPrintf(kOnPrefChangeFormat,
131 pref_key.c_str());
132 EventRouter* router = EventRouter::Get(profile_);
133 if (router && router->HasEventListener(event_name)) {
134 const PrefService::Preference* preference =
135 profile_->GetPrefs()->FindPreference(pref_key.c_str());
136 const base::Value* value = preference->GetValue();
138 scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue);
139 result->Set(preference_api_constants::kValue, value->DeepCopy());
140 base::ListValue args;
141 args.Append(result.release());
143 for (const scoped_refptr<const extensions::Extension>& extension :
144 ExtensionRegistry::Get(profile_)->enabled_extensions()) {
145 const std::string& extension_id = extension->id();
146 if (router->ExtensionHasEventListener(extension_id, event_name)) {
147 scoped_ptr<base::ListValue> args_copy(args.DeepCopy());
148 // TODO(kalman): Have a histogram value for each pref type.
149 // This isn't so important for the current use case of these
150 // histograms, which is to track which event types are waking up event
151 // pages, or which are delivered to persistent background pages. Simply
152 // "a setting changed" is enough detail for that. However if we try to
153 // use these histograms for any fine-grained logic (like removing the
154 // string event name altogether), or if we discover this event is
155 // firing a lot and want to understand that better, then this will need
156 // to change.
157 events::HistogramValue histogram_value =
158 events::TYPES_PRIVATE_CHROME_DIRECT_SETTING_ON_CHANGE;
159 scoped_ptr<Event> event(
160 new Event(histogram_value, event_name, args_copy.Pass()));
161 router->DispatchEventToExtension(extension_id, event.Pass());
167 } // namespace chromedirectsetting
168 } // namespace extensions