OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/speech/chrome_speech_recognition_manager_delegate.h" | 5 #include "chrome/browser/speech/chrome_speech_recognition_manager_delegate.h" |
6 | 6 |
7 #include <set> | 7 #include <set> |
8 #include <string> | 8 #include <string> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
11 #include "base/prefs/pref_service.h" | 11 #include "base/prefs/pref_service.h" |
12 #include "base/strings/utf_string_conversions.h" | 12 #include "base/strings/utf_string_conversions.h" |
13 #include "base/synchronization/lock.h" | 13 #include "base/synchronization/lock.h" |
14 #include "base/threading/thread_restrictions.h" | 14 #include "base/threading/thread_restrictions.h" |
15 #include "chrome/browser/browser_process.h" | 15 #include "chrome/browser/browser_process.h" |
16 #include "chrome/browser/profiles/profile_manager.h" | 16 #include "chrome/browser/profiles/profile_manager.h" |
17 #include "chrome/browser/tab_contents/tab_util.h" | 17 #include "chrome/browser/tab_contents/tab_util.h" |
18 #include "chrome/common/pref_names.h" | 18 #include "chrome/common/pref_names.h" |
19 #include "chrome/common/url_constants.h" | 19 #include "chrome/common/url_constants.h" |
20 #include "content/public/browser/browser_thread.h" | 20 #include "content/public/browser/browser_thread.h" |
21 #include "content/public/browser/notification_registrar.h" | |
22 #include "content/public/browser/notification_source.h" | |
23 #include "content/public/browser/notification_types.h" | |
24 #include "content/public/browser/render_process_host.h" | 21 #include "content/public/browser/render_process_host.h" |
25 #include "content/public/browser/render_view_host.h" | 22 #include "content/public/browser/render_view_host.h" |
26 #include "content/public/browser/resource_context.h" | 23 #include "content/public/browser/resource_context.h" |
27 #include "content/public/browser/speech_recognition_manager.h" | 24 #include "content/public/browser/speech_recognition_manager.h" |
28 #include "content/public/browser/speech_recognition_session_config.h" | 25 #include "content/public/browser/speech_recognition_session_config.h" |
29 #include "content/public/browser/speech_recognition_session_context.h" | 26 #include "content/public/browser/speech_recognition_session_context.h" |
30 #include "content/public/browser/web_contents.h" | 27 #include "content/public/browser/web_contents.h" |
| 28 #include "content/public/browser/web_contents_observer.h" |
31 #include "content/public/common/speech_recognition_error.h" | 29 #include "content/public/common/speech_recognition_error.h" |
32 #include "content/public/common/speech_recognition_result.h" | 30 #include "content/public/common/speech_recognition_result.h" |
33 #include "net/url_request/url_request_context_getter.h" | 31 #include "net/url_request/url_request_context_getter.h" |
34 | 32 |
35 #if defined(OS_WIN) | 33 #if defined(OS_WIN) |
36 #include "chrome/installer/util/wmi.h" | 34 #include "chrome/installer/util/wmi.h" |
37 #endif | 35 #endif |
38 | 36 |
39 #if defined(ENABLE_EXTENSIONS) | 37 #if defined(ENABLE_EXTENSIONS) |
40 #include "chrome/browser/extensions/extension_service.h" | 38 #include "chrome/browser/extensions/extension_service.h" |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
130 | 128 |
131 DISALLOW_COPY_AND_ASSIGN(OptionalRequestInfo); | 129 DISALLOW_COPY_AND_ASSIGN(OptionalRequestInfo); |
132 }; | 130 }; |
133 | 131 |
134 // Simple utility to get notified when a WebContent (a tab or an extension's | 132 // Simple utility to get notified when a WebContent (a tab or an extension's |
135 // background page) is closed or crashes. The callback will always be called on | 133 // background page) is closed or crashes. The callback will always be called on |
136 // the UI thread. | 134 // the UI thread. |
137 // There is no restriction on the constructor, however this class must be | 135 // There is no restriction on the constructor, however this class must be |
138 // destroyed on the UI thread, due to the NotificationRegistrar dependency. | 136 // destroyed on the UI thread, due to the NotificationRegistrar dependency. |
139 class ChromeSpeechRecognitionManagerDelegate::TabWatcher | 137 class ChromeSpeechRecognitionManagerDelegate::TabWatcher |
140 : public base::RefCountedThreadSafe<TabWatcher>, | 138 : public base::RefCountedThreadSafe<TabWatcher> { |
141 public content::NotificationObserver { | |
142 public: | 139 public: |
143 typedef base::Callback<void(int render_process_id, int render_view_id)> | 140 typedef base::Callback<void(int render_process_id, int render_view_id)> |
144 TabClosedCallback; | 141 TabClosedCallback; |
145 | 142 |
146 explicit TabWatcher(TabClosedCallback tab_closed_callback) | 143 explicit TabWatcher(TabClosedCallback tab_closed_callback) |
147 : tab_closed_callback_(tab_closed_callback) { | 144 : tab_closed_callback_(tab_closed_callback) { |
148 } | 145 } |
149 | 146 |
150 // Starts monitoring the WebContents corresponding to the given | 147 // Starts monitoring the WebContents corresponding to the given |
151 // |render_process_id|, |render_view_id| pair, invoking |tab_closed_callback_| | 148 // |render_process_id|, |render_view_id| pair, invoking |tab_closed_callback_| |
152 // if closed/unloaded. | 149 // if closed/unloaded. |
153 void Watch(int render_process_id, int render_view_id) { | 150 void Watch(int render_process_id, int render_view_id) { |
154 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { | 151 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { |
155 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind( | 152 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind( |
156 &TabWatcher::Watch, this, render_process_id, render_view_id)); | 153 &TabWatcher::Watch, this, render_process_id, render_view_id)); |
157 return; | 154 return; |
158 } | 155 } |
159 | 156 |
160 WebContents* web_contents = tab_util::GetWebContentsByID(render_process_id, | 157 WebContents* web_contents = tab_util::GetWebContentsByID(render_process_id, |
161 render_view_id); | 158 render_view_id); |
162 // Sessions initiated by speech input extension APIs will end up in a NULL | 159 // Sessions initiated by speech input extension APIs will end up in a NULL |
163 // WebContent here, but they are properly managed by the | 160 // WebContent here, but they are properly managed by the |
164 // chrome::SpeechInputExtensionManager. However, sessions initiated within a | 161 // chrome::SpeechInputExtensionManager. However, sessions initiated within a |
165 // extension using the (new) speech JS APIs, will be properly handled here. | 162 // extension using the (new) speech JS APIs, will be properly handled here. |
166 // TODO(primiano) turn this line into a DCHECK once speech input extension | 163 // TODO(primiano) turn this line into a DCHECK once speech input extension |
167 // API is deprecated. | 164 // API is deprecated. |
168 if (!web_contents) | 165 if (!web_contents) |
169 return; | 166 return; |
170 | 167 |
171 // Avoid multiple registrations on |registrar_| for the same |web_contents|. | 168 // Avoid multiple registrations for the same |web_contents|. |
172 if (FindWebContents(web_contents) != registered_web_contents_.end()) { | 169 if (FindWebContents(web_contents) != registered_web_contents_.end()) { |
173 return; | 170 return; |
174 } | 171 } |
175 registered_web_contents_.push_back( | 172 registered_web_contents_.push_back(new WebContentsTracker( |
176 WebContentsInfo(web_contents, render_process_id, render_view_id)); | 173 web_contents, base::Bind(&TabWatcher::OnTabClosed, |
177 | 174 // |this| outlives WebContentsTracker. |
178 // Lazy initialize the registrar. | 175 base::Unretained(this), web_contents), |
179 if (!registrar_.get()) | 176 render_process_id, render_view_id)); |
180 registrar_.reset(new content::NotificationRegistrar()); | |
181 | |
182 registrar_->Add(this, | |
183 content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED, | |
184 content::Source<WebContents>(web_contents)); | |
185 registrar_->Add(this, | |
186 content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED, | |
187 content::Source<WebContents>(web_contents)); | |
188 } | 177 } |
189 | 178 |
190 // content::NotificationObserver implementation. | 179 void OnTabClosed(content::WebContents* web_contents) { |
191 void Observe(int type, | 180 ScopedVector<WebContentsTracker>::iterator iter = |
192 const content::NotificationSource& source, | 181 FindWebContents(web_contents); |
193 const content::NotificationDetails& details) override { | |
194 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
195 DCHECK(type == content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED || | |
196 type == content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED); | |
197 | |
198 WebContents* web_contents = content::Source<WebContents>(source).ptr(); | |
199 std::vector<WebContentsInfo>::iterator iter = FindWebContents(web_contents); | |
200 DCHECK(iter != registered_web_contents_.end()); | 182 DCHECK(iter != registered_web_contents_.end()); |
201 int render_process_id = iter->render_process_id; | 183 int render_process_id = (*iter)->render_process_id(); |
202 int render_view_id = iter->render_view_id; | 184 int render_view_id = (*iter)->render_view_id(); |
203 registered_web_contents_.erase(iter); | 185 registered_web_contents_.erase(iter); |
204 | 186 |
205 registrar_->Remove(this, | |
206 content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED, | |
207 content::Source<WebContents>(web_contents)); | |
208 registrar_->Remove(this, | |
209 content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED, | |
210 content::Source<WebContents>(web_contents)); | |
211 | |
212 tab_closed_callback_.Run(render_process_id, render_view_id); | 187 tab_closed_callback_.Run(render_process_id, render_view_id); |
213 } | 188 } |
214 | 189 |
215 private: | 190 private: |
216 struct WebContentsInfo { | 191 class WebContentsTracker : public content::WebContentsObserver { |
217 WebContentsInfo(content::WebContents* web_contents, | 192 public: |
218 int render_process_id, | 193 WebContentsTracker(content::WebContents* web_contents, |
219 int render_view_id) | 194 const base::Closure& finished_callback, |
220 : web_contents(web_contents), | 195 int render_process_id, |
221 render_process_id(render_process_id), | 196 int render_view_id) |
222 render_view_id(render_view_id) {} | 197 : content::WebContentsObserver(web_contents), |
| 198 finished_callback_(finished_callback), |
| 199 render_process_id_(render_process_id), |
| 200 render_view_id_(render_view_id) {} |
223 | 201 |
224 ~WebContentsInfo() {} | 202 ~WebContentsTracker() override {} |
225 | 203 |
226 content::WebContents* web_contents; | 204 int render_process_id() const { return render_process_id_; } |
227 int render_process_id; | 205 int render_view_id() const { return render_view_id_; } |
228 int render_view_id; | 206 |
| 207 private: |
| 208 // content::WebContentsObserver overrides. |
| 209 void WebContentsDestroyed() override { |
| 210 Observe(nullptr); |
| 211 finished_callback_.Run(); |
| 212 // NOTE: We are deleted now. |
| 213 } |
| 214 void RenderViewHostChanged(content::RenderViewHost* old_host, |
| 215 content::RenderViewHost* new_host) override { |
| 216 Observe(nullptr); |
| 217 finished_callback_.Run(); |
| 218 // NOTE: We are deleted now. |
| 219 } |
| 220 |
| 221 const base::Closure finished_callback_; |
| 222 const int render_process_id_; |
| 223 const int render_view_id_; |
229 }; | 224 }; |
230 | 225 |
231 friend class base::RefCountedThreadSafe<TabWatcher>; | 226 friend class base::RefCountedThreadSafe<TabWatcher>; |
232 | 227 |
233 ~TabWatcher() override { | 228 ~TabWatcher() { |
234 // Must be destroyed on the UI thread due to |registrar_| non thread-safety. | 229 // Must be destroyed on the UI thread due to |registrar_| non thread-safety. |
| 230 // TODO(lazyboy): Do we still need this? |
235 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 231 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
236 } | 232 } |
237 | 233 |
238 // Helper function to find the iterator in |registered_web_contents_| which | 234 // Helper function to find the iterator in |registered_web_contents_| which |
239 // contains |web_contents|. | 235 // contains |web_contents|. |
240 std::vector<WebContentsInfo>::iterator FindWebContents( | 236 ScopedVector<WebContentsTracker>::iterator FindWebContents( |
241 content::WebContents* web_contents) { | 237 content::WebContents* web_contents) { |
242 for (std::vector<WebContentsInfo>::iterator i( | 238 for (ScopedVector<WebContentsTracker>::iterator i( |
243 registered_web_contents_.begin()); | 239 registered_web_contents_.begin()); |
244 i != registered_web_contents_.end(); ++i) { | 240 i != registered_web_contents_.end(); ++i) { |
245 if (i->web_contents == web_contents) | 241 if ((*i)->web_contents() == web_contents) |
246 return i; | 242 return i; |
247 } | 243 } |
248 | 244 |
249 return registered_web_contents_.end(); | 245 return registered_web_contents_.end(); |
250 } | 246 } |
251 | 247 |
252 // Lazy-initialized and used on the UI thread to handle web contents | |
253 // notifications (tab closing). | |
254 scoped_ptr<content::NotificationRegistrar> registrar_; | |
255 | |
256 // Keeps track of which WebContent(s) have been registered, in order to avoid | 248 // Keeps track of which WebContent(s) have been registered, in order to avoid |
257 // double registrations on |registrar_| and to pass the correct render | 249 // double registrations on WebContentsObserver and to pass the correct render |
258 // process id and render view id to |tab_closed_callback_| after the process | 250 // process id and render view id to |tab_closed_callback_| after the process |
259 // has gone away. | 251 // has gone away. |
260 std::vector<WebContentsInfo> registered_web_contents_; | 252 ScopedVector<WebContentsTracker> registered_web_contents_; |
261 | 253 |
262 // Callback used to notify, on the thread specified by |callback_thread_| the | 254 // Callback used to notify, on the thread specified by |callback_thread_| the |
263 // closure of a registered tab. | 255 // closure of a registered tab. |
264 TabClosedCallback tab_closed_callback_; | 256 TabClosedCallback tab_closed_callback_; |
265 | 257 |
266 DISALLOW_COPY_AND_ASSIGN(TabWatcher); | 258 DISALLOW_COPY_AND_ASSIGN(TabWatcher); |
267 }; | 259 }; |
268 | 260 |
269 ChromeSpeechRecognitionManagerDelegate | 261 ChromeSpeechRecognitionManagerDelegate |
270 ::ChromeSpeechRecognitionManagerDelegate() { | 262 ::ChromeSpeechRecognitionManagerDelegate() { |
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
434 // Otherwise this should be a regular tab contents. | 426 // Otherwise this should be a regular tab contents. |
435 allowed = true; | 427 allowed = true; |
436 check_permission = true; | 428 check_permission = true; |
437 #endif | 429 #endif |
438 | 430 |
439 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | 431 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
440 base::Bind(callback, check_permission, allowed)); | 432 base::Bind(callback, check_permission, allowed)); |
441 } | 433 } |
442 | 434 |
443 } // namespace speech | 435 } // namespace speech |
OLD | NEW |