cros_settings.cc revision 4e180b6a0b4720a9b8e9e959a882386f690f08ff
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.
4
5#include "chrome/browser/chromeos/settings/cros_settings.h"
6
7#include "base/bind.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"
19
20namespace chromeos {
21
22static CrosSettings*  g_cros_settings = NULL;
23
24// static
25void CrosSettings::Initialize() {
26  CHECK(!g_cros_settings);
27  g_cros_settings = new CrosSettings(DeviceSettingsService::Get());
28}
29
30// static
31bool CrosSettings::IsInitialized() {
32  return g_cros_settings;
33}
34
35// static
36void CrosSettings::Shutdown() {
37  DCHECK(g_cros_settings);
38  delete g_cros_settings;
39  g_cros_settings = NULL;
40}
41
42// static
43CrosSettings* CrosSettings::Get() {
44  CHECK(g_cros_settings);
45  return g_cros_settings;
46}
47
48CrosSettings::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));
56  } else {
57    AddSettingsProvider(
58        new DeviceSettingsProvider(notify_cb, device_settings_service));
59  }
60  // System settings are not mocked currently.
61  AddSettingsProvider(new SystemSettingsProvider(notify_cb));
62}
63
64CrosSettings::~CrosSettings() {
65  STLDeleteElements(&providers_);
66  STLDeleteValues(&settings_observers_);
67}
68
69bool CrosSettings::IsCrosSettings(const std::string& path) {
70  return StartsWithASCII(path, kCrosSettingsPrefix, true);
71}
72
73void CrosSettings::Set(const std::string& path, const base::Value& in_value) {
74  DCHECK(CalledOnValidThread());
75  CrosSettingsProvider* provider;
76  provider = GetProvider(path);
77  if (provider)
78    provider->Set(path, in_value);
79}
80
81const base::Value* CrosSettings::GetPref(const std::string& path) const {
82  DCHECK(CalledOnValidThread());
83  CrosSettingsProvider* provider = GetProvider(path);
84  if (provider)
85    return provider->Get(path);
86  NOTREACHED() << path << " preference was not found in the signed settings.";
87  return NULL;
88}
89
90CrosSettingsProvider::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)
97      return status;
98  }
99  return CrosSettingsProvider::TRUSTED;
100}
101
102void CrosSettings::SetBoolean(const std::string& path, bool in_value) {
103  DCHECK(CalledOnValidThread());
104  base::FundamentalValue value(in_value);
105  Set(path, value);
106}
107
108void CrosSettings::SetInteger(const std::string& path, int in_value) {
109  DCHECK(CalledOnValidThread());
110  base::FundamentalValue value(in_value);
111  Set(path, value);
112}
113
114void CrosSettings::SetDouble(const std::string& path, double in_value) {
115  DCHECK(CalledOnValidThread());
116  base::FundamentalValue value(in_value);
117  Set(path, value);
118}
119
120void CrosSettings::SetString(const std::string& path,
121                             const std::string& in_value) {
122  DCHECK(CalledOnValidThread());
123  base::StringValue value(in_value);
124  Set(path, value);
125}
126
127void 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);
135}
136
137void 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);
145}
146
147bool CrosSettings::GetBoolean(const std::string& path,
148                              bool* bool_value) const {
149  DCHECK(CalledOnValidThread());
150  const base::Value* value = GetPref(path);
151  if (value)
152    return value->GetAsBoolean(bool_value);
153  return false;
154}
155
156bool CrosSettings::GetInteger(const std::string& path,
157                              int* out_value) const {
158  DCHECK(CalledOnValidThread());
159  const base::Value* value = GetPref(path);
160  if (value)
161    return value->GetAsInteger(out_value);
162  return false;
163}
164
165bool CrosSettings::GetDouble(const std::string& path,
166                             double* out_value) const {
167  DCHECK(CalledOnValidThread());
168  const base::Value* value = GetPref(path);
169  if (value)
170    return value->GetAsDouble(out_value);
171  return false;
172}
173
174bool CrosSettings::GetString(const std::string& path,
175                             std::string* out_value) const {
176  DCHECK(CalledOnValidThread());
177  const base::Value* value = GetPref(path);
178  if (value)
179    return value->GetAsString(out_value);
180  return false;
181}
182
183bool CrosSettings::GetList(const std::string& path,
184                           const base::ListValue** out_value) const {
185  DCHECK(CalledOnValidThread());
186  const base::Value* value = GetPref(path);
187  if (value)
188    return value->GetAsList(out_value);
189  return false;
190}
191
192bool CrosSettings::GetDictionary(
193    const std::string& path,
194    const base::DictionaryValue** out_value) const {
195  DCHECK(CalledOnValidThread());
196  const base::Value* value = GetPref(path);
197  if (value)
198    return value->GetAsDictionary(out_value);
199  return false;
200}
201
202bool CrosSettings::FindEmailInList(const std::string& path,
203                                   const std::string& email) const {
204  DCHECK(CalledOnValidThread());
205  std::string canonicalized_email(
206      gaia::CanonicalizeEmail(gaia::SanitizeEmail(email)));
207  std::string wildcard_email;
208  std::string::size_type at_pos = canonicalized_email.find('@');
209  if (at_pos != std::string::npos) {
210    wildcard_email =
211        std::string("*").append(canonicalized_email.substr(at_pos));
212  }
213
214  const base::ListValue* list;
215  if (!GetList(path, &list))
216    return false;
217  for (base::ListValue::const_iterator entry(list->begin());
218       entry != list->end();
219       ++entry) {
220    std::string entry_string;
221    if (!(*entry)->GetAsString(&entry_string)) {
222      NOTREACHED();
223      continue;
224    }
225    std::string canonicalized_entry(
226        gaia::CanonicalizeEmail(gaia::SanitizeEmail(entry_string)));
227
228    if (canonicalized_entry == canonicalized_email ||
229        canonicalized_entry == wildcard_email) {
230      return true;
231    }
232  }
233  return false;
234}
235
236bool CrosSettings::AddSettingsProvider(CrosSettingsProvider* provider) {
237  DCHECK(CalledOnValidThread());
238  providers_.push_back(provider);
239
240  // Allow the provider to notify this object when settings have changed.
241  // Providers instantiated inside this class will have the same callback
242  // passed to their constructor, but doing it here allows for providers
243  // to be instantiated outside this class.
244  CrosSettingsProvider::NotifyObserversCallback notify_cb(
245      base::Bind(&CrosSettings::FireObservers, base::Unretained(this)));
246  provider->SetNotifyObserversCallback(notify_cb);
247  return true;
248}
249
250bool CrosSettings::RemoveSettingsProvider(CrosSettingsProvider* provider) {
251  DCHECK(CalledOnValidThread());
252  std::vector<CrosSettingsProvider*>::iterator it =
253      std::find(providers_.begin(), providers_.end(), provider);
254  if (it != providers_.end()) {
255    providers_.erase(it);
256    return true;
257  }
258  return false;
259}
260
261scoped_ptr<CrosSettings::ObserverSubscription>
262CrosSettings::AddSettingsObserver(const std::string& path,
263                                  const base::Closure& callback) {
264  DCHECK(!path.empty());
265  DCHECK(!callback.is_null());
266  DCHECK(CalledOnValidThread());
267
268  if (!GetProvider(path)) {
269    NOTREACHED() << "Trying to add an observer for an unregistered setting: "
270                 << path;
271    return scoped_ptr<CrosSettings::ObserverSubscription>();
272  }
273
274  // Get the callback registry associated with the path.
275  base::CallbackList<void(void)>* registry = NULL;
276  SettingsObserverMap::iterator observer_iterator =
277      settings_observers_.find(path);
278  if (observer_iterator == settings_observers_.end()) {
279    registry = new base::CallbackList<void(void)>;
280    settings_observers_[path] = registry;
281  } else {
282    registry = observer_iterator->second;
283  }
284
285  return registry->Add(callback);
286}
287
288CrosSettingsProvider* CrosSettings::GetProvider(
289    const std::string& path) const {
290  for (size_t i = 0; i < providers_.size(); ++i) {
291    if (providers_[i]->HandlesSetting(path))
292      return providers_[i];
293  }
294  return NULL;
295}
296
297void CrosSettings::FireObservers(const std::string& path) {
298  DCHECK(CalledOnValidThread());
299  SettingsObserverMap::iterator observer_iterator =
300      settings_observers_.find(path);
301  if (observer_iterator == settings_observers_.end())
302    return;
303
304  observer_iterator->second->Notify();
305}
306
307ScopedTestCrosSettings::ScopedTestCrosSettings() {
308  CrosSettings::Initialize();
309}
310
311ScopedTestCrosSettings::~ScopedTestCrosSettings() {
312  CrosSettings::Shutdown();
313}
314
315}  // namespace chromeos
316