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