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"
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
{
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(
46 EventRouter::Observer
* observer
) {
47 for (base::hash_set
<std::string
>::iterator iter
= whitelist_
.begin();
48 iter
!= whitelist_
.end();
50 std::string event_name
= base::StringPrintf(
53 EventRouter::Get(profile
)->RegisterObserver(observer
, event_name
);
57 void RegisterPropertyListeners(
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();
64 const char* pref_key
= (*iter
).c_str();
65 std::string event_name
= base::StringPrintf(
68 registrar
->Add(pref_key
, callback
);
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(
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
,
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
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