Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(477)

Side by Side Diff: chrome/browser/extensions/extension_preference_api.cc

Issue 6596044: Add onChange event to preference extension APIs. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: test Created 9 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/extensions/extension_preference_api.h" 5 #include "chrome/browser/extensions/extension_preference_api.h"
6 6
7 #include "base/json/json_writer.h"
7 #include "base/singleton.h" 8 #include "base/singleton.h"
8 #include "base/stringprintf.h" 9 #include "base/stringprintf.h"
9 #include "base/values.h" 10 #include "base/values.h"
11 #include "chrome/browser/extensions/extension_event_router.h"
10 #include "chrome/browser/extensions/extension_prefs.h" 12 #include "chrome/browser/extensions/extension_prefs.h"
11 #include "chrome/browser/extensions/extension_service.h" 13 #include "chrome/browser/extensions/extension_service.h"
12 #include "chrome/browser/profiles/profile.h" 14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/common/notification_type.h"
16 #include "chrome/common/notification_service.h"
13 #include "chrome/common/pref_names.h" 17 #include "chrome/common/pref_names.h"
14 18
15 namespace { 19 namespace {
16 20
17 struct PrefMappingEntry {
18 const char* extension_pref;
19 const char* browser_pref;
20 const char* permission;
21 };
22
23 const char kNotControllable[] = "NotControllable"; 21 const char kNotControllable[] = "NotControllable";
24 const char kControlledByOtherExtensions[] = "ControlledByOtherExtensions"; 22 const char kControlledByOtherExtensions[] = "ControlledByOtherExtensions";
25 const char kControllableByThisExtension[] = "ControllableByThisExtension"; 23 const char kControllableByThisExtension[] = "ControllableByThisExtension";
26 const char kControlledByThisExtension[] = "ControlledByThisExtension"; 24 const char kControlledByThisExtension[] = "ControlledByThisExtension";
27 25
28 const char kIncognito[] = "incognito"; 26 const char kIncognito[] = "incognito";
29 const char kIncognitoSpecific[] = "incognitoSpecific"; 27 const char kIncognitoSpecific[] = "incognitoSpecific";
30 const char kLevelOfControl[] = "levelOfControl"; 28 const char kLevelOfControl[] = "levelOfControl";
31 const char kValue[] = "value"; 29 const char kValue[] = "value";
32 30
31 const char kOnPrefChangeFormat[] = "experimental.preferences.%s.onChange";
32
33 const char kPermissionErrorMessage[] =
34 "You do not have permission to access the preference '%s'. "
35 "Be sure to declare in your manifest what permissions you need.";
36
33 const char kIncognitoErrorMessage[] = 37 const char kIncognitoErrorMessage[] =
34 "You do not have permission to access incognito preferences."; 38 "You do not have permission to access incognito preferences.";
35 39
36 PrefMappingEntry pref_mapping[] = { 40 struct PrefMappingEntry {
41 const char* extension_pref;
42 const char* browser_pref;
43 const char* permission;
44 };
45
46 PrefMappingEntry kPrefMapping[] = {
37 { "blockThirdPartyCookies", 47 { "blockThirdPartyCookies",
38 prefs::kBlockThirdPartyCookies, 48 prefs::kBlockThirdPartyCookies,
39 Extension::kContentSettingsPermission 49 Extension::kContentSettingsPermission
40 }, 50 },
41 { "proxy", 51 { "proxy",
42 prefs::kProxy, 52 prefs::kProxy,
43 Extension::kProxyPermission 53 Extension::kProxyPermission
44 }, 54 },
45 }; 55 };
46 56
47 class PrefMapping { 57 class PrefMapping {
48 public: 58 public:
49 static PrefMapping* GetInstance() { 59 static PrefMapping* GetInstance() {
50 return Singleton<PrefMapping>::get(); 60 return Singleton<PrefMapping>::get();
51 } 61 }
52 62
53 bool FindBrowserPrefForExtensionPref(const std::string& extension_pref, 63 bool FindBrowserPrefForExtensionPref(const std::string& extension_pref,
54 std::string* browser_pref, 64 std::string* browser_pref,
55 std::string* permission) { 65 std::string* permission) {
56 std::map<std::string, std::pair<std::string, std::string> >::iterator it = 66 std::map<std::string, std::pair<std::string, std::string> >::iterator it =
57 mapping_.find(extension_pref); 67 mapping_.find(extension_pref);
58 if (it != mapping_.end()) { 68 if (it != mapping_.end()) {
59 *browser_pref = it->second.first; 69 *browser_pref = it->second.first;
60 *permission = it->second.second; 70 *permission = it->second.second;
61 return true; 71 return true;
62 } 72 }
63 return false; 73 return false;
64 } 74 }
65 75
76 bool FindEventForBrowserPref(const std::string& browser_pref,
77 std::string* event_name,
78 std::string* permission) {
79 std::map<std::string, std::pair<std::string, std::string> >::iterator it =
80 event_mapping_.find(browser_pref);
81 if (it != event_mapping_.end()) {
82 *event_name = it->second.first;
83 *permission = it->second.second;
84 return true;
85 }
86 return false;
87 }
88
66 private: 89 private:
67 friend struct DefaultSingletonTraits<PrefMapping>; 90 friend struct DefaultSingletonTraits<PrefMapping>;
68 91
92 // Mapping from extension pref keys to browser pref keys.
battre 2011/03/10 13:07:28 Thanks you :-)
69 std::map<std::string, std::pair<std::string, std::string> > mapping_; 93 std::map<std::string, std::pair<std::string, std::string> > mapping_;
70 94
95 // Mapping from browser pref keys to extension event names.
96 std::map<std::string, std::pair<std::string, std::string> > event_mapping_;
97
71 PrefMapping() { 98 PrefMapping() {
72 for (size_t i = 0; i < arraysize(pref_mapping); ++i) { 99 for (size_t i = 0; i < arraysize(kPrefMapping); ++i) {
73 mapping_[pref_mapping[i].extension_pref] = 100 mapping_[kPrefMapping[i].extension_pref] =
74 std::make_pair(pref_mapping[i].browser_pref, 101 std::make_pair(kPrefMapping[i].browser_pref,
75 pref_mapping[i].permission); 102 kPrefMapping[i].permission);
103 std::string event_name =
104 base::StringPrintf(kOnPrefChangeFormat,
105 kPrefMapping[i].extension_pref);
106 event_mapping_[kPrefMapping[i].browser_pref] =
107 std::make_pair(event_name, kPrefMapping[i].permission);
76 } 108 }
battre 2011/03/10 13:07:28 DCHECK(mapping_.size()==arraysize(kPrefMapping) &&
Bernhard Bauer 2011/03/10 14:51:15 Done.
77 } 109 }
78 }; 110 };
79 111
80 const char kPermissionErrorMessage[] = 112 // Returns a string constant (defined in the API) indicating the level of
81 "You do not have permission to access the preference '%s'. " 113 // control this extension has over the specified preference.
82 "Be sure to declare in your manifest what permissions you need."; 114 const char* GetLevelOfControl(
115 Profile* profile,
116 const std::string& extension_id,
117 const std::string& browser_pref,
118 bool incognito) {
119 PrefService* prefs = incognito ? profile->GetOffTheRecordPrefs()
120 : profile->GetPrefs();
121 const PrefService::Preference* pref =
122 prefs->FindPreference(browser_pref.c_str());
123 CHECK(pref);
124 ExtensionPrefs* ep = profile->GetExtensionService()->extension_prefs();
125
126 if (!pref->IsExtensionModifiable())
127 return kNotControllable;
128
129 if (ep->DoesExtensionControlPref(extension_id, browser_pref, incognito))
130 return kControlledByThisExtension;
131
132 if (ep->CanExtensionControlPref(extension_id, browser_pref, incognito))
133 return kControllableByThisExtension;
134
135 return kControlledByOtherExtensions;
136 }
83 137
84 } // namespace 138 } // namespace
85 139
140 ExtensionPreferenceEventRouter::ExtensionPreferenceEventRouter(
141 Profile* profile) : profile_(profile) {
142 registrar_.Init(profile_->GetPrefs());
143 incognito_registrar_.Init(profile_->GetOffTheRecordPrefs());
144 for (size_t i = 0; i < arraysize(kPrefMapping); ++i) {
145 registrar_.Add(kPrefMapping[i].browser_pref, this);
146 incognito_registrar_.Add(kPrefMapping[i].browser_pref, this);
147 }
148 }
149
150 ExtensionPreferenceEventRouter::~ExtensionPreferenceEventRouter() { }
151
152 void ExtensionPreferenceEventRouter::Observe(
153 NotificationType type,
154 const NotificationSource& source,
155 const NotificationDetails& details) {
156 if (type == NotificationType::PREF_CHANGED) {
157 const std::string* pref_key =
158 Details<const std::string>(details).ptr();
159 OnPrefChanged(Source<PrefService>(source).ptr(), *pref_key);
battre 2011/03/10 13:07:28 PREF_CHANGED is only fired when the effective valu
Bernhard Bauer 2011/03/10 14:51:15 Oh, I was assuming it is also fired when the level
battre 2011/03/11 09:28:36 This is not implemented, yet.
160 } else {
161 NOTREACHED();
162 }
163 }
164
165 void ExtensionPreferenceEventRouter::OnPrefChanged(
166 PrefService* pref_service,
167 const std::string& browser_pref) {
168 bool incognito = (pref_service != profile_->GetPrefs());
169
170 std::string event_name;
171 std::string permission;
172 bool rv = PrefMapping::GetInstance()->FindEventForBrowserPref(
173 browser_pref, &event_name, &permission);
174 DCHECK(rv);
175
176 ListValue args;
177 DictionaryValue* dict = new DictionaryValue();
178 args.Append(dict);
179 const PrefService::Preference* pref =
180 pref_service->FindPreference(browser_pref.c_str());
181 CHECK(pref);
182 ExtensionService* extension_service = profile_->GetExtensionService();
183 dict->Set(kValue, pref->GetValue()->DeepCopy());
battre 2011/03/10 13:07:28 The proxy settings API needs a hook to modify this
Bernhard Bauer 2011/03/10 14:51:15 Hm, I see. I guess we'll need a separate event rou
battre 2011/03/11 09:28:36 Yes, we could even extract the value transformatio
184 if (incognito) {
185 ExtensionPrefs* ep = extension_service->extension_prefs();
186 dict->Set(
187 kIncognitoSpecific,
188 Value::CreateBooleanValue(ep->HasIncognitoPrefValue(browser_pref)));
189 }
190
191 ExtensionEventRouter* router = profile_->GetExtensionEventRouter();
192 if (!router || !router->HasEventListener(event_name))
193 return;
194 const ExtensionList* extensions = extension_service->extensions();
195 for (ExtensionList::const_iterator it = extensions->begin();
196 it != extensions->end(); ++it) {
197 std::string extension_id = (*it)->id();
198 // TODO(bauerb): Only iterate over registered event listeners.
199 if (router->ExtensionHasEventListener(extension_id, event_name) &&
200 (*it)->HasApiPermission(permission) &&
201 (!incognito || extension_service->CanCrossIncognito(*it))) {
202 std::string level_of_control =
203 GetLevelOfControl(profile_, extension_id, browser_pref, incognito);
204 dict->Set(kLevelOfControl, Value::CreateStringValue(level_of_control));
205
206 std::string json_args;
207 base::JSONWriter::Write(&args, false, &json_args);
208
209 DispatchEvent(extension_id, event_name, json_args);
210 }
211 }
212 }
213
214 void ExtensionPreferenceEventRouter::DispatchEvent(
215 const std::string& extension_id,
216 const std::string& event_name,
217 const std::string& json_args) {
218 profile_->GetExtensionEventRouter()->DispatchEventToExtension(
219 extension_id, event_name, json_args, NULL, GURL());
220 }
221
86 // TODO(battre): Factor out common parts once this is stable. 222 // TODO(battre): Factor out common parts once this is stable.
87 223
88 GetPreferenceFunction::~GetPreferenceFunction() { } 224 GetPreferenceFunction::~GetPreferenceFunction() { }
89 225
90 const char* GetPreferenceFunction::GetLevelOfControl(
91 const std::string& browser_pref,
92 bool incognito) const {
93 PrefService* prefs = incognito ? profile_->GetOffTheRecordPrefs()
94 : profile_->GetPrefs();
95 const PrefService::Preference* pref =
96 prefs->FindPreference(browser_pref.c_str());
97 CHECK(pref);
98 ExtensionPrefs* ep = profile_->GetExtensionService()->extension_prefs();
99
100 if (!pref->IsExtensionModifiable())
101 return kNotControllable;
102
103 if (ep->DoesExtensionControlPref(extension_id(), browser_pref, incognito))
104 return kControlledByThisExtension;
105
106 if (ep->CanExtensionControlPref(extension_id(), browser_pref, incognito))
107 return kControllableByThisExtension;
108
109 return kControlledByOtherExtensions;
110 }
111
112 bool GetPreferenceFunction::RunImpl() { 226 bool GetPreferenceFunction::RunImpl() {
113 std::string pref_key; 227 std::string pref_key;
114 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &pref_key)); 228 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &pref_key));
115 DictionaryValue* details = NULL; 229 DictionaryValue* details = NULL;
116 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &details)); 230 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &details));
117 231
118 bool incognito = false; 232 bool incognito = false;
119 if (details->HasKey(kIncognito)) 233 if (details->HasKey(kIncognito))
120 EXTENSION_FUNCTION_VALIDATE(details->GetBoolean(kIncognito, &incognito)); 234 EXTENSION_FUNCTION_VALIDATE(details->GetBoolean(kIncognito, &incognito));
121 235
(...skipping 10 matching lines...) Expand all
132 PrefMapping::GetInstance()->FindBrowserPrefForExtensionPref( 246 PrefMapping::GetInstance()->FindBrowserPrefForExtensionPref(
133 pref_key, &browser_pref, &permission)); 247 pref_key, &browser_pref, &permission));
134 if (!GetExtension()->HasApiPermission(permission)) { 248 if (!GetExtension()->HasApiPermission(permission)) {
135 error_ = base::StringPrintf(kPermissionErrorMessage, pref_key.c_str()); 249 error_ = base::StringPrintf(kPermissionErrorMessage, pref_key.c_str());
136 return false; 250 return false;
137 } 251 }
138 252
139 const PrefService::Preference* pref = 253 const PrefService::Preference* pref =
140 prefs->FindPreference(browser_pref.c_str()); 254 prefs->FindPreference(browser_pref.c_str());
141 CHECK(pref); 255 CHECK(pref);
142 std::string level_of_control = GetLevelOfControl(browser_pref, incognito); 256 std::string level_of_control =
257 GetLevelOfControl(profile_, extension_id(), browser_pref, incognito);
143 258
144 scoped_ptr<DictionaryValue> result(new DictionaryValue); 259 scoped_ptr<DictionaryValue> result(new DictionaryValue);
145 result->Set(kValue, pref->GetValue()->DeepCopy()); 260 result->Set(kValue, pref->GetValue()->DeepCopy());
146 result->Set(kLevelOfControl, Value::CreateStringValue(level_of_control)); 261 result->Set(kLevelOfControl, Value::CreateStringValue(level_of_control));
147 if (incognito) { 262 if (incognito) {
148 ExtensionPrefs* ep = profile_->GetExtensionService()->extension_prefs(); 263 ExtensionPrefs* ep = profile_->GetExtensionService()->extension_prefs();
149 result->Set( 264 result->Set(
150 kIncognitoSpecific, 265 kIncognitoSpecific,
151 Value::CreateBooleanValue(ep->HasIncognitoPrefValue(browser_pref))); 266 Value::CreateBooleanValue(ep->HasIncognitoPrefValue(browser_pref)));
152 } 267 }
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
216 PrefMapping::GetInstance()->FindBrowserPrefForExtensionPref( 331 PrefMapping::GetInstance()->FindBrowserPrefForExtensionPref(
217 pref_key, &browser_pref, &permission)); 332 pref_key, &browser_pref, &permission));
218 if (!GetExtension()->HasApiPermission(permission)) { 333 if (!GetExtension()->HasApiPermission(permission)) {
219 error_ = base::StringPrintf(kPermissionErrorMessage, pref_key.c_str()); 334 error_ = base::StringPrintf(kPermissionErrorMessage, pref_key.c_str());
220 return false; 335 return false;
221 } 336 }
222 ExtensionPrefs* prefs = profile_->GetExtensionService()->extension_prefs(); 337 ExtensionPrefs* prefs = profile_->GetExtensionService()->extension_prefs();
223 prefs->RemoveExtensionControlledPref(extension_id(), browser_pref, incognito); 338 prefs->RemoveExtensionControlledPref(extension_id(), browser_pref, incognito);
224 return true; 339 return true;
225 } 340 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698