Chromium Code Reviews| Index: chrome/browser/extensions/extension_settings_frontend.cc |
| diff --git a/chrome/browser/extensions/extension_settings_frontend.cc b/chrome/browser/extensions/extension_settings_frontend.cc |
| index 4963e927ae92c67c77fb084f76387cce05297626..eca0f967803f42aec6de0c5e6c73fa9936f1dc0a 100644 |
| --- a/chrome/browser/extensions/extension_settings_frontend.cc |
| +++ b/chrome/browser/extensions/extension_settings_frontend.cc |
| @@ -6,20 +6,114 @@ |
| #include "base/bind.h" |
| #include "base/file_path.h" |
| +#include "chrome/browser/extensions/extension_event_names.h" |
| +#include "chrome/browser/extensions/extension_event_router.h" |
| +#include "chrome/browser/extensions/extension_service.h" |
| #include "chrome/browser/extensions/extension_settings_backend.h" |
| +#include "chrome/browser/profiles/profile.h" |
| #include "content/browser/browser_thread.h" |
| -ExtensionSettingsFrontend::ExtensionSettingsFrontend( |
| - const FilePath& base_path) |
| - : core_(new ExtensionSettingsFrontend::Core()) { |
| +// Observer which sends events to a target profile iff the profile isn't the |
| +// originating profile for the event. |
| +class ExtensionSettingsFrontend::DefaultObserver |
| + : public ExtensionSettingsObserver { |
| + public: |
| + explicit DefaultObserver(Profile* profile) : target_profile_(profile) {} |
| + virtual ~DefaultObserver() {} |
| + |
| + virtual void OnSettingsChanged( |
| + const Profile* origin_profile, |
| + const std::string& extension_id, |
| + const ExtensionSettingChanges& changes) OVERRIDE { |
| + if (origin_profile != target_profile_) { |
| + target_profile_->GetExtensionEventRouter()->DispatchEventToExtension( |
| + extension_id, |
| + extension_event_names::kOnSettingsChanged, |
| + // This is the list of function arguments to pass to the onChanged |
| + // handler of extensions, a single argument with the list of changes. |
| + std::string("[") + changes.ToJson() + "]", |
| + target_profile_, |
| + GURL()); |
| + } |
| + } |
| + |
| + private: |
| + Profile* target_profile_; |
| +}; |
| + |
| +// Ref-counted container for the ExtensionSettingsBackend object. |
| +class ExtensionSettingsFrontend::Core |
| + : public base::RefCountedThreadSafe<Core> { |
| + public: |
| + explicit Core( |
| + const scoped_refptr<ObserverListThreadSafe<ExtensionSettingsObserver> >& |
| + observers) |
| + : observers_(observers), backend_(NULL) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + } |
| + |
| + // Does any FILE thread specific initialization, such as construction of |
| + // |backend_|. Must be called before any call to |
| + // RunWithBackendOnFileThread(). |
| + void InitOnFileThread(const FilePath& base_path) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| + DCHECK(!backend_); |
| + backend_ = new ExtensionSettingsBackend(base_path, observers_); |
| + } |
| + |
| + // Runs |callback| with the extension backend. |
| + void RunWithBackendOnFileThread(const BackendCallback& callback) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| + DCHECK(backend_); |
| + callback.Run(backend_); |
| + } |
| + |
| + private: |
| + virtual ~Core() { |
| + if (BrowserThread::CurrentlyOn(BrowserThread::FILE)) { |
| + delete backend_; |
| + } else if (BrowserThread::CurrentlyOn(BrowserThread::UI)) { |
| + BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, backend_); |
| + } else { |
| + NOTREACHED(); |
| + } |
| + } |
| + |
| + friend class base::RefCountedThreadSafe<Core>; |
| + |
| + // Observers to settings changes (thread safe). |
| + scoped_refptr<ObserverListThreadSafe<ExtensionSettingsObserver> > |
| + observers_; |
| + |
| + // Lives on the FILE thread. |
| + ExtensionSettingsBackend* backend_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(Core); |
| +}; |
| + |
| +ExtensionSettingsFrontend::ExtensionSettingsFrontend(Profile* profile) |
| + : observers_(new ObserverListThreadSafe<ExtensionSettingsObserver>()), |
| + core_(new ExtensionSettingsFrontend::Core(observers_.get())) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + |
| + registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CREATED, |
|
akalin
2011/10/18 19:00:04
Wait, you're listening to creation of *any* profil
not at google - send to devlin
2011/10/19 03:14:32
Thanks, fixed.
|
| + NotificationService::AllBrowserContextsAndSources()); |
| + registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED, |
| + NotificationService::AllBrowserContextsAndSources()); |
| + OnProfileCreated(profile); |
| + |
| BrowserThread::PostTask( |
| BrowserThread::FILE, |
| FROM_HERE, |
| base::Bind( |
| &ExtensionSettingsFrontend::Core::InitOnFileThread, |
| core_.get(), |
| - base_path)); |
| + profile->GetPath().AppendASCII( |
| + ExtensionService::kSettingsDirectoryName))); |
| +} |
| + |
| +ExtensionSettingsFrontend::~ExtensionSettingsFrontend() { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| } |
| void ExtensionSettingsFrontend::RunWithBackend( |
| @@ -34,34 +128,45 @@ void ExtensionSettingsFrontend::RunWithBackend( |
| callback)); |
| } |
| -ExtensionSettingsFrontend::~ExtensionSettingsFrontend() { |
| - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| +void ExtensionSettingsFrontend::AddObserver( |
| + ExtensionSettingsObserver* observer) { |
| + observers_->AddObserver(observer); |
| } |
| -ExtensionSettingsFrontend::Core::Core() : backend_(NULL) { |
| - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| +void ExtensionSettingsFrontend::RemoveObserver( |
| + ExtensionSettingsObserver* observer) { |
| + observers_->RemoveObserver(observer); |
| } |
| -void ExtensionSettingsFrontend::Core::InitOnFileThread( |
| - const FilePath& base_path) { |
| - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| - DCHECK(!backend_); |
| - backend_ = new ExtensionSettingsBackend(base_path); |
| +void ExtensionSettingsFrontend::Observe( |
| + int type, |
| + const NotificationSource& source, |
| + const NotificationDetails& details) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + switch (type) { |
| + case chrome::NOTIFICATION_PROFILE_CREATED: |
| + OnProfileCreated(Source<Profile>(source).ptr()); |
| + break; |
| + case chrome::NOTIFICATION_PROFILE_DESTROYED: |
| + OnProfileDestroyed(Source<Profile>(source).ptr()); |
| + break; |
| + default: |
| + NOTREACHED(); |
| + } |
| } |
| -void ExtensionSettingsFrontend::Core::RunWithBackendOnFileThread( |
| - const BackendCallback& callback) { |
| - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| - DCHECK(backend_); |
| - callback.Run(backend_); |
| +void ExtensionSettingsFrontend::OnProfileCreated(Profile* new_profile) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + DCHECK(profile_observers_.find(new_profile) == profile_observers_.end()); |
| + linked_ptr<DefaultObserver> new_observer(new DefaultObserver(new_profile)); |
| + profile_observers_[new_profile] = new_observer; |
| + AddObserver(new_observer.get()); |
| } |
| -ExtensionSettingsFrontend::Core::~Core() { |
| - if (BrowserThread::CurrentlyOn(BrowserThread::FILE)) { |
| - delete backend_; |
| - } else if (BrowserThread::CurrentlyOn(BrowserThread::UI)) { |
| - BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, backend_); |
| - } else { |
| - NOTREACHED(); |
| - } |
| +void ExtensionSettingsFrontend::OnProfileDestroyed(Profile* old_profile) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + linked_ptr<DefaultObserver> old_observer = profile_observers_[old_profile]; |
| + DCHECK(old_observer.get()); |
| + profile_observers_.erase(old_profile); |
| + RemoveObserver(old_observer.get()); |
| } |