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