OLD | NEW |
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" |
| 15 #include "content/public/browser/notification_service.h" |
11 | 16 |
12 ExtensionSettingsFrontend::ExtensionSettingsFrontend( | 17 class ExtensionSettingsFrontend::DefaultObserver |
13 const FilePath& base_path) | 18 : public ExtensionSettingsObserver { |
14 : core_(new ExtensionSettingsFrontend::Core()) { | 19 public: |
| 20 explicit DefaultObserver(Profile* profile) : target_profile_(profile) {} |
| 21 virtual ~DefaultObserver() {} |
| 22 |
| 23 virtual void OnSettingsChanged( |
| 24 const Profile* origin_profile, |
| 25 const std::string& extension_id, |
| 26 const ExtensionSettingChanges& changes) OVERRIDE { |
| 27 if (origin_profile != target_profile_) { |
| 28 target_profile_->GetExtensionEventRouter()->DispatchEventToExtension( |
| 29 extension_id, |
| 30 extension_event_names::kOnSettingsChanged, |
| 31 // This is the list of function arguments to pass to the onChanged |
| 32 // handler of extensions, a single argument with the list of changes. |
| 33 std::string("[") + changes.ToJson() + "]", |
| 34 target_profile_, |
| 35 GURL()); |
| 36 } |
| 37 } |
| 38 |
| 39 private: |
| 40 Profile* target_profile_; |
| 41 }; |
| 42 |
| 43 class ExtensionSettingsFrontend::Core |
| 44 : public base::RefCountedThreadSafe<Core> { |
| 45 public: |
| 46 explicit Core( |
| 47 const scoped_refptr<ObserverListThreadSafe<ExtensionSettingsObserver> >& |
| 48 observers) |
| 49 : observers_(observers), backend_(NULL) { |
| 50 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 51 } |
| 52 |
| 53 // Does any FILE thread specific initialization, such as construction of |
| 54 // |backend_|. Must be called before any call to |
| 55 // RunWithBackendOnFileThread(). |
| 56 void InitOnFileThread(const FilePath& base_path) { |
| 57 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 58 DCHECK(!backend_); |
| 59 backend_ = new ExtensionSettingsBackend(base_path, observers_); |
| 60 } |
| 61 |
| 62 // Runs |callback| with the extension backend. |
| 63 void RunWithBackendOnFileThread(const BackendCallback& callback) { |
| 64 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 65 DCHECK(backend_); |
| 66 callback.Run(backend_); |
| 67 } |
| 68 |
| 69 private: |
| 70 virtual ~Core() { |
| 71 if (BrowserThread::CurrentlyOn(BrowserThread::FILE)) { |
| 72 delete backend_; |
| 73 } else if (BrowserThread::CurrentlyOn(BrowserThread::UI)) { |
| 74 BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, backend_); |
| 75 } else { |
| 76 NOTREACHED(); |
| 77 } |
| 78 } |
| 79 |
| 80 friend class base::RefCountedThreadSafe<Core>; |
| 81 |
| 82 // Observers to settings changes (thread safe). |
| 83 scoped_refptr<ObserverListThreadSafe<ExtensionSettingsObserver> > |
| 84 observers_; |
| 85 |
| 86 // Lives on the FILE thread. |
| 87 ExtensionSettingsBackend* backend_; |
| 88 |
| 89 DISALLOW_COPY_AND_ASSIGN(Core); |
| 90 }; |
| 91 |
| 92 ExtensionSettingsFrontend::ExtensionSettingsFrontend(Profile* profile) |
| 93 : profile_(profile), |
| 94 observers_(new ObserverListThreadSafe<ExtensionSettingsObserver>()), |
| 95 core_(new ExtensionSettingsFrontend::Core(observers_.get())) { |
15 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 96 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 97 DCHECK(!profile->IsOffTheRecord()); |
| 98 |
| 99 // This class listens to all PROFILE_{CREATED,DESTROYED} events but we're |
| 100 // only interested in those for the original Profile given on construction |
| 101 // and its incognito version. |
| 102 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CREATED, |
| 103 content::NotificationService::AllBrowserContextsAndSources()); |
| 104 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED, |
| 105 content::NotificationService::AllBrowserContextsAndSources()); |
| 106 OnProfileCreated(profile); |
| 107 |
16 BrowserThread::PostTask( | 108 BrowserThread::PostTask( |
17 BrowserThread::FILE, | 109 BrowserThread::FILE, |
18 FROM_HERE, | 110 FROM_HERE, |
19 base::Bind( | 111 base::Bind( |
20 &ExtensionSettingsFrontend::Core::InitOnFileThread, | 112 &ExtensionSettingsFrontend::Core::InitOnFileThread, |
21 core_.get(), | 113 core_.get(), |
22 base_path)); | 114 profile->GetPath().AppendASCII( |
| 115 ExtensionService::kSettingsDirectoryName))); |
| 116 } |
| 117 |
| 118 ExtensionSettingsFrontend::~ExtensionSettingsFrontend() { |
| 119 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
23 } | 120 } |
24 | 121 |
25 void ExtensionSettingsFrontend::RunWithBackend( | 122 void ExtensionSettingsFrontend::RunWithBackend( |
26 const BackendCallback& callback) { | 123 const BackendCallback& callback) { |
27 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 124 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
28 BrowserThread::PostTask( | 125 BrowserThread::PostTask( |
29 BrowserThread::FILE, | 126 BrowserThread::FILE, |
30 FROM_HERE, | 127 FROM_HERE, |
31 base::Bind( | 128 base::Bind( |
32 &ExtensionSettingsFrontend::Core::RunWithBackendOnFileThread, | 129 &ExtensionSettingsFrontend::Core::RunWithBackendOnFileThread, |
33 core_.get(), | 130 core_.get(), |
34 callback)); | 131 callback)); |
35 } | 132 } |
36 | 133 |
37 ExtensionSettingsFrontend::~ExtensionSettingsFrontend() { | 134 void ExtensionSettingsFrontend::AddObserver( |
38 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 135 ExtensionSettingsObserver* observer) { |
| 136 observers_->AddObserver(observer); |
39 } | 137 } |
40 | 138 |
41 ExtensionSettingsFrontend::Core::Core() : backend_(NULL) { | 139 void ExtensionSettingsFrontend::RemoveObserver( |
42 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 140 ExtensionSettingsObserver* observer) { |
| 141 observers_->RemoveObserver(observer); |
43 } | 142 } |
44 | 143 |
45 void ExtensionSettingsFrontend::Core::InitOnFileThread( | 144 void ExtensionSettingsFrontend::Observe( |
46 const FilePath& base_path) { | 145 int type, |
47 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 146 const content::NotificationSource& source, |
48 DCHECK(!backend_); | 147 const content::NotificationDetails& details) { |
49 backend_ = new ExtensionSettingsBackend(base_path); | 148 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 149 switch (type) { |
| 150 case chrome::NOTIFICATION_PROFILE_CREATED: |
| 151 OnProfileCreated(content::Source<Profile>(source).ptr()); |
| 152 break; |
| 153 case chrome::NOTIFICATION_PROFILE_DESTROYED: |
| 154 OnProfileDestroyed(content::Source<Profile>(source).ptr()); |
| 155 break; |
| 156 default: |
| 157 NOTREACHED(); |
| 158 } |
50 } | 159 } |
51 | 160 |
52 void ExtensionSettingsFrontend::Core::RunWithBackendOnFileThread( | 161 void ExtensionSettingsFrontend::OnProfileCreated(Profile* new_profile) { |
53 const BackendCallback& callback) { | 162 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
54 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 163 if (new_profile == profile_) { |
55 DCHECK(backend_); | 164 ClearDefaultObserver(&original_profile_observer); |
56 callback.Run(backend_); | 165 SetDefaultObserver(new_profile, &original_profile_observer); |
| 166 } else if (new_profile->GetOriginalProfile() == profile_) { |
| 167 DCHECK(new_profile->IsOffTheRecord()); |
| 168 ClearDefaultObserver(&incognito_profile_observer_); |
| 169 SetDefaultObserver(new_profile, &incognito_profile_observer_); |
| 170 } |
57 } | 171 } |
58 | 172 |
59 ExtensionSettingsFrontend::Core::~Core() { | 173 void ExtensionSettingsFrontend::OnProfileDestroyed(Profile* old_profile) { |
60 if (BrowserThread::CurrentlyOn(BrowserThread::FILE)) { | 174 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
61 delete backend_; | 175 if (old_profile == profile_) { |
62 } else if (BrowserThread::CurrentlyOn(BrowserThread::UI)) { | 176 ClearDefaultObserver(&original_profile_observer); |
63 BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, backend_); | 177 } else if (old_profile->GetOriginalProfile() == profile_) { |
64 } else { | 178 DCHECK(old_profile->IsOffTheRecord()); |
65 NOTREACHED(); | 179 ClearDefaultObserver(&incognito_profile_observer_); |
66 } | 180 } |
67 } | 181 } |
| 182 |
| 183 void ExtensionSettingsFrontend::SetDefaultObserver( |
| 184 Profile* profile, scoped_ptr<DefaultObserver>* observer) { |
| 185 DCHECK(!observer->get()); |
| 186 observer->reset(new DefaultObserver(profile)); |
| 187 AddObserver(observer->get()); |
| 188 } |
| 189 |
| 190 void ExtensionSettingsFrontend::ClearDefaultObserver( |
| 191 scoped_ptr<DefaultObserver>* observer) { |
| 192 if (observer->get()) { |
| 193 RemoveObserver(observer->get()); |
| 194 observer->reset(); |
| 195 } |
| 196 } |
OLD | NEW |