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

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

Issue 5213002: Fix for Bug 50726 "Save extension list and "winning" prefs from extensions" (Closed) Base URL: http://git.chromium.org/git/chromium.git@trunk
Patch Set: Same patch but without stuff that is already included in 5204006 Created 10 years 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
(Empty)
1 // Copyright (c) 2010 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/extension_pref_store.h"
6
7 #include "base/logging.h"
8 #include "base/values.h"
9 #include "chrome/browser/browser_process.h"
10 #include "chrome/browser/prefs/pref_service.h"
11 #include "chrome/browser/profiles/profile.h"
12 #include "chrome/common/extensions/extension.h"
13 #include "chrome/common/notification_service.h"
14
15 ExtensionPrefStore::ExtensionPrefStore(Profile* profile,
16 PrefNotifier::PrefStoreType type)
17 : prefs_(new DictionaryValue()),
18 profile_(profile),
19 type_(type) {
20 RegisterObservers();
21 }
22
23 ExtensionPrefStore::~ExtensionPrefStore() {
24 STLDeleteElements(&extension_stack_);
25 notification_registrar_.RemoveAll();
26 }
27
28 void ExtensionPrefStore::InstallExtensionPref(const Extension* extension,
29 const char* new_pref_path,
30 Value* new_pref_value) {
31 ExtensionStack::iterator i;
32 for (i = extension_stack_.begin(); i != extension_stack_.end(); ++i) {
33 if ((*i)->extension == extension)
34 break;
35 }
36
37 // If this extension is not already in the stack, add it. Otherwise, update
38 // or add the value of this preference, but don't change the extension's
39 // position in the stack. We store the extension even if this preference
40 // isn't registered with our PrefService, so that the ordering of extensions
41 // is consistent among all local-state and user ExtensionPrefStores.
42 PrefService* pref_service = GetPrefService();
43 // The pref_service may be NULL in unit testing.
44 bool is_registered_pref = (pref_service == NULL ||
45 pref_service->FindPreference(new_pref_path) != NULL);
46 PrefValueMap* pref_values;
47 if (i == extension_stack_.end()) {
48 pref_values = new PrefValueMap();
49 if (is_registered_pref)
50 (*pref_values)[new_pref_path] = new_pref_value;
51
52 ExtensionPrefs* extension_prefs = new ExtensionPrefs(extension,
53 pref_values);
54 extension_stack_.push_front(extension_prefs);
55 } else if (is_registered_pref) {
56 pref_values = (*i)->pref_values;
57 delete (*pref_values)[new_pref_path];
58 (*pref_values)[new_pref_path] = new_pref_value;
59 }
60
61 // Apply the preference to our local |prefs_| store.
62 UpdateOnePref(new_pref_path);
63 }
64
65 void ExtensionPrefStore::UninstallExtension(const Extension* extension) {
66 // Remove this extension from the stack.
67 for (ExtensionStack::iterator i = extension_stack_.begin();
68 i != extension_stack_.end(); ++i) {
69 if ((*i)->extension == extension) {
70 scoped_ptr<ExtensionPrefs> to_be_deleted(*i);
71 extension_stack_.erase(i);
72 UpdatePrefs(to_be_deleted->pref_values);
73 return;
74 }
75 }
76 }
77
78 void ExtensionPrefStore::GetExtensionIDs(std::vector<std::string>* result) {
79 for (ExtensionStack::iterator i = extension_stack_.begin();
80 i != extension_stack_.end(); ++i) {
81 (*result).push_back((*i)->extension->id());
82 }
83 }
84
85 // This could be sped up by keeping track of which extension currently controls
86 // a given preference, among other optimizations. But probably fewer than 10
87 // installed extensions will be trying to control any preferences, so stick
88 // with this simpler algorithm until it causes a problem.
89 void ExtensionPrefStore::UpdateOnePref(const char* path) {
90 PrefService* pref_service = GetPrefService();
91
92 // There are at least two PrefServices, one for local state and one for
93 // user prefs. (See browser_main.cc.) Different preferences are registered
94 // in each; if this one doesn't have the desired pref registered, we ignore
95 // it and let the other one handle it.
96 // The pref_service may be NULL in unit testing.
97 if (pref_service && !pref_service->FindPreference(path))
98 return;
99
100 // Save the old value before removing it from the local cache.
101 Value* my_old_value_ptr = NULL;
102 prefs_->Get(path, &my_old_value_ptr);
103 scoped_ptr<Value> my_old_value;
104 if (my_old_value_ptr)
105 my_old_value.reset(my_old_value_ptr->DeepCopy());
106
107 // DictionaryValue::Set complains if a key is overwritten with the same
108 // value, so remove it first.
109 prefs_->Remove(path, NULL);
110
111 // Find the first extension that wants to set this pref and use its value.
112 Value* my_new_value = NULL;
113 for (ExtensionStack::iterator ext_iter = extension_stack_.begin();
114 ext_iter != extension_stack_.end(); ++ext_iter) {
115 PrefValueMap::iterator value_iter = (*ext_iter)->pref_values->find(path);
116 if (value_iter != (*ext_iter)->pref_values->end()) {
117 prefs_->Set(path, (*value_iter).second->DeepCopy());
118 my_new_value = (*value_iter).second;
119 break;
120 }
121 }
122
123 if (pref_service) {
124 bool value_changed = true;
125 if (!my_old_value.get() && !my_new_value) {
126 value_changed = false;
127 } else if (my_old_value.get() &&
128 my_new_value &&
129 my_old_value->Equals(my_new_value)) {
130 value_changed = false;
131 }
132
133 if (value_changed)
134 pref_service->pref_notifier()->OnPreferenceSet(path, type_);
135 }
136 }
137
138 void ExtensionPrefStore::UpdatePrefs(const PrefValueMap* pref_values) {
139 if (!pref_values)
140 return;
141
142 for (PrefValueMap::const_iterator i = pref_values->begin();
143 i != pref_values->end(); ++i) {
144 UpdateOnePref(i->first);
145 }
146 }
147
148 PrefService* ExtensionPrefStore::GetPrefService() {
149 if (profile_)
150 return profile_->GetPrefs();
151 return g_browser_process->local_state();
152 }
153
154 void ExtensionPrefStore::RegisterObservers() {
155 notification_registrar_.Add(this,
156 NotificationType::EXTENSION_PREF_CHANGED,
157 NotificationService::AllSources());
158
159 notification_registrar_.Add(this,
160 NotificationType::EXTENSION_UNLOADED,
161 NotificationService::AllSources());
162 }
163
164 void ExtensionPrefStore::Observe(NotificationType type,
165 const NotificationSource& source,
166 const NotificationDetails& details) {
167 switch (type.value) {
168 case NotificationType::EXTENSION_PREF_CHANGED: {
169 Profile* extension_profile = Source<Profile>(source).ptr();
170 // The ExtensionPrefStore for the local state watches all profiles.
171 if (!profile_ || profile_ == extension_profile) {
172 ExtensionPrefStore::ExtensionPrefDetails* data =
173 Details<ExtensionPrefStore::ExtensionPrefDetails>(details).ptr();
174 InstallExtensionPref(data->first, data->second.first,
175 data->second.second);
176 }
177 break;
178 }
179 case NotificationType::EXTENSION_UNLOADED: {
180 Profile* extension_profile = Source<Profile>(source).ptr();
181 const Extension* extension = Details<const Extension>(details).ptr();
182 // The ExtensionPrefStore for the local state watches all profiles.
183 if (profile_ == NULL || profile_ == extension_profile)
184 UninstallExtension(extension);
185 break;
186 }
187 default: {
188 NOTREACHED();
189 }
190 }
191 }
192
193 ExtensionPrefStore::ExtensionPrefs::ExtensionPrefs(const Extension* extension,
194 PrefValueMap* values) : extension(extension), pref_values(values) {}
195
196 ExtensionPrefStore::ExtensionPrefs::~ExtensionPrefs() {
197 STLDeleteValues(pref_values);
198 delete pref_values;
199 }
OLDNEW
« no previous file with comments | « chrome/browser/extensions/extension_pref_store.h ('k') | chrome/browser/extensions/extension_pref_store_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698