cros_settings.cc revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
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/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 "chrome/common/chrome_notification_types.h" 18#include "chrome/common/chrome_switches.h" 19#include "content/public/browser/notification_details.h" 20#include "content/public/browser/notification_source.h" 21#include "content/public/browser/notification_types.h" 22#include "google_apis/gaia/gaia_auth_util.h" 23 24namespace chromeos { 25 26static CrosSettings* g_cros_settings = NULL; 27 28// static 29void CrosSettings::Initialize() { 30 CHECK(!g_cros_settings); 31 g_cros_settings = new CrosSettings(); 32} 33 34// static 35bool CrosSettings::IsInitialized() { 36 return g_cros_settings; 37} 38 39// static 40void CrosSettings::Shutdown() { 41 DCHECK(g_cros_settings); 42 delete g_cros_settings; 43 g_cros_settings = NULL; 44} 45 46// static 47CrosSettings* CrosSettings::Get() { 48 CHECK(g_cros_settings); 49 return g_cros_settings; 50} 51 52bool CrosSettings::IsCrosSettings(const std::string& path) { 53 return StartsWithASCII(path, kCrosSettingsPrefix, true); 54} 55 56void CrosSettings::Set(const std::string& path, const base::Value& in_value) { 57 DCHECK(CalledOnValidThread()); 58 CrosSettingsProvider* provider; 59 provider = GetProvider(path); 60 if (provider) 61 provider->Set(path, in_value); 62} 63 64const base::Value* CrosSettings::GetPref(const std::string& path) const { 65 DCHECK(CalledOnValidThread()); 66 CrosSettingsProvider* provider = GetProvider(path); 67 if (provider) 68 return provider->Get(path); 69 NOTREACHED() << path << " preference was not found in the signed settings."; 70 return NULL; 71} 72 73CrosSettingsProvider::TrustedStatus CrosSettings::PrepareTrustedValues( 74 const base::Closure& callback) const { 75 DCHECK(CalledOnValidThread()); 76 for (size_t i = 0; i < providers_.size(); ++i) { 77 CrosSettingsProvider::TrustedStatus status = 78 providers_[i]->PrepareTrustedValues(callback); 79 if (status != CrosSettingsProvider::TRUSTED) 80 return status; 81 } 82 return CrosSettingsProvider::TRUSTED; 83} 84 85void CrosSettings::SetBoolean(const std::string& path, bool in_value) { 86 DCHECK(CalledOnValidThread()); 87 base::FundamentalValue value(in_value); 88 Set(path, value); 89} 90 91void CrosSettings::SetInteger(const std::string& path, int in_value) { 92 DCHECK(CalledOnValidThread()); 93 base::FundamentalValue value(in_value); 94 Set(path, value); 95} 96 97void CrosSettings::SetDouble(const std::string& path, double in_value) { 98 DCHECK(CalledOnValidThread()); 99 base::FundamentalValue value(in_value); 100 Set(path, value); 101} 102 103void CrosSettings::SetString(const std::string& path, 104 const std::string& in_value) { 105 DCHECK(CalledOnValidThread()); 106 base::StringValue value(in_value); 107 Set(path, value); 108} 109 110void CrosSettings::AppendToList(const std::string& path, 111 const base::Value* value) { 112 DCHECK(CalledOnValidThread()); 113 const base::Value* old_value = GetPref(path); 114 scoped_ptr<base::Value> new_value( 115 old_value ? old_value->DeepCopy() : new base::ListValue()); 116 static_cast<base::ListValue*>(new_value.get())->Append(value->DeepCopy()); 117 Set(path, *new_value); 118} 119 120void CrosSettings::RemoveFromList(const std::string& path, 121 const base::Value* value) { 122 DCHECK(CalledOnValidThread()); 123 const base::Value* old_value = GetPref(path); 124 scoped_ptr<base::Value> new_value( 125 old_value ? old_value->DeepCopy() : new base::ListValue()); 126 static_cast<base::ListValue*>(new_value.get())->Remove(*value, NULL); 127 Set(path, *new_value); 128} 129 130bool CrosSettings::GetBoolean(const std::string& path, 131 bool* bool_value) const { 132 DCHECK(CalledOnValidThread()); 133 const base::Value* value = GetPref(path); 134 if (value) 135 return value->GetAsBoolean(bool_value); 136 return false; 137} 138 139bool CrosSettings::GetInteger(const std::string& path, 140 int* out_value) const { 141 DCHECK(CalledOnValidThread()); 142 const base::Value* value = GetPref(path); 143 if (value) 144 return value->GetAsInteger(out_value); 145 return false; 146} 147 148bool CrosSettings::GetDouble(const std::string& path, 149 double* out_value) const { 150 DCHECK(CalledOnValidThread()); 151 const base::Value* value = GetPref(path); 152 if (value) 153 return value->GetAsDouble(out_value); 154 return false; 155} 156 157bool CrosSettings::GetString(const std::string& path, 158 std::string* out_value) const { 159 DCHECK(CalledOnValidThread()); 160 const base::Value* value = GetPref(path); 161 if (value) 162 return value->GetAsString(out_value); 163 return false; 164} 165 166bool CrosSettings::GetList(const std::string& path, 167 const base::ListValue** out_value) const { 168 DCHECK(CalledOnValidThread()); 169 const base::Value* value = GetPref(path); 170 if (value) 171 return value->GetAsList(out_value); 172 return false; 173} 174 175bool CrosSettings::GetDictionary( 176 const std::string& path, 177 const base::DictionaryValue** out_value) const { 178 DCHECK(CalledOnValidThread()); 179 const base::Value* value = GetPref(path); 180 if (value) 181 return value->GetAsDictionary(out_value); 182 return false; 183} 184 185bool CrosSettings::FindEmailInList(const std::string& path, 186 const std::string& email) const { 187 DCHECK(CalledOnValidThread()); 188 std::string canonicalized_email( 189 gaia::CanonicalizeEmail(gaia::SanitizeEmail(email))); 190 std::string wildcard_email; 191 std::string::size_type at_pos = canonicalized_email.find('@'); 192 if (at_pos != std::string::npos) { 193 wildcard_email = 194 std::string("*").append(canonicalized_email.substr(at_pos)); 195 } 196 197 const base::ListValue* list; 198 if (!GetList(path, &list)) 199 return false; 200 for (base::ListValue::const_iterator entry(list->begin()); 201 entry != list->end(); 202 ++entry) { 203 std::string entry_string; 204 if (!(*entry)->GetAsString(&entry_string)) { 205 NOTREACHED(); 206 continue; 207 } 208 std::string canonicalized_entry( 209 gaia::CanonicalizeEmail(gaia::SanitizeEmail(entry_string))); 210 211 if (canonicalized_entry == canonicalized_email || 212 canonicalized_entry == wildcard_email) { 213 return true; 214 } 215 } 216 return false; 217} 218 219bool CrosSettings::AddSettingsProvider(CrosSettingsProvider* provider) { 220 DCHECK(CalledOnValidThread()); 221 providers_.push_back(provider); 222 223 // Allow the provider to notify this object when settings have changed. 224 // Providers instantiated inside this class will have the same callback 225 // passed to their constructor, but doing it here allows for providers 226 // to be instantiated outside this class. 227 CrosSettingsProvider::NotifyObserversCallback notify_cb( 228 base::Bind(&CrosSettings::FireObservers, base::Unretained(this))); 229 provider->SetNotifyObserversCallback(notify_cb); 230 return true; 231} 232 233bool CrosSettings::RemoveSettingsProvider(CrosSettingsProvider* provider) { 234 DCHECK(CalledOnValidThread()); 235 std::vector<CrosSettingsProvider*>::iterator it = 236 std::find(providers_.begin(), providers_.end(), provider); 237 if (it != providers_.end()) { 238 providers_.erase(it); 239 return true; 240 } 241 return false; 242} 243 244void CrosSettings::AddSettingsObserver(const char* path, 245 content::NotificationObserver* obs) { 246 DCHECK(path); 247 DCHECK(obs); 248 DCHECK(CalledOnValidThread()); 249 250 if (!GetProvider(std::string(path))) { 251 NOTREACHED() << "Trying to add an observer for an unregistered setting: " 252 << path; 253 return; 254 } 255 256 // Get the settings observer list associated with the path. 257 NotificationObserverList* observer_list = NULL; 258 SettingsObserverMap::iterator observer_iterator = 259 settings_observers_.find(path); 260 if (observer_iterator == settings_observers_.end()) { 261 observer_list = new NotificationObserverList; 262 settings_observers_[path] = observer_list; 263 } else { 264 observer_list = observer_iterator->second; 265 } 266 267 // Verify that this observer doesn't already exist. 268 NotificationObserverList::Iterator it(*observer_list); 269 content::NotificationObserver* existing_obs; 270 while ((existing_obs = it.GetNext()) != NULL) { 271 if (existing_obs == obs) 272 return; 273 } 274 275 // Ok, safe to add the pref observer. 276 observer_list->AddObserver(obs); 277} 278 279void CrosSettings::RemoveSettingsObserver(const char* path, 280 content::NotificationObserver* obs) { 281 DCHECK(CalledOnValidThread()); 282 283 SettingsObserverMap::iterator observer_iterator = 284 settings_observers_.find(path); 285 if (observer_iterator == settings_observers_.end()) 286 return; 287 288 NotificationObserverList* observer_list = observer_iterator->second; 289 observer_list->RemoveObserver(obs); 290} 291 292CrosSettingsProvider* CrosSettings::GetProvider( 293 const std::string& path) const { 294 for (size_t i = 0; i < providers_.size(); ++i) { 295 if (providers_[i]->HandlesSetting(path)) 296 return providers_[i]; 297 } 298 return NULL; 299} 300 301CrosSettings::CrosSettings() { 302 CrosSettingsProvider::NotifyObserversCallback notify_cb( 303 base::Bind(&CrosSettings::FireObservers, 304 // This is safe since |this| is never deleted. 305 base::Unretained(this))); 306 if (CommandLine::ForCurrentProcess()->HasSwitch( 307 switches::kStubCrosSettings)) { 308 AddSettingsProvider(new StubCrosSettingsProvider(notify_cb)); 309 } else { 310 AddSettingsProvider( 311 new DeviceSettingsProvider(notify_cb, DeviceSettingsService::Get())); 312 } 313 // System settings are not mocked currently. 314 AddSettingsProvider(new SystemSettingsProvider(notify_cb)); 315} 316 317CrosSettings::~CrosSettings() { 318 STLDeleteElements(&providers_); 319 STLDeleteValues(&settings_observers_); 320} 321 322void CrosSettings::FireObservers(const std::string& path) { 323 DCHECK(CalledOnValidThread()); 324 SettingsObserverMap::iterator observer_iterator = 325 settings_observers_.find(path); 326 if (observer_iterator == settings_observers_.end()) 327 return; 328 329 NotificationObserverList::Iterator it(*(observer_iterator->second)); 330 content::NotificationObserver* observer; 331 while ((observer = it.GetNext()) != NULL) { 332 observer->Observe(chrome::NOTIFICATION_SYSTEM_SETTING_CHANGED, 333 content::Source<CrosSettings>(this), 334 content::Details<const std::string>(&path)); 335 } 336} 337 338ScopedTestCrosSettings::ScopedTestCrosSettings() { 339 CrosSettings::Initialize(); 340} 341 342ScopedTestCrosSettings::~ScopedTestCrosSettings() { 343 CrosSettings::Shutdown(); 344} 345 346} // namespace chromeos 347