1 // Copyright (c) 2012 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/chromeos/settings/cros_settings.h"
8 #include "base/command_line.h"
9 #include "base/logging.h"
10 #include "base/stl_util.h"
11 #include "base/strings/string_util.h"
12 #include "base/values.h"
13 #include "chrome/browser/chromeos/settings/device_settings_provider.h"
14 #include "chrome/browser/chromeos/settings/device_settings_service.h"
15 #include "chrome/browser/chromeos/settings/stub_cros_settings_provider.h"
16 #include "chrome/browser/chromeos/settings/system_settings_provider.h"
17 #include "chromeos/chromeos_switches.h"
18 #include "google_apis/gaia/gaia_auth_util.h"
22 static CrosSettings
* g_cros_settings
= NULL
;
25 void CrosSettings::Initialize() {
26 CHECK(!g_cros_settings
);
27 g_cros_settings
= new CrosSettings(DeviceSettingsService::Get());
31 bool CrosSettings::IsInitialized() {
32 return g_cros_settings
;
36 void CrosSettings::Shutdown() {
37 DCHECK(g_cros_settings
);
38 delete g_cros_settings
;
39 g_cros_settings
= NULL
;
43 CrosSettings
* CrosSettings::Get() {
44 CHECK(g_cros_settings
);
45 return g_cros_settings
;
48 CrosSettings::CrosSettings(DeviceSettingsService
* device_settings_service
) {
49 CrosSettingsProvider::NotifyObserversCallback
notify_cb(
50 base::Bind(&CrosSettings::FireObservers
,
51 // This is safe since |this| is never deleted.
52 base::Unretained(this)));
53 if (CommandLine::ForCurrentProcess()->HasSwitch(
54 switches::kStubCrosSettings
)) {
55 AddSettingsProvider(new StubCrosSettingsProvider(notify_cb
));
58 new DeviceSettingsProvider(notify_cb
, device_settings_service
));
60 // System settings are not mocked currently.
61 AddSettingsProvider(new SystemSettingsProvider(notify_cb
));
64 CrosSettings::~CrosSettings() {
65 STLDeleteElements(&providers_
);
66 STLDeleteValues(&settings_observers_
);
69 bool CrosSettings::IsCrosSettings(const std::string
& path
) {
70 return StartsWithASCII(path
, kCrosSettingsPrefix
, true);
73 void CrosSettings::Set(const std::string
& path
, const base::Value
& in_value
) {
74 DCHECK(CalledOnValidThread());
75 CrosSettingsProvider
* provider
;
76 provider
= GetProvider(path
);
78 provider
->Set(path
, in_value
);
81 const base::Value
* CrosSettings::GetPref(const std::string
& path
) const {
82 DCHECK(CalledOnValidThread());
83 CrosSettingsProvider
* provider
= GetProvider(path
);
85 return provider
->Get(path
);
86 NOTREACHED() << path
<< " preference was not found in the signed settings.";
90 CrosSettingsProvider::TrustedStatus
CrosSettings::PrepareTrustedValues(
91 const base::Closure
& callback
) const {
92 DCHECK(CalledOnValidThread());
93 for (size_t i
= 0; i
< providers_
.size(); ++i
) {
94 CrosSettingsProvider::TrustedStatus status
=
95 providers_
[i
]->PrepareTrustedValues(callback
);
96 if (status
!= CrosSettingsProvider::TRUSTED
)
99 return CrosSettingsProvider::TRUSTED
;
102 void CrosSettings::SetBoolean(const std::string
& path
, bool in_value
) {
103 DCHECK(CalledOnValidThread());
104 base::FundamentalValue
value(in_value
);
108 void CrosSettings::SetInteger(const std::string
& path
, int in_value
) {
109 DCHECK(CalledOnValidThread());
110 base::FundamentalValue
value(in_value
);
114 void CrosSettings::SetDouble(const std::string
& path
, double in_value
) {
115 DCHECK(CalledOnValidThread());
116 base::FundamentalValue
value(in_value
);
120 void CrosSettings::SetString(const std::string
& path
,
121 const std::string
& in_value
) {
122 DCHECK(CalledOnValidThread());
123 base::StringValue
value(in_value
);
127 void CrosSettings::AppendToList(const std::string
& path
,
128 const base::Value
* value
) {
129 DCHECK(CalledOnValidThread());
130 const base::Value
* old_value
= GetPref(path
);
131 scoped_ptr
<base::Value
> new_value(
132 old_value
? old_value
->DeepCopy() : new base::ListValue());
133 static_cast<base::ListValue
*>(new_value
.get())->Append(value
->DeepCopy());
134 Set(path
, *new_value
);
137 void CrosSettings::RemoveFromList(const std::string
& path
,
138 const base::Value
* value
) {
139 DCHECK(CalledOnValidThread());
140 const base::Value
* old_value
= GetPref(path
);
141 scoped_ptr
<base::Value
> new_value(
142 old_value
? old_value
->DeepCopy() : new base::ListValue());
143 static_cast<base::ListValue
*>(new_value
.get())->Remove(*value
, NULL
);
144 Set(path
, *new_value
);
147 bool CrosSettings::GetBoolean(const std::string
& path
,
148 bool* bool_value
) const {
149 DCHECK(CalledOnValidThread());
150 const base::Value
* value
= GetPref(path
);
152 return value
->GetAsBoolean(bool_value
);
156 bool CrosSettings::GetInteger(const std::string
& path
,
157 int* out_value
) const {
158 DCHECK(CalledOnValidThread());
159 const base::Value
* value
= GetPref(path
);
161 return value
->GetAsInteger(out_value
);
165 bool CrosSettings::GetDouble(const std::string
& path
,
166 double* out_value
) const {
167 DCHECK(CalledOnValidThread());
168 const base::Value
* value
= GetPref(path
);
170 return value
->GetAsDouble(out_value
);
174 bool CrosSettings::GetString(const std::string
& path
,
175 std::string
* out_value
) const {
176 DCHECK(CalledOnValidThread());
177 const base::Value
* value
= GetPref(path
);
179 return value
->GetAsString(out_value
);
183 bool CrosSettings::GetList(const std::string
& path
,
184 const base::ListValue
** out_value
) const {
185 DCHECK(CalledOnValidThread());
186 const base::Value
* value
= GetPref(path
);
188 return value
->GetAsList(out_value
);
192 bool CrosSettings::GetDictionary(
193 const std::string
& path
,
194 const base::DictionaryValue
** out_value
) const {
195 DCHECK(CalledOnValidThread());
196 const base::Value
* value
= GetPref(path
);
198 return value
->GetAsDictionary(out_value
);
202 bool CrosSettings::FindEmailInList(const std::string
& path
,
203 const std::string
& email
,
204 bool* wildcard_match
) const {
205 DCHECK(CalledOnValidThread());
206 std::string
canonicalized_email(
207 gaia::CanonicalizeEmail(gaia::SanitizeEmail(email
)));
208 std::string wildcard_email
;
209 std::string::size_type at_pos
= canonicalized_email
.find('@');
210 if (at_pos
!= std::string::npos
) {
212 std::string("*").append(canonicalized_email
.substr(at_pos
));
216 *wildcard_match
= false;
218 const base::ListValue
* list
;
219 if (!GetList(path
, &list
))
222 bool found_wildcard_match
= false;
223 for (base::ListValue::const_iterator
entry(list
->begin());
224 entry
!= list
->end();
226 std::string entry_string
;
227 if (!(*entry
)->GetAsString(&entry_string
)) {
231 std::string
canonicalized_entry(
232 gaia::CanonicalizeEmail(gaia::SanitizeEmail(entry_string
)));
234 if (canonicalized_entry
!= wildcard_email
&&
235 canonicalized_entry
== canonicalized_email
) {
239 // If there is a wildcard match, don't exit early. There might be an exact
240 // match further down the list that should take precedence if present.
241 if (canonicalized_entry
== wildcard_email
)
242 found_wildcard_match
= true;
246 *wildcard_match
= found_wildcard_match
;
248 return found_wildcard_match
;
251 bool CrosSettings::AddSettingsProvider(CrosSettingsProvider
* provider
) {
252 DCHECK(CalledOnValidThread());
253 providers_
.push_back(provider
);
255 // Allow the provider to notify this object when settings have changed.
256 // Providers instantiated inside this class will have the same callback
257 // passed to their constructor, but doing it here allows for providers
258 // to be instantiated outside this class.
259 CrosSettingsProvider::NotifyObserversCallback
notify_cb(
260 base::Bind(&CrosSettings::FireObservers
, base::Unretained(this)));
261 provider
->SetNotifyObserversCallback(notify_cb
);
265 bool CrosSettings::RemoveSettingsProvider(CrosSettingsProvider
* provider
) {
266 DCHECK(CalledOnValidThread());
267 std::vector
<CrosSettingsProvider
*>::iterator it
=
268 std::find(providers_
.begin(), providers_
.end(), provider
);
269 if (it
!= providers_
.end()) {
270 providers_
.erase(it
);
276 scoped_ptr
<CrosSettings::ObserverSubscription
>
277 CrosSettings::AddSettingsObserver(const std::string
& path
,
278 const base::Closure
& callback
) {
279 DCHECK(!path
.empty());
280 DCHECK(!callback
.is_null());
281 DCHECK(CalledOnValidThread());
283 if (!GetProvider(path
)) {
284 NOTREACHED() << "Trying to add an observer for an unregistered setting: "
286 return scoped_ptr
<CrosSettings::ObserverSubscription
>();
289 // Get the callback registry associated with the path.
290 base::CallbackList
<void(void)>* registry
= NULL
;
291 SettingsObserverMap::iterator observer_iterator
=
292 settings_observers_
.find(path
);
293 if (observer_iterator
== settings_observers_
.end()) {
294 registry
= new base::CallbackList
<void(void)>;
295 settings_observers_
[path
] = registry
;
297 registry
= observer_iterator
->second
;
300 return registry
->Add(callback
);
303 CrosSettingsProvider
* CrosSettings::GetProvider(
304 const std::string
& path
) const {
305 for (size_t i
= 0; i
< providers_
.size(); ++i
) {
306 if (providers_
[i
]->HandlesSetting(path
))
307 return providers_
[i
];
312 void CrosSettings::FireObservers(const std::string
& path
) {
313 DCHECK(CalledOnValidThread());
314 SettingsObserverMap::iterator observer_iterator
=
315 settings_observers_
.find(path
);
316 if (observer_iterator
== settings_observers_
.end())
319 observer_iterator
->second
->Notify();
322 ScopedTestCrosSettings::ScopedTestCrosSettings() {
323 CrosSettings::Initialize();
326 ScopedTestCrosSettings::~ScopedTestCrosSettings() {
327 CrosSettings::Shutdown();
330 } // namespace chromeos