summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
authorbauerb@chromium.org <bauerb@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-03-16 13:31:40 +0000
committerbauerb@chromium.org <bauerb@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-03-16 13:31:40 +0000
commit118de789e8f54ef394bbac3f6f2be6572bf0b79a (patch)
tree310b688d7175103e7fdc4d93cf89e968700305eb /chrome/browser
parentc2a7e681b65010b0b07bdce367ed71e7ecf6fa09 (diff)
downloadchromium_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')
-rw-r--r--chrome/browser/extensions/extension_content_settings_apitest.cc11
-rw-r--r--chrome/browser/extensions/extension_preference_api.cc155
-rw-r--r--chrome/browser/extensions/extension_preference_api.h35
-rw-r--r--chrome/browser/extensions/extension_service.cc3
-rw-r--r--chrome/browser/extensions/extension_service.h3
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.