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

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

Issue 8177022: Add onChanged events to the extension settings API, both from sync and between (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: profile fix, comments Created 9 years, 2 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_settings_frontend.h" 5 #include "chrome/browser/extensions/extension_settings_frontend.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/file_path.h" 8 #include "base/file_path.h"
9 #include "chrome/browser/extensions/extension_event_names.h"
10 #include "chrome/browser/extensions/extension_event_router.h"
11 #include "chrome/browser/extensions/extension_service.h"
9 #include "chrome/browser/extensions/extension_settings_backend.h" 12 #include "chrome/browser/extensions/extension_settings_backend.h"
13 #include "chrome/browser/profiles/profile.h"
10 #include "content/browser/browser_thread.h" 14 #include "content/browser/browser_thread.h"
11 15
12 ExtensionSettingsFrontend::ExtensionSettingsFrontend( 16 // Observer which sends events to a target profile iff the profile isn't the
13 const FilePath& base_path) 17 // originating profile for the event.
14 : core_(new ExtensionSettingsFrontend::Core()) { 18 class ExtensionSettingsFrontend::DefaultObserver
19 : public ExtensionSettingsObserver {
20 public:
21 explicit DefaultObserver(Profile* profile) : target_profile_(profile) {}
22 virtual ~DefaultObserver() {}
23
24 virtual void OnSettingsChanged(
25 const Profile* origin_profile,
26 const std::string& extension_id,
27 const ExtensionSettingChanges& changes) OVERRIDE {
akalin 2011/10/19 19:09:49 maybe DCHECK that origin_profile->OriginalProfile(
not at google - send to devlin 2011/10/19 22:59:36 I don't think this would be right though? target_
akalin 2011/10/19 23:17:00 Right, that's why I put 'vice versa', so something
not at google - send to devlin 2011/10/19 23:47:34 Don't know. Seems to be adding noise to a very si
28 if (origin_profile != target_profile_) {
29 target_profile_->GetExtensionEventRouter()->DispatchEventToExtension(
30 extension_id,
31 extension_event_names::kOnSettingsChanged,
32 // This is the list of function arguments to pass to the onChanged
33 // handler of extensions, a single argument with the list of changes.
34 std::string("[") + changes.ToJson() + "]",
35 target_profile_,
36 GURL());
37 }
38 }
39
40 private:
41 Profile* target_profile_;
42 };
43
44 // Ref-counted container for the ExtensionSettingsBackend object.
45 class ExtensionSettingsFrontend::Core
46 : public base::RefCountedThreadSafe<Core> {
47 public:
48 explicit Core(
49 const scoped_refptr<ObserverListThreadSafe<ExtensionSettingsObserver> >&
50 observers)
51 : observers_(observers), backend_(NULL) {
52 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
53 }
54
55 // Does any FILE thread specific initialization, such as construction of
56 // |backend_|. Must be called before any call to
57 // RunWithBackendOnFileThread().
58 void InitOnFileThread(const FilePath& base_path) {
59 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
60 DCHECK(!backend_);
61 backend_ = new ExtensionSettingsBackend(base_path, observers_);
62 }
63
64 // Runs |callback| with the extension backend.
65 void RunWithBackendOnFileThread(const BackendCallback& callback) {
66 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
67 DCHECK(backend_);
68 callback.Run(backend_);
69 }
70
71 private:
72 virtual ~Core() {
73 if (BrowserThread::CurrentlyOn(BrowserThread::FILE)) {
74 delete backend_;
75 } else if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
76 BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, backend_);
77 } else {
78 NOTREACHED();
79 }
80 }
81
82 friend class base::RefCountedThreadSafe<Core>;
83
84 // Observers to settings changes (thread safe).
85 scoped_refptr<ObserverListThreadSafe<ExtensionSettingsObserver> >
86 observers_;
87
88 // Lives on the FILE thread.
89 ExtensionSettingsBackend* backend_;
90
91 DISALLOW_COPY_AND_ASSIGN(Core);
92 };
93
94 ExtensionSettingsFrontend::ExtensionSettingsFrontend(Profile* profile)
95 : profile_(profile),
96 observers_(new ObserverListThreadSafe<ExtensionSettingsObserver>()),
97 core_(new ExtensionSettingsFrontend::Core(observers_.get())) {
15 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 98 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
99
akalin 2011/10/19 19:09:49 possible to DCHECK that profile_ isn't an incognit
not at google - send to devlin 2011/10/19 22:59:36 Done.
100 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CREATED,
akalin 2011/10/19 19:09:49 comment here about how even though you're listenin
not at google - send to devlin 2011/10/19 22:59:36 Done.
101 NotificationService::AllBrowserContextsAndSources());
102 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
103 NotificationService::AllBrowserContextsAndSources());
104 OnProfileCreated(profile);
105
16 BrowserThread::PostTask( 106 BrowserThread::PostTask(
17 BrowserThread::FILE, 107 BrowserThread::FILE,
18 FROM_HERE, 108 FROM_HERE,
19 base::Bind( 109 base::Bind(
20 &ExtensionSettingsFrontend::Core::InitOnFileThread, 110 &ExtensionSettingsFrontend::Core::InitOnFileThread,
21 core_.get(), 111 core_.get(),
22 base_path)); 112 profile->GetPath().AppendASCII(
113 ExtensionService::kSettingsDirectoryName)));
114 }
115
116 ExtensionSettingsFrontend::~ExtensionSettingsFrontend() {
117 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
23 } 118 }
24 119
25 void ExtensionSettingsFrontend::RunWithBackend( 120 void ExtensionSettingsFrontend::RunWithBackend(
26 const BackendCallback& callback) { 121 const BackendCallback& callback) {
27 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 122 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
28 BrowserThread::PostTask( 123 BrowserThread::PostTask(
29 BrowserThread::FILE, 124 BrowserThread::FILE,
30 FROM_HERE, 125 FROM_HERE,
31 base::Bind( 126 base::Bind(
32 &ExtensionSettingsFrontend::Core::RunWithBackendOnFileThread, 127 &ExtensionSettingsFrontend::Core::RunWithBackendOnFileThread,
33 core_.get(), 128 core_.get(),
34 callback)); 129 callback));
35 } 130 }
36 131
37 ExtensionSettingsFrontend::~ExtensionSettingsFrontend() { 132 void ExtensionSettingsFrontend::AddObserver(
38 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 133 ExtensionSettingsObserver* observer) {
134 observers_->AddObserver(observer);
39 } 135 }
40 136
41 ExtensionSettingsFrontend::Core::Core() : backend_(NULL) { 137 void ExtensionSettingsFrontend::RemoveObserver(
42 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 138 ExtensionSettingsObserver* observer) {
139 observers_->RemoveObserver(observer);
43 } 140 }
44 141
45 void ExtensionSettingsFrontend::Core::InitOnFileThread( 142 void ExtensionSettingsFrontend::Observe(
46 const FilePath& base_path) { 143 int type,
47 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 144 const NotificationSource& source,
48 DCHECK(!backend_); 145 const NotificationDetails& details) {
49 backend_ = new ExtensionSettingsBackend(base_path); 146 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
147 switch (type) {
148 case chrome::NOTIFICATION_PROFILE_CREATED:
149 OnProfileCreated(Source<Profile>(source).ptr());
150 break;
151 case chrome::NOTIFICATION_PROFILE_DESTROYED:
152 OnProfileDestroyed(Source<Profile>(source).ptr());
153 break;
154 default:
155 NOTREACHED();
156 }
50 } 157 }
51 158
52 void ExtensionSettingsFrontend::Core::RunWithBackendOnFileThread( 159 void ExtensionSettingsFrontend::OnProfileCreated(Profile* new_profile) {
53 const BackendCallback& callback) { 160 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
54 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 161 if (new_profile == profile_ && !profile_observer_.get()) {
55 DCHECK(backend_); 162 profile_observer_.reset(new DefaultObserver(profile_));
56 callback.Run(backend_); 163 AddObserver(profile_observer_.get());
164 } else if (new_profile == profile_->GetOffTheRecordProfile() &&
akalin 2011/10/19 19:09:49 hmm GetOffTheRecordProfile() may create one if one
not at google - send to devlin 2011/10/19 22:59:36 Yes you're right. This would work.
165 !incognito_profile_observer_.get()) {
166 incognito_profile_observer_.reset(new DefaultObserver(new_profile));
167 AddObserver(incognito_profile_observer_.get());
168 }
57 } 169 }
58 170
59 ExtensionSettingsFrontend::Core::~Core() { 171 void ExtensionSettingsFrontend::OnProfileDestroyed(Profile* old_profile) {
60 if (BrowserThread::CurrentlyOn(BrowserThread::FILE)) { 172 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
61 delete backend_; 173 if (old_profile == profile_ && profile_observer_.get()) {
62 } else if (BrowserThread::CurrentlyOn(BrowserThread::UI)) { 174 RemoveObserver(profile_observer_.get());
63 BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, backend_); 175 profile_observer_.reset();
64 } else { 176 } else if (old_profile == profile_->GetOffTheRecordProfile() &&
akalin 2011/10/19 19:09:49 same here
not at google - send to devlin 2011/10/19 22:59:36 Done.
65 NOTREACHED(); 177 incognito_profile_observer_.get()) {
178 RemoveObserver(incognito_profile_observer_.get());
179 incognito_profile_observer_.reset();
66 } 180 }
67 } 181 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698