diff options
author | bauerb@chromium.org <bauerb@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-03-16 13:31:40 +0000 |
---|---|---|
committer | bauerb@chromium.org <bauerb@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-03-16 13:31:40 +0000 |
commit | 118de789e8f54ef394bbac3f6f2be6572bf0b79a (patch) | |
tree | 310b688d7175103e7fdc4d93cf89e968700305eb /chrome/browser | |
parent | c2a7e681b65010b0b07bdce367ed71e7ecf6fa09 (diff) | |
download | chromium_src-118de789e8f54ef394bbac3f6f2be6572bf0b79a.zip chromium_src-118de789e8f54ef394bbac3f6f2be6572bf0b79a.tar.gz chromium_src-118de789e8f54ef394bbac3f6f2be6572bf0b79a.tar.bz2 |
Add onChange event to preference extension APIs.
BUG=73994
TEST=TBD
Review URL: http://codereview.chromium.org/6596044
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@78354 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
5 files changed, 182 insertions, 25 deletions
diff --git a/chrome/browser/extensions/extension_content_settings_apitest.cc b/chrome/browser/extensions/extension_content_settings_apitest.cc index 2839f3c..c71d5f6 100644 --- a/chrome/browser/extensions/extension_content_settings_apitest.cc +++ b/chrome/browser/extensions/extension_content_settings_apitest.cc @@ -74,3 +74,14 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ContentSettingsClear) { EXPECT_FALSE(pref->IsExtensionControlled()); EXPECT_EQ(true, pref_service->GetBoolean(prefs::kBlockThirdPartyCookies)); } + +IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ContentSettingsOnChange) { + CommandLine::ForCurrentProcess()->AppendSwitch( + switches::kEnableExperimentalExtensionApis); + + PrefService* prefs = browser()->profile()->GetPrefs(); + prefs->SetBoolean(prefs::kBlockThirdPartyCookies, false); + + EXPECT_TRUE(RunExtensionTestIncognito("content_settings/onchange")) << + message_; +} diff --git a/chrome/browser/extensions/extension_preference_api.cc b/chrome/browser/extensions/extension_preference_api.cc index 73e29ce..d4b8410 100644 --- a/chrome/browser/extensions/extension_preference_api.cc +++ b/chrome/browser/extensions/extension_preference_api.cc @@ -11,11 +11,14 @@ #include "base/stl_util-inl.h" #include "base/stringprintf.h" #include "base/values.h" +#include "chrome/browser/extensions/extension_event_router.h" #include "chrome/browser/extensions/extension_prefs.h" #include "chrome/browser/extensions/extension_proxy_api.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/profiles/profile.h" #include "chrome/common/pref_names.h" +#include "content/common/notification_type.h" +#include "content/common/notification_service.h" namespace { @@ -35,6 +38,8 @@ const char kIncognitoSpecific[] = "incognitoSpecific"; const char kLevelOfControl[] = "levelOfControl"; const char kValue[] = "value"; +const char kOnPrefChangeFormat[] = "experimental.preferences.%s.onChange"; + const char kIncognitoErrorMessage[] = "You do not have permission to access incognito preferences."; @@ -68,6 +73,32 @@ class IdentityPrefTransformer : public PrefTransformerInterface { } }; +// Returns a string constant (defined in the API) indicating the level of +// control this extension has over the specified preference. +const char* GetLevelOfControl( + Profile* profile, + const std::string& extension_id, + const std::string& browser_pref, + bool incognito) { + PrefService* prefs = incognito ? profile->GetOffTheRecordPrefs() + : profile->GetPrefs(); + const PrefService::Preference* pref = + prefs->FindPreference(browser_pref.c_str()); + CHECK(pref); + ExtensionPrefs* ep = profile->GetExtensionService()->extension_prefs(); + + if (!pref->IsExtensionModifiable()) + return kNotControllable; + + if (ep->DoesExtensionControlPref(extension_id, browser_pref, incognito)) + return kControlledByThisExtension; + + if (ep->CanExtensionControlPref(extension_id, browser_pref, incognito)) + return kControllableByThisExtension; + + return kControlledByOtherExtensions; +} + class PrefMapping { public: static PrefMapping* GetInstance() { @@ -87,6 +118,19 @@ class PrefMapping { return false; } + bool FindEventForBrowserPref(const std::string& browser_pref, + std::string* event_name, + std::string* permission) { + std::map<std::string, std::pair<std::string, std::string> >::iterator it = + event_mapping_.find(browser_pref); + if (it != event_mapping_.end()) { + *event_name = it->second.first; + *permission = it->second.second; + return true; + } + return false; + } + PrefTransformerInterface* FindTransformerForBrowserPref( const std::string& browser_pref) { std::map<std::string, PrefTransformerInterface*>::iterator it = @@ -106,8 +150,14 @@ class PrefMapping { mapping_[kPrefMapping[i].extension_pref] = std::make_pair(kPrefMapping[i].browser_pref, kPrefMapping[i].permission); + std::string event_name = + base::StringPrintf(kOnPrefChangeFormat, + kPrefMapping[i].extension_pref); + event_mapping_[kPrefMapping[i].browser_pref] = + std::make_pair(event_name, kPrefMapping[i].permission); } DCHECK_EQ(arraysize(kPrefMapping), mapping_.size()); + DCHECK_EQ(arraysize(kPrefMapping), event_mapping_.size()); RegisterPrefTransformer(prefs::kProxy, new ProxyPrefTransformer()); } @@ -123,43 +173,109 @@ class PrefMapping { transformers_[browser_pref] = transformer; } - // Mapping from extension pref keys to browser pref keys. + // Mapping from extension pref keys to browser pref keys and permissions. std::map<std::string, std::pair<std::string, std::string> > mapping_; + // Mapping from browser pref keys to extension event names and permissions. + std::map<std::string, std::pair<std::string, std::string> > event_mapping_; // Mapping from browser pref keys to transformers. std::map<std::string, PrefTransformerInterface*> transformers_; scoped_ptr<PrefTransformerInterface> identity_transformer_; + + DISALLOW_COPY_AND_ASSIGN(PrefMapping); }; } // namespace -// TODO(battre): Factor out common parts once this is stable. +ExtensionPreferenceEventRouter::ExtensionPreferenceEventRouter( + Profile* profile) : profile_(profile) { + registrar_.Init(profile_->GetPrefs()); + incognito_registrar_.Init(profile_->GetOffTheRecordPrefs()); + for (size_t i = 0; i < arraysize(kPrefMapping); ++i) { + registrar_.Add(kPrefMapping[i].browser_pref, this); + incognito_registrar_.Add(kPrefMapping[i].browser_pref, this); + } +} -GetPreferenceFunction::~GetPreferenceFunction() { } +ExtensionPreferenceEventRouter::~ExtensionPreferenceEventRouter() { } + +void ExtensionPreferenceEventRouter::Observe( + NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) { + if (type == NotificationType::PREF_CHANGED) { + const std::string* pref_key = + Details<const std::string>(details).ptr(); + OnPrefChanged(Source<PrefService>(source).ptr(), *pref_key); + } else { + NOTREACHED(); + } +} -const char* GetPreferenceFunction::GetLevelOfControl( - const std::string& browser_pref, - bool incognito) const { - PrefService* prefs = incognito ? profile_->GetOffTheRecordPrefs() - : profile_->GetPrefs(); +void ExtensionPreferenceEventRouter::OnPrefChanged( + PrefService* pref_service, + const std::string& browser_pref) { + bool incognito = (pref_service != profile_->GetPrefs()); + + std::string event_name; + std::string permission; + bool rv = PrefMapping::GetInstance()->FindEventForBrowserPref( + browser_pref, &event_name, &permission); + DCHECK(rv); + + ListValue args; + DictionaryValue* dict = new DictionaryValue(); + args.Append(dict); const PrefService::Preference* pref = - prefs->FindPreference(browser_pref.c_str()); + pref_service->FindPreference(browser_pref.c_str()); CHECK(pref); - ExtensionPrefs* ep = profile_->GetExtensionService()->extension_prefs(); + ExtensionService* extension_service = profile_->GetExtensionService(); + PrefTransformerInterface* transformer = + PrefMapping::GetInstance()->FindTransformerForBrowserPref(browser_pref); + dict->Set(kValue, transformer->BrowserToExtensionPref(pref->GetValue())); + if (incognito) { + ExtensionPrefs* ep = extension_service->extension_prefs(); + dict->Set( + kIncognitoSpecific, + Value::CreateBooleanValue(ep->HasIncognitoPrefValue(browser_pref))); + } - if (!pref->IsExtensionModifiable()) - return kNotControllable; + ExtensionEventRouter* router = profile_->GetExtensionEventRouter(); + if (!router || !router->HasEventListener(event_name)) + return; + const ExtensionList* extensions = extension_service->extensions(); + for (ExtensionList::const_iterator it = extensions->begin(); + it != extensions->end(); ++it) { + std::string extension_id = (*it)->id(); + // TODO(bauerb): Only iterate over registered event listeners. + if (router->ExtensionHasEventListener(extension_id, event_name) && + (*it)->HasApiPermission(permission) && + (!incognito || extension_service->CanCrossIncognito(*it))) { + std::string level_of_control = + GetLevelOfControl(profile_, extension_id, browser_pref, incognito); + dict->Set(kLevelOfControl, Value::CreateStringValue(level_of_control)); + + std::string json_args; + base::JSONWriter::Write(&args, false, &json_args); + + DispatchEvent(extension_id, event_name, json_args); + } + } +} - if (ep->DoesExtensionControlPref(extension_id(), browser_pref, incognito)) - return kControlledByThisExtension; +void ExtensionPreferenceEventRouter::DispatchEvent( + const std::string& extension_id, + const std::string& event_name, + const std::string& json_args) { + profile_->GetExtensionEventRouter()->DispatchEventToExtension( + extension_id, event_name, json_args, NULL, GURL()); +} - if (ep->CanExtensionControlPref(extension_id(), browser_pref, incognito)) - return kControllableByThisExtension; +// TODO(battre): Factor out common parts once this is stable. - return kControlledByOtherExtensions; -} +GetPreferenceFunction::~GetPreferenceFunction() { } bool GetPreferenceFunction::RunImpl() { std::string pref_key; @@ -191,7 +307,8 @@ bool GetPreferenceFunction::RunImpl() { const PrefService::Preference* pref = prefs->FindPreference(browser_pref.c_str()); CHECK(pref); - std::string level_of_control = GetLevelOfControl(browser_pref, incognito); + std::string level_of_control = + GetLevelOfControl(profile_, extension_id(), browser_pref, incognito); scoped_ptr<DictionaryValue> result(new DictionaryValue); PrefTransformerInterface* transformer = diff --git a/chrome/browser/extensions/extension_preference_api.h b/chrome/browser/extensions/extension_preference_api.h index d020c11..31c4452 100644 --- a/chrome/browser/extensions/extension_preference_api.h +++ b/chrome/browser/extensions/extension_preference_api.h @@ -9,6 +9,35 @@ #include <string> #include "chrome/browser/extensions/extension_function.h" +#include "chrome/browser/prefs/pref_change_registrar.h" +#include "content/common/notification_observer.h" + +class ExtensionPreferenceEventRouter : public NotificationObserver { + public: + explicit ExtensionPreferenceEventRouter(Profile* profile); + virtual ~ExtensionPreferenceEventRouter(); + + private: + // NotificationObserver implementation. + virtual void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details); + + void OnPrefChanged(PrefService* pref_service, const std::string& pref_key); + + // This method dispatches events to the extension message service. + void DispatchEvent(const std::string& extension_id, + const std::string& event_name, + const std::string& json_args); + + PrefChangeRegistrar registrar_; + PrefChangeRegistrar incognito_registrar_; + + // Weak, owns us (transitively via ExtensionService). + Profile* profile_; + + DISALLOW_COPY_AND_ASSIGN(ExtensionPreferenceEventRouter); +}; class Value; @@ -36,12 +65,6 @@ class GetPreferenceFunction : public SyncExtensionFunction { virtual ~GetPreferenceFunction(); virtual bool RunImpl(); DECLARE_EXTENSION_FUNCTION_NAME("experimental.preferences.get") - - private: - // Returns a string constant (defined in API) indicating the level of - // control this extension has on the specified preference. - const char* GetLevelOfControl(const std::string& browser_pref, - bool incognito) const; }; class SetPreferenceFunction : public SyncExtensionFunction { diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc index a0d334e..1c751f9 100644 --- a/chrome/browser/extensions/extension_service.cc +++ b/chrome/browser/extensions/extension_service.cc @@ -34,6 +34,7 @@ #include "chrome/browser/extensions/extension_history_api.h" #include "chrome/browser/extensions/extension_host.h" #include "chrome/browser/extensions/extension_management_api.h" +#include "chrome/browser/extensions/extension_preference_api.h" #include "chrome/browser/extensions/extension_process_manager.h" #include "chrome/browser/extensions/extension_processes_api.h" #include "chrome/browser/extensions/extension_special_storage_policy.h" @@ -460,6 +461,7 @@ void ExtensionService::InitEventRouters() { ExtensionAccessibilityEventRouter::GetInstance()->ObserveProfile(profile_); browser_event_router_.reset(new ExtensionBrowserEventRouter(profile_)); browser_event_router_->Init(); + preference_event_router_.reset(new ExtensionPreferenceEventRouter(profile_)); ExtensionBookmarkEventRouter::GetInstance()->Observe( profile_->GetBookmarkModel()); ExtensionCookiesEventRouter::GetInstance()->Init(); @@ -1103,6 +1105,7 @@ void ExtensionService::DestroyingProfile() { updater_->Stop(); } browser_event_router_.reset(); + preference_event_router_.reset(); pref_change_registrar_.RemoveAll(); profile_ = NULL; toolbar_model_.DestroyingProfile(); diff --git a/chrome/browser/extensions/extension_service.h b/chrome/browser/extensions/extension_service.h index 096319a..5e83300 100644 --- a/chrome/browser/extensions/extension_service.h +++ b/chrome/browser/extensions/extension_service.h @@ -37,6 +37,7 @@ #include "content/common/property_bag.h" class ExtensionBrowserEventRouter; +class ExtensionPreferenceEventRouter; class ExtensionServiceBackend; class ExtensionToolbarModel; class ExtensionUpdater; @@ -564,6 +565,8 @@ class ExtensionService scoped_ptr<ExtensionBrowserEventRouter> browser_event_router_; + scoped_ptr<ExtensionPreferenceEventRouter> preference_event_router_; + // A collection of external extension providers. Each provider reads // a source of external extension information. Examples include the // windows registry and external_extensions.json. |