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/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 
     20 namespace chromeos {
     21 
     22 static CrosSettings*  g_cros_settings = NULL;
     23 
     24 // static
     25 void CrosSettings::Initialize() {
     26   CHECK(!g_cros_settings);
     27   g_cros_settings = new CrosSettings(DeviceSettingsService::Get());
     28 }
     29 
     30 // static
     31 bool CrosSettings::IsInitialized() {
     32   return g_cros_settings;
     33 }
     34 
     35 // static
     36 void CrosSettings::Shutdown() {
     37   DCHECK(g_cros_settings);
     38   delete g_cros_settings;
     39   g_cros_settings = NULL;
     40 }
     41 
     42 // static
     43 CrosSettings* CrosSettings::Get() {
     44   CHECK(g_cros_settings);
     45   return g_cros_settings;
     46 }
     47 
     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));
     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 
     64 CrosSettings::~CrosSettings() {
     65   STLDeleteElements(&providers_);
     66   STLDeleteValues(&settings_observers_);
     67 }
     68 
     69 bool CrosSettings::IsCrosSettings(const std::string& path) {
     70   return StartsWithASCII(path, kCrosSettingsPrefix, true);
     71 }
     72 
     73 void 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 
     81 const 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 
     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)
     97       return status;
     98   }
     99   return CrosSettingsProvider::TRUSTED;
    100 }
    101 
    102 void CrosSettings::SetBoolean(const std::string& path, bool in_value) {
    103   DCHECK(CalledOnValidThread());
    104   base::FundamentalValue value(in_value);
    105   Set(path, value);
    106 }
    107 
    108 void CrosSettings::SetInteger(const std::string& path, int in_value) {
    109   DCHECK(CalledOnValidThread());
    110   base::FundamentalValue value(in_value);
    111   Set(path, value);
    112 }
    113 
    114 void CrosSettings::SetDouble(const std::string& path, double in_value) {
    115   DCHECK(CalledOnValidThread());
    116   base::FundamentalValue value(in_value);
    117   Set(path, value);
    118 }
    119 
    120 void 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 
    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);
    135 }
    136 
    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);
    145 }
    146 
    147 bool 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 
    156 bool 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 
    165 bool 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 
    174 bool 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 
    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);
    187   if (value)
    188     return value->GetAsList(out_value);
    189   return false;
    190 }
    191 
    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);
    197   if (value)
    198     return value->GetAsDictionary(out_value);
    199   return false;
    200 }
    201 
    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) {
    211     wildcard_email =
    212         std::string("*").append(canonicalized_email.substr(at_pos));
    213   }
    214 
    215   if (wildcard_match)
    216     *wildcard_match = false;
    217 
    218   const base::ListValue* list;
    219   if (!GetList(path, &list))
    220     return false;
    221 
    222   bool found_wildcard_match = false;
    223   for (base::ListValue::const_iterator entry(list->begin());
    224        entry != list->end();
    225        ++entry) {
    226     std::string entry_string;
    227     if (!(*entry)->GetAsString(&entry_string)) {
    228       NOTREACHED();
    229       continue;
    230     }
    231     std::string canonicalized_entry(
    232         gaia::CanonicalizeEmail(gaia::SanitizeEmail(entry_string)));
    233 
    234     if (canonicalized_entry != wildcard_email &&
    235         canonicalized_entry == canonicalized_email) {
    236       return true;
    237     }
    238 
    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;
    243   }
    244 
    245   if (wildcard_match)
    246     *wildcard_match = found_wildcard_match;
    247 
    248   return found_wildcard_match;
    249 }
    250 
    251 bool CrosSettings::AddSettingsProvider(CrosSettingsProvider* provider) {
    252   DCHECK(CalledOnValidThread());
    253   providers_.push_back(provider);
    254 
    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);
    262   return true;
    263 }
    264 
    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);
    271     return true;
    272   }
    273   return false;
    274 }
    275 
    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());
    282 
    283   if (!GetProvider(path)) {
    284     NOTREACHED() << "Trying to add an observer for an unregistered setting: "
    285                  << path;
    286     return scoped_ptr<CrosSettings::ObserverSubscription>();
    287   }
    288 
    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;
    296   } else {
    297     registry = observer_iterator->second;
    298   }
    299 
    300   return registry->Add(callback);
    301 }
    302 
    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];
    308   }
    309   return NULL;
    310 }
    311 
    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())
    317     return;
    318 
    319   observer_iterator->second->Notify();
    320 }
    321 
    322 ScopedTestCrosSettings::ScopedTestCrosSettings() {
    323   CrosSettings::Initialize();
    324 }
    325 
    326 ScopedTestCrosSettings::~ScopedTestCrosSettings() {
    327   CrosSettings::Shutdown();
    328 }
    329 
    330 }  // namespace chromeos
    331