diff options
Diffstat (limited to 'chrome/browser/extensions/extension_settings_frontend.cc')
-rw-r--r-- | chrome/browser/extensions/extension_settings_frontend.cc | 175 |
1 files changed, 152 insertions, 23 deletions
diff --git a/chrome/browser/extensions/extension_settings_frontend.cc b/chrome/browser/extensions/extension_settings_frontend.cc index 4963e92..84bfaac 100644 --- a/chrome/browser/extensions/extension_settings_frontend.cc +++ b/chrome/browser/extensions/extension_settings_frontend.cc @@ -6,20 +6,117 @@ #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" +#include "content/public/browser/notification_service.h" -ExtensionSettingsFrontend::ExtensionSettingsFrontend( - const FilePath& base_path) - : core_(new ExtensionSettingsFrontend::Core()) { +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_; +}; + +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) + : profile_(profile), + observers_(new ObserverListThreadSafe<ExtensionSettingsObserver>()), + core_(new ExtensionSettingsFrontend::Core(observers_.get())) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + DCHECK(!profile->IsOffTheRecord()); + + // This class listens to all PROFILE_{CREATED,DESTROYED} events but we're + // only interested in those for the original Profile given on construction + // and its incognito version. + registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CREATED, + content::NotificationService::AllBrowserContextsAndSources()); + registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED, + content::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 +131,66 @@ void ExtensionSettingsFrontend::RunWithBackend( callback)); } -ExtensionSettingsFrontend::~ExtensionSettingsFrontend() { +void ExtensionSettingsFrontend::AddObserver( + ExtensionSettingsObserver* observer) { + observers_->AddObserver(observer); +} + +void ExtensionSettingsFrontend::RemoveObserver( + ExtensionSettingsObserver* observer) { + observers_->RemoveObserver(observer); +} + +void ExtensionSettingsFrontend::Observe( + int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + switch (type) { + case chrome::NOTIFICATION_PROFILE_CREATED: + OnProfileCreated(content::Source<Profile>(source).ptr()); + break; + case chrome::NOTIFICATION_PROFILE_DESTROYED: + OnProfileDestroyed(content::Source<Profile>(source).ptr()); + break; + default: + NOTREACHED(); + } } -ExtensionSettingsFrontend::Core::Core() : backend_(NULL) { +void ExtensionSettingsFrontend::OnProfileCreated(Profile* new_profile) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + if (new_profile == profile_) { + ClearDefaultObserver(&original_profile_observer); + SetDefaultObserver(new_profile, &original_profile_observer); + } else if (new_profile->GetOriginalProfile() == profile_) { + DCHECK(new_profile->IsOffTheRecord()); + ClearDefaultObserver(&incognito_profile_observer_); + SetDefaultObserver(new_profile, &incognito_profile_observer_); + } } -void ExtensionSettingsFrontend::Core::InitOnFileThread( - const FilePath& base_path) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - DCHECK(!backend_); - backend_ = new ExtensionSettingsBackend(base_path); +void ExtensionSettingsFrontend::OnProfileDestroyed(Profile* old_profile) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + if (old_profile == profile_) { + ClearDefaultObserver(&original_profile_observer); + } else if (old_profile->GetOriginalProfile() == profile_) { + DCHECK(old_profile->IsOffTheRecord()); + ClearDefaultObserver(&incognito_profile_observer_); + } } -void ExtensionSettingsFrontend::Core::RunWithBackendOnFileThread( - const BackendCallback& callback) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - DCHECK(backend_); - callback.Run(backend_); +void ExtensionSettingsFrontend::SetDefaultObserver( + Profile* profile, scoped_ptr<DefaultObserver>* observer) { + DCHECK(!observer->get()); + observer->reset(new DefaultObserver(profile)); + AddObserver(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::ClearDefaultObserver( + scoped_ptr<DefaultObserver>* observer) { + if (observer->get()) { + RemoveObserver(observer->get()); + observer->reset(); } } |