1 // Copyright 2013 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/extensions/api/preference/chrome_direct_setting_api.h" 6 7 #include "base/bind.h" 8 #include "base/containers/hash_tables.h" 9 #include "base/lazy_instance.h" 10 #include "base/prefs/pref_change_registrar.h" 11 #include "base/prefs/pref_service.h" 12 #include "base/strings/stringprintf.h" 13 #include "chrome/browser/extensions/api/preference/preference_api_constants.h" 14 #include "chrome/browser/extensions/extension_service.h" 15 #include "chrome/browser/profiles/profile.h" 16 #include "extensions/browser/extension_system.h" 17 18 namespace extensions { 19 namespace chromedirectsetting { 20 21 const char kOnPrefChangeFormat[] = 22 "types.private.ChromeDirectSetting.%s.onChange"; 23 24 class PreferenceWhitelist { 25 public: 26 PreferenceWhitelist() { 27 whitelist_.insert("googlegeolocationaccess.enabled"); 28 } 29 30 ~PreferenceWhitelist() {} 31 32 bool IsPreferenceOnWhitelist(const std::string& pref_key){ 33 return whitelist_.find(pref_key) != whitelist_.end(); 34 } 35 36 void RegisterEventListeners( 37 Profile* profile, 38 EventRouter::Observer* observer) { 39 for (base::hash_set<std::string>::iterator iter = whitelist_.begin(); 40 iter != whitelist_.end(); 41 iter++) { 42 std::string event_name = base::StringPrintf( 43 kOnPrefChangeFormat, 44 (*iter).c_str()); 45 EventRouter::Get(profile)->RegisterObserver(observer, event_name); 46 } 47 } 48 49 void RegisterPropertyListeners( 50 Profile* profile, 51 PrefChangeRegistrar* registrar, 52 const base::Callback<void(const std::string&)>& callback) { 53 for (base::hash_set<std::string>::iterator iter = whitelist_.begin(); 54 iter != whitelist_.end(); 55 iter++) { 56 const char* pref_key = (*iter).c_str(); 57 std::string event_name = base::StringPrintf( 58 kOnPrefChangeFormat, 59 pref_key); 60 registrar->Add(pref_key, callback); 61 } 62 } 63 64 private: 65 base::hash_set<std::string> whitelist_; 66 67 DISALLOW_COPY_AND_ASSIGN(PreferenceWhitelist); 68 }; 69 70 base::LazyInstance<PreferenceWhitelist> preference_whitelist = 71 LAZY_INSTANCE_INITIALIZER; 72 73 static base::LazyInstance< 74 BrowserContextKeyedAPIFactory<ChromeDirectSettingAPI> > g_factory = 75 LAZY_INSTANCE_INITIALIZER; 76 77 ChromeDirectSettingAPI::ChromeDirectSettingAPI(content::BrowserContext* context) 78 : profile_(Profile::FromBrowserContext(context)) { 79 preference_whitelist.Get().RegisterEventListeners(profile_, this); 80 } 81 82 ChromeDirectSettingAPI::~ChromeDirectSettingAPI() {} 83 84 // KeyedService implementation. 85 void ChromeDirectSettingAPI::Shutdown() {} 86 87 // BrowserContextKeyedAPI implementation. 88 BrowserContextKeyedAPIFactory<ChromeDirectSettingAPI>* 89 ChromeDirectSettingAPI::GetFactoryInstance() { 90 return g_factory.Pointer(); 91 } 92 93 // EventRouter::Observer implementation. 94 void ChromeDirectSettingAPI::OnListenerAdded(const EventListenerInfo& details) { 95 EventRouter::Get(profile_)->UnregisterObserver(this); 96 registrar_.Init(profile_->GetPrefs()); 97 preference_whitelist.Get().RegisterPropertyListeners( 98 profile_, 99 ®istrar_, 100 base::Bind(&ChromeDirectSettingAPI::OnPrefChanged, 101 base::Unretained(this), 102 registrar_.prefs())); 103 } 104 105 bool ChromeDirectSettingAPI::IsPreferenceOnWhitelist( 106 const std::string& pref_key) { 107 return preference_whitelist.Get().IsPreferenceOnWhitelist(pref_key); 108 } 109 110 ChromeDirectSettingAPI* ChromeDirectSettingAPI::Get( 111 content::BrowserContext* context) { 112 return BrowserContextKeyedAPIFactory<ChromeDirectSettingAPI>::Get(context); 113 } 114 115 // BrowserContextKeyedAPI implementation. 116 const char* ChromeDirectSettingAPI::service_name() { 117 return "ChromeDirectSettingAPI"; 118 } 119 120 void ChromeDirectSettingAPI::OnPrefChanged( 121 PrefService* pref_service, const std::string& pref_key) { 122 std::string event_name = base::StringPrintf(kOnPrefChangeFormat, 123 pref_key.c_str()); 124 EventRouter* router = EventRouter::Get(profile_); 125 if (router && router->HasEventListener(event_name)) { 126 const PrefService::Preference* preference = 127 profile_->GetPrefs()->FindPreference(pref_key.c_str()); 128 const base::Value* value = preference->GetValue(); 129 130 scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue); 131 result->Set(preference_api_constants::kValue, value->DeepCopy()); 132 base::ListValue args; 133 args.Append(result.release()); 134 135 ExtensionService* extension_service = 136 ExtensionSystem::Get(profile_)->extension_service(); 137 const ExtensionSet* extensions = extension_service->extensions(); 138 for (ExtensionSet::const_iterator it = extensions->begin(); 139 it != extensions->end(); ++it) { 140 if ((*it)->location() == Manifest::COMPONENT) { 141 std::string extension_id = (*it)->id(); 142 if (router->ExtensionHasEventListener(extension_id, event_name)) { 143 scoped_ptr<base::ListValue> args_copy(args.DeepCopy()); 144 scoped_ptr<Event> event(new Event(event_name, args_copy.Pass())); 145 router->DispatchEventToExtension(extension_id, event.Pass()); 146 } 147 } 148 } 149 } 150 } 151 152 } // namespace chromedirectsetting 153 } // namespace extensions 154