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

Side by Side Diff: chrome/browser/speech/chrome_speech_recognition_manager_delegate.cc

Issue 10663018: Changing tab closure handling logic in speech recognition code and cleaning bubble controller. (Spe… (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 6 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) 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 <string> 7 #include <string>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/synchronization/lock.h" 10 #include "base/synchronization/lock.h"
11 #include "base/threading/thread_restrictions.h" 11 #include "base/threading/thread_restrictions.h"
12 #include "base/utf_string_conversions.h" 12 #include "base/utf_string_conversions.h"
13 #include "chrome/browser/browser_process.h" 13 #include "chrome/browser/browser_process.h"
14 #include "chrome/browser/extensions/extension_service.h" 14 #include "chrome/browser/extensions/extension_service.h"
15 #include "chrome/browser/prefs/pref_service.h" 15 #include "chrome/browser/prefs/pref_service.h"
16 #include "chrome/browser/profiles/profile_manager.h" 16 #include "chrome/browser/profiles/profile_manager.h"
17 #include "chrome/browser/speech/chrome_speech_recognition_preferences.h" 17 #include "chrome/browser/speech/chrome_speech_recognition_preferences.h"
18 #include "chrome/browser/speech/speech_recognition_tray_icon_controller.h" 18 #include "chrome/browser/speech/speech_recognition_tray_icon_controller.h"
19 #include "chrome/browser/speech/tab_watcher.h"
19 #include "chrome/browser/tab_contents/tab_util.h" 20 #include "chrome/browser/tab_contents/tab_util.h"
20 #include "chrome/browser/view_type_utils.h" 21 #include "chrome/browser/view_type_utils.h"
21 #include "chrome/common/pref_names.h" 22 #include "chrome/common/pref_names.h"
22 #include "content/public/browser/browser_thread.h" 23 #include "content/public/browser/browser_thread.h"
23 #include "content/public/browser/render_process_host.h" 24 #include "content/public/browser/render_process_host.h"
24 #include "content/public/browser/render_view_host.h" 25 #include "content/public/browser/render_view_host.h"
25 #include "content/public/browser/resource_context.h" 26 #include "content/public/browser/resource_context.h"
26 #include "content/public/browser/speech_recognition_manager.h" 27 #include "content/public/browser/speech_recognition_manager.h"
27 #include "content/public/browser/speech_recognition_session_config.h" 28 #include "content/public/browser/speech_recognition_session_config.h"
28 #include "content/public/browser/speech_recognition_session_context.h" 29 #include "content/public/browser/speech_recognition_session_context.h"
29 #include "content/public/browser/web_contents.h" 30 #include "content/public/browser/web_contents.h"
30 #include "content/public/common/speech_recognition_error.h" 31 #include "content/public/common/speech_recognition_error.h"
31 #include "content/public/common/speech_recognition_result.h" 32 #include "content/public/common/speech_recognition_result.h"
32 #include "grit/generated_resources.h" 33 #include "grit/generated_resources.h"
33 #include "net/url_request/url_request_context_getter.h" 34 #include "net/url_request/url_request_context_getter.h"
34 #include "ui/base/l10n/l10n_util.h" 35 #include "ui/base/l10n/l10n_util.h"
35 36
36 #if defined(OS_WIN) 37 #if defined(OS_WIN)
37 #include "chrome/installer/util/wmi.h" 38 #include "chrome/installer/util/wmi.h"
38 #endif 39 #endif
39 40
40 using content::BrowserThread; 41 using content::BrowserThread;
41 using content::SpeechRecognitionManager; 42 using content::SpeechRecognitionManager;
42 using content::SpeechRecognitionSessionContext;
43 using content::WebContents; 43 using content::WebContents;
44 44
45 namespace { 45 namespace {
46 const int kNoActiveBubble =
47 content::SpeechRecognitionManager::kSessionIDInvalid;
48 46
49 const char kExtensionPrefix[] = "chrome-extension://"; 47 const char kExtensionPrefix[] = "chrome-extension://";
50 48
51 bool RequiresBubble(int session_id) { 49 bool RequiresBubble(int session_id) {
52 return SpeechRecognitionManager::GetInstance()-> 50 return SpeechRecognitionManager::GetInstance()->
53 GetSessionContext(session_id).requested_by_page_element; 51 GetSessionContext(session_id).requested_by_page_element;
54 } 52 }
55 53
56 bool RequiresTrayIcon(int session_id) { 54 bool RequiresTrayIcon(int session_id) {
57 return !RequiresBubble(session_id); 55 return !RequiresBubble(session_id);
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
117 ~OptionalRequestInfo() {} 115 ~OptionalRequestInfo() {}
118 116
119 base::Lock lock_; 117 base::Lock lock_;
120 std::string value_; 118 std::string value_;
121 bool can_report_metrics_; 119 bool can_report_metrics_;
122 120
123 DISALLOW_COPY_AND_ASSIGN(OptionalRequestInfo); 121 DISALLOW_COPY_AND_ASSIGN(OptionalRequestInfo);
124 }; 122 };
125 123
126 ChromeSpeechRecognitionManagerDelegate::ChromeSpeechRecognitionManagerDelegate() 124 ChromeSpeechRecognitionManagerDelegate::ChromeSpeechRecognitionManagerDelegate()
127 : active_bubble_session_id_(kNoActiveBubble) { 125 {
128 } 126 }
129 127
130 ChromeSpeechRecognitionManagerDelegate:: 128 ChromeSpeechRecognitionManagerDelegate::
131 ~ChromeSpeechRecognitionManagerDelegate() { 129 ~ChromeSpeechRecognitionManagerDelegate() {
132 if (tray_icon_controller_.get()) 130 if (tray_icon_controller_.get())
133 tray_icon_controller_->Hide(); 131 tray_icon_controller_->Hide();
134 if (active_bubble_session_id_ != kNoActiveBubble) { 132 if (bubble_controller_.get() && bubble_controller_->GetActiveSessionID())
135 DCHECK(bubble_controller_.get()); 133 bubble_controller_->CloseBubble();
136 bubble_controller_->CloseBubble(active_bubble_session_id_);
137 }
138 } 134 }
139 135
140 void ChromeSpeechRecognitionManagerDelegate::InfoBubbleButtonClicked( 136 void ChromeSpeechRecognitionManagerDelegate::InfoBubbleButtonClicked(
141 int session_id, SpeechRecognitionBubble::Button button) { 137 int session_id, SpeechRecognitionBubble::Button button) {
142 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 138 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
143 DCHECK_EQ(active_bubble_session_id_, session_id);
144 139
145 // Note, the session might have been destroyed, therefore avoid calls to the 140 // Note, the session might have been destroyed, therefore avoid calls to the
146 // manager which imply its existance (e.g., GetSessionContext()). 141 // manager which imply its existance (e.g., GetSessionContext()).
147 142
148 if (button == SpeechRecognitionBubble::BUTTON_CANCEL) { 143 if (button == SpeechRecognitionBubble::BUTTON_CANCEL) {
149 GetBubbleController()->CloseBubble(session_id); 144 GetBubbleController()->CloseBubble();
150 last_session_config_.reset(); 145 last_session_config_.reset();
151 active_bubble_session_id_ = kNoActiveBubble;
152 146
153 // We can safely call AbortSession even if the session has already ended, 147 // We can safely call AbortSession even if the session has already ended,
154 // the manager's public methods are reliable and will handle it properly. 148 // the manager's public methods are reliable and will handle it properly.
155 SpeechRecognitionManager::GetInstance()->AbortSession(session_id); 149 SpeechRecognitionManager::GetInstance()->AbortSession(session_id);
156 } else if (button == SpeechRecognitionBubble::BUTTON_TRY_AGAIN) { 150 } else if (button == SpeechRecognitionBubble::BUTTON_TRY_AGAIN) {
157 GetBubbleController()->CloseBubble(session_id); 151 GetBubbleController()->CloseBubble();
158 active_bubble_session_id_ = kNoActiveBubble;
159 RestartLastSession(); 152 RestartLastSession();
160 } 153 }
161 } 154 }
162 155
163 void ChromeSpeechRecognitionManagerDelegate::InfoBubbleFocusChanged( 156 void ChromeSpeechRecognitionManagerDelegate::InfoBubbleFocusChanged(
164 int session_id) { 157 int session_id) {
165 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 158 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
166 DCHECK_EQ(active_bubble_session_id_, session_id);
167 159
168 // Note, the session might have been destroyed, therefore avoid calls to the 160 // Note, the session might have been destroyed, therefore avoid calls to the
169 // manager which imply its existance (e.g., GetSessionContext()). 161 // manager which imply its existance (e.g., GetSessionContext()).
170 162
171 GetBubbleController()->CloseBubble(session_id); 163 GetBubbleController()->CloseBubble();
172 last_session_config_.reset(); 164 last_session_config_.reset();
173 active_bubble_session_id_ = kNoActiveBubble;
174 165
175 // If the user clicks outside the bubble while capturing audio we abort the 166 // If the user clicks outside the bubble while capturing audio we abort the
176 // session. Otherwise, i.e. audio capture is ended and we are just waiting for 167 // session. Otherwise, i.e. audio capture is ended and we are just waiting for
177 // results, this activity is carried silently in background. 168 // results, this activity is carried silently in background.
178 if (SpeechRecognitionManager::GetInstance()->IsCapturingAudio()) 169 if (SpeechRecognitionManager::GetInstance()->IsCapturingAudio())
179 SpeechRecognitionManager::GetInstance()->AbortSession(session_id); 170 SpeechRecognitionManager::GetInstance()->AbortSession(session_id);
180 } 171 }
181 172
182 void ChromeSpeechRecognitionManagerDelegate::RestartLastSession() { 173 void ChromeSpeechRecognitionManagerDelegate::RestartLastSession() {
183 DCHECK(last_session_config_.get()); 174 DCHECK(last_session_config_.get());
184 SpeechRecognitionManager* manager = SpeechRecognitionManager::GetInstance(); 175 SpeechRecognitionManager* manager = SpeechRecognitionManager::GetInstance();
185 const int new_session_id = manager->CreateSession(*last_session_config_); 176 const int new_session_id = manager->CreateSession(*last_session_config_);
186 DCHECK_NE(new_session_id, kNoActiveBubble); 177 DCHECK_NE(SpeechRecognitionManager::kSessionIDInvalid, new_session_id);
187 last_session_config_.reset(); 178 last_session_config_.reset();
188 manager->StartSession(new_session_id); 179 manager->StartSession(new_session_id);
189 } 180 }
190 181
182 void ChromeSpeechRecognitionManagerDelegate::TabClosedCallback(
183 int render_process_id, int render_view_id) {
184 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
185
186 if (SpeechRecognitionManager* mgr = SpeechRecognitionManager::GetInstance())
187 mgr->AbortAllSessionsForRenderer(render_process_id, render_view_id);
188
189 if (bubble_controller_.get() &&
190 bubble_controller_->IsShowingBubbleOn(render_process_id,
191 render_view_id)) {
192 bubble_controller_->CloseBubble();
193 }
194 }
195
191 void ChromeSpeechRecognitionManagerDelegate::OnRecognitionStart( 196 void ChromeSpeechRecognitionManagerDelegate::OnRecognitionStart(
192 int session_id) { 197 int session_id) {
193 const content::SpeechRecognitionSessionContext& context = 198 const content::SpeechRecognitionSessionContext& context =
194 SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id); 199 SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id);
195 200
196 if (RequiresBubble(session_id)) { 201 if (RequiresBubble(session_id)) {
197 // Copy the configuration of the session (for the "try again" button). 202 // Copy the configuration of the session (for the "try again" button).
198 last_session_config_.reset(new content::SpeechRecognitionSessionConfig( 203 last_session_config_.reset(new content::SpeechRecognitionSessionConfig(
199 SpeechRecognitionManager::GetInstance()->GetSessionConfig(session_id))); 204 SpeechRecognitionManager::GetInstance()->GetSessionConfig(session_id)));
200 205
201 // Create and show the bubble. 206 // Create and show the bubble.
202 DCHECK_EQ(active_bubble_session_id_, kNoActiveBubble);
203 active_bubble_session_id_ = session_id;
204 GetBubbleController()->CreateBubble(session_id, 207 GetBubbleController()->CreateBubble(session_id,
205 context.render_process_id, 208 context.render_process_id,
206 context.render_view_id, 209 context.render_view_id,
207 context.element_rect); 210 context.element_rect);
211 }
208 212
209 // TODO(primiano) Why not creating directly the bubble in warmup mode? 213 // Register callback to auto abort session on tab closure.
210 GetBubbleController()->SetBubbleWarmUpMode(session_id); 214 // |tab_watcher_| is lazyly istantiated on the first call.
215 if (!tab_watcher_.get()) {
216 tab_watcher_ = new TabWatcher(
217 base::Bind(&ChromeSpeechRecognitionManagerDelegate::TabClosedCallback,
218 base::Unretained(this)),
219 BrowserThread::IO);
211 } 220 }
221 tab_watcher_->Watch(context.render_process_id, context.render_view_id);
212 } 222 }
213 223
214 void ChromeSpeechRecognitionManagerDelegate::OnAudioStart(int session_id) { 224 void ChromeSpeechRecognitionManagerDelegate::OnAudioStart(int session_id) {
215 if (RequiresBubble(session_id)) { 225 if (RequiresBubble(session_id)) {
216 GetBubbleController()->SetBubbleRecordingMode(session_id); 226 GetBubbleController()->SetBubbleRecordingMode();
217 } else if (RequiresTrayIcon(session_id)) { 227 } else if (RequiresTrayIcon(session_id)) {
218 // We post the action to the UI thread for sessions requiring a tray icon, 228 // We post the action to the UI thread for sessions requiring a tray icon,
219 // since ChromeSpeechRecognitionPreferences (which requires UI thread) is 229 // since ChromeSpeechRecognitionPreferences (which requires UI thread) is
220 // involved for determining whether a security alert balloon is required. 230 // involved for determining whether a security alert balloon is required.
221 const content::SpeechRecognitionSessionContext& context = 231 const content::SpeechRecognitionSessionContext& context =
222 SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id); 232 SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id);
223 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind( 233 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
224 &ChromeSpeechRecognitionManagerDelegate::ShowTrayIconOnUIThread, 234 &ChromeSpeechRecognitionManagerDelegate::ShowTrayIconOnUIThread,
225 context.context_name, 235 context.context_name,
226 context.render_process_id, 236 context.render_process_id,
227 scoped_refptr<SpeechRecognitionTrayIconController>( 237 scoped_refptr<SpeechRecognitionTrayIconController>(
228 GetTrayIconController()))); 238 GetTrayIconController())));
229 } 239 }
230 } 240 }
231 241
232 void ChromeSpeechRecognitionManagerDelegate::OnEnvironmentEstimationComplete( 242 void ChromeSpeechRecognitionManagerDelegate::OnEnvironmentEstimationComplete(
233 int session_id) { 243 int session_id) {
234 } 244 }
235 245
236 void ChromeSpeechRecognitionManagerDelegate::OnSoundStart(int session_id) { 246 void ChromeSpeechRecognitionManagerDelegate::OnSoundStart(int session_id) {
237 } 247 }
238 248
239 void ChromeSpeechRecognitionManagerDelegate::OnSoundEnd(int session_id) { 249 void ChromeSpeechRecognitionManagerDelegate::OnSoundEnd(int session_id) {
240 } 250 }
241 251
242 void ChromeSpeechRecognitionManagerDelegate::OnAudioEnd(int session_id) { 252 void ChromeSpeechRecognitionManagerDelegate::OnAudioEnd(int session_id) {
243 // OnAudioEnd can be also raised after an abort, when the bubble has already 253 // OnAudioEnd can be also raised after an abort, when the bubble has already
244 // been closed. 254 // been closed.
245 if (RequiresBubble(session_id) && active_bubble_session_id_ == session_id) { 255 if (RequiresBubble(session_id) &&
246 GetBubbleController()->SetBubbleRecognizingMode(session_id); 256 GetBubbleController()->GetActiveSessionID() == session_id) {
257 GetBubbleController()->SetBubbleRecognizingMode();
247 } else if (RequiresTrayIcon(session_id)) { 258 } else if (RequiresTrayIcon(session_id)) {
248 GetTrayIconController()->Hide(); 259 GetTrayIconController()->Hide();
249 } 260 }
250 } 261 }
251 262
252 void ChromeSpeechRecognitionManagerDelegate::OnRecognitionResult( 263 void ChromeSpeechRecognitionManagerDelegate::OnRecognitionResult(
253 int session_id, const content::SpeechRecognitionResult& result) { 264 int session_id, const content::SpeechRecognitionResult& result) {
254 // A result can be dispatched when the bubble is not visible anymore (e.g., 265 // A result can be dispatched when the bubble is not visible anymore (e.g.,
255 // lost focus while waiting for a result, thus continuing in background). 266 // lost focus while waiting for a result, thus continuing in background).
256 if (RequiresBubble(session_id) && active_bubble_session_id_ == session_id) { 267 if (RequiresBubble(session_id) &&
257 GetBubbleController()->CloseBubble(session_id); 268 GetBubbleController()->GetActiveSessionID() == session_id) {
269 GetBubbleController()->CloseBubble();
258 last_session_config_.reset(); 270 last_session_config_.reset();
259 active_bubble_session_id_ = kNoActiveBubble;
260 } 271 }
261 } 272 }
262 273
263 void ChromeSpeechRecognitionManagerDelegate::OnRecognitionError( 274 void ChromeSpeechRecognitionManagerDelegate::OnRecognitionError(
264 int session_id, const content::SpeechRecognitionError& error) { 275 int session_id, const content::SpeechRecognitionError& error) {
265 // An error can be dispatched when the bubble is not visible anymore. 276 // An error can be dispatched when the bubble is not visible anymore.
266 if (active_bubble_session_id_ != session_id) 277 if (GetBubbleController()->GetActiveSessionID() != session_id)
267 return; 278 return;
268 DCHECK(RequiresBubble(session_id)); 279 DCHECK(RequiresBubble(session_id));
269 280
270 int error_message_id = 0; 281 int error_message_id = 0;
271 switch (error.code) { 282 switch (error.code) {
272 case content::SPEECH_RECOGNITION_ERROR_AUDIO: 283 case content::SPEECH_RECOGNITION_ERROR_AUDIO:
273 switch (error.details) { 284 switch (error.details) {
274 case content::SPEECH_AUDIO_ERROR_DETAILS_NO_MIC: 285 case content::SPEECH_AUDIO_ERROR_DETAILS_NO_MIC:
275 error_message_id = IDS_SPEECH_INPUT_NO_MIC; 286 error_message_id = IDS_SPEECH_INPUT_NO_MIC;
276 break; 287 break;
(...skipping 15 matching lines...) Expand all
292 error_message_id = IDS_SPEECH_INPUT_NO_RESULTS; 303 error_message_id = IDS_SPEECH_INPUT_NO_RESULTS;
293 break; 304 break;
294 case content::SPEECH_RECOGNITION_ERROR_NETWORK: 305 case content::SPEECH_RECOGNITION_ERROR_NETWORK:
295 error_message_id = IDS_SPEECH_INPUT_NET_ERROR; 306 error_message_id = IDS_SPEECH_INPUT_NET_ERROR;
296 break; 307 break;
297 default: 308 default:
298 NOTREACHED() << "unknown error " << error.code; 309 NOTREACHED() << "unknown error " << error.code;
299 return; 310 return;
300 } 311 }
301 GetBubbleController()->SetBubbleMessage( 312 GetBubbleController()->SetBubbleMessage(
302 session_id, l10n_util::GetStringUTF16(error_message_id)); 313 l10n_util::GetStringUTF16(error_message_id));
303 } 314 }
304 315
305 void ChromeSpeechRecognitionManagerDelegate::OnAudioLevelsChange( 316 void ChromeSpeechRecognitionManagerDelegate::OnAudioLevelsChange(
306 int session_id, float volume, float noise_volume) { 317 int session_id, float volume, float noise_volume) {
307 if (active_bubble_session_id_ == session_id) { 318 if (GetBubbleController()->GetActiveSessionID() == session_id) {
308 DCHECK(RequiresBubble(session_id)); 319 DCHECK(RequiresBubble(session_id));
309 GetBubbleController()->SetBubbleInputVolume(session_id, 320 GetBubbleController()->SetBubbleInputVolume(volume, noise_volume);
310 volume, noise_volume);
311 } else if (RequiresTrayIcon(session_id)) { 321 } else if (RequiresTrayIcon(session_id)) {
312 GetTrayIconController()->SetVUMeterVolume(volume); 322 GetTrayIconController()->SetVUMeterVolume(volume);
313 } 323 }
314 } 324 }
315 325
316 void ChromeSpeechRecognitionManagerDelegate::OnRecognitionEnd(int session_id) { 326 void ChromeSpeechRecognitionManagerDelegate::OnRecognitionEnd(int session_id) {
317 // No need to remove the bubble here, since either one of the following events 327 // No need to remove the bubble here, since either one of the following events
318 // must have happened prior to this callback: 328 // must have happened prior to this callback:
319 // - A previous OnRecognitionResult event already closed the bubble. 329 // - A previous OnRecognitionResult event already closed the bubble.
320 // - An error occurred, so the bubble is showing the error and will be closed 330 // - An error occurred, so the bubble is showing the error and will be closed
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after
447 457
448 SpeechRecognitionTrayIconController* 458 SpeechRecognitionTrayIconController*
449 ChromeSpeechRecognitionManagerDelegate::GetTrayIconController() { 459 ChromeSpeechRecognitionManagerDelegate::GetTrayIconController() {
450 if (!tray_icon_controller_.get()) 460 if (!tray_icon_controller_.get())
451 tray_icon_controller_ = new SpeechRecognitionTrayIconController(); 461 tray_icon_controller_ = new SpeechRecognitionTrayIconController();
452 return tray_icon_controller_.get(); 462 return tray_icon_controller_.get();
453 } 463 }
454 464
455 465
456 } // namespace speech 466 } // namespace speech
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698