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

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: Moved TabWatcher as a private class in chrome_speech_recognition_manager_delegate.cc Created 8 years, 5 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 <set>
7 #include <string> 8 #include <string>
8 9
9 #include "base/bind.h" 10 #include "base/bind.h"
10 #include "base/synchronization/lock.h" 11 #include "base/synchronization/lock.h"
11 #include "base/threading/thread_restrictions.h" 12 #include "base/threading/thread_restrictions.h"
12 #include "base/utf_string_conversions.h" 13 #include "base/utf_string_conversions.h"
13 #include "chrome/browser/browser_process.h" 14 #include "chrome/browser/browser_process.h"
14 #include "chrome/browser/extensions/extension_service.h" 15 #include "chrome/browser/extensions/extension_service.h"
15 #include "chrome/browser/prefs/pref_service.h" 16 #include "chrome/browser/prefs/pref_service.h"
16 #include "chrome/browser/profiles/profile_manager.h" 17 #include "chrome/browser/profiles/profile_manager.h"
17 #include "chrome/browser/speech/chrome_speech_recognition_preferences.h" 18 #include "chrome/browser/speech/chrome_speech_recognition_preferences.h"
18 #include "chrome/browser/speech/speech_recognition_tray_icon_controller.h" 19 #include "chrome/browser/speech/speech_recognition_tray_icon_controller.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"
24 #include "content/public/browser/notification_registrar.h"
25 #include "content/public/browser/notification_source.h"
26 #include "content/public/browser/notification_types.h"
23 #include "content/public/browser/render_process_host.h" 27 #include "content/public/browser/render_process_host.h"
24 #include "content/public/browser/render_view_host.h" 28 #include "content/public/browser/render_view_host.h"
25 #include "content/public/browser/resource_context.h" 29 #include "content/public/browser/resource_context.h"
26 #include "content/public/browser/speech_recognition_manager.h" 30 #include "content/public/browser/speech_recognition_manager.h"
27 #include "content/public/browser/speech_recognition_session_config.h" 31 #include "content/public/browser/speech_recognition_session_config.h"
28 #include "content/public/browser/speech_recognition_session_context.h" 32 #include "content/public/browser/speech_recognition_session_context.h"
29 #include "content/public/browser/web_contents.h" 33 #include "content/public/browser/web_contents.h"
30 #include "content/public/common/speech_recognition_error.h" 34 #include "content/public/common/speech_recognition_error.h"
31 #include "content/public/common/speech_recognition_result.h" 35 #include "content/public/common/speech_recognition_result.h"
32 #include "grit/generated_resources.h" 36 #include "grit/generated_resources.h"
33 #include "net/url_request/url_request_context_getter.h" 37 #include "net/url_request/url_request_context_getter.h"
34 #include "ui/base/l10n/l10n_util.h" 38 #include "ui/base/l10n/l10n_util.h"
35 39
36 #if defined(OS_WIN) 40 #if defined(OS_WIN)
37 #include "chrome/installer/util/wmi.h" 41 #include "chrome/installer/util/wmi.h"
38 #endif 42 #endif
39 43
40 using content::BrowserThread; 44 using content::BrowserThread;
41 using content::SpeechRecognitionManager; 45 using content::SpeechRecognitionManager;
42 using content::SpeechRecognitionSessionContext;
43 using content::WebContents; 46 using content::WebContents;
44 47
45 namespace { 48 namespace {
46 const int kNoActiveBubble =
47 content::SpeechRecognitionManager::kSessionIDInvalid;
48 49
49 const char kExtensionPrefix[] = "chrome-extension://"; 50 const char kExtensionPrefix[] = "chrome-extension://";
50 51
51 bool RequiresBubble(int session_id) { 52 bool RequiresBubble(int session_id) {
52 return SpeechRecognitionManager::GetInstance()-> 53 return SpeechRecognitionManager::GetInstance()->
53 GetSessionContext(session_id).requested_by_page_element; 54 GetSessionContext(session_id).requested_by_page_element;
54 } 55 }
55 56
56 bool RequiresTrayIcon(int session_id) { 57 bool RequiresTrayIcon(int session_id) {
57 return !RequiresBubble(session_id); 58 return !RequiresBubble(session_id);
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
116 117
117 ~OptionalRequestInfo() {} 118 ~OptionalRequestInfo() {}
118 119
119 base::Lock lock_; 120 base::Lock lock_;
120 std::string value_; 121 std::string value_;
121 bool can_report_metrics_; 122 bool can_report_metrics_;
122 123
123 DISALLOW_COPY_AND_ASSIGN(OptionalRequestInfo); 124 DISALLOW_COPY_AND_ASSIGN(OptionalRequestInfo);
124 }; 125 };
125 126
126 ChromeSpeechRecognitionManagerDelegate::ChromeSpeechRecognitionManagerDelegate() 127 // Simple utility to get notified when a WebContent (a tab or an extension's
127 : active_bubble_session_id_(kNoActiveBubble) { 128 // background page) is closed or crashes. Both the callback site and the
129 // callback thread are passed by the caller in the constructor.
130 // There is no restriction on the constructor, however this class must be
131 // destroyed on the UI thread, due to the NotificationRegistrar dependency.
132 class ChromeSpeechRecognitionManagerDelegate::TabWatcher
133 : public base::RefCountedThreadSafe<TabWatcher>,
134 public content::NotificationObserver {
135 public:
136 typedef base::Callback<void(int render_process_id, int render_view_id)>
137 TabClosedCallback;
138
139 TabWatcher(TabClosedCallback tab_closed_callback,
140 BrowserThread::ID callback_thread)
141 : tab_closed_callback_(tab_closed_callback),
142 callback_thread_(callback_thread) {
143 }
144
145 // Starts monitoring the WebContents corresponding to the given
146 // |render_process_id|, |render_view_id| pair, invoking |tab_closed_callback_|
147 // if closed/unloaded.
148 void Watch(int render_process_id, int render_view_id) {
149 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
150 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
151 &TabWatcher::Watch, this, render_process_id, render_view_id));
152 return;
153 }
154
155 WebContents* web_contents = tab_util::GetWebContentsByID(render_process_id,
156 render_view_id);
157 // Sessions initiated by speech input extension APIs will end up in a NULL
158 // WebContent here, but they are properly managed by the
159 // chrome::SpeechInputExtensionManager. However, sessions initiated within a
160 // extension using the (new) speech JS APIs, will be properly handled here.
161 // TODO(primiano) turn this line into a DCHECK once speech input extension
162 // API is deprecated.
163 if (!web_contents)
164 return;
165
166 // Avoid multiple registrations on |registrar_| for the same |web_contents|.
167 if (registered_web_contents_.find(web_contents) !=
168 registered_web_contents_.end()) {
169 return;
170 }
171 registered_web_contents_.insert(web_contents);
172
173 // Lazy initialize the registrar.
174 if (!registrar_.get())
175 registrar_.reset(new content::NotificationRegistrar());
176
177 registrar_->Add(this,
178 content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED,
179 content::Source<WebContents>(web_contents));
180 }
181
182 // content::NotificationObserver implementation.
183 virtual void Observe(int type,
184 const content::NotificationSource& source,
185 const content::NotificationDetails& details) OVERRIDE {
186 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
187 DCHECK_EQ(content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED, type);
188
189 WebContents* web_contents = content::Source<WebContents>(source).ptr();
190 int render_process_id = web_contents->GetRenderProcessHost()->GetID();
191 int render_view_id = web_contents->GetRenderViewHost()->GetRoutingID();
192
193 registrar_->Remove(this,
194 content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED,
195 content::Source<WebContents>(web_contents));
196 registered_web_contents_.erase(web_contents);
197
198 BrowserThread::PostTask(callback_thread_, FROM_HERE, base::Bind(
199 tab_closed_callback_, render_process_id, render_view_id));
200 }
201
202 private:
203 friend class base::RefCountedThreadSafe<TabWatcher>;
204
205 virtual ~TabWatcher() {
206 // Must be destroyed on the UI thread due to |registrar_| non thread-safety.
207 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
208 }
209
210 // Lazy-initialized and used on the UI thread to handle web contents
211 // notifications (tab closing).
212 scoped_ptr<content::NotificationRegistrar> registrar_;
213
214 // Keeps track of which WebContent(s) have been registered, in order to avoid
215 // double registrations on |registrar_|
216 std::set<content::WebContents*> registered_web_contents_;
217
218 // Callback used to notify, on the thread specified by |callback_thread_| the
219 // closure of a registered tab.
220 TabClosedCallback tab_closed_callback_;
221 content::BrowserThread::ID callback_thread_;
222
223 DISALLOW_COPY_AND_ASSIGN(TabWatcher);
224 };
225
226 ChromeSpeechRecognitionManagerDelegate
227 ::ChromeSpeechRecognitionManagerDelegate() {
128 } 228 }
129 229
130 ChromeSpeechRecognitionManagerDelegate:: 230 ChromeSpeechRecognitionManagerDelegate
131 ~ChromeSpeechRecognitionManagerDelegate() { 231 ::~ChromeSpeechRecognitionManagerDelegate() {
132 if (tray_icon_controller_.get()) 232 if (tray_icon_controller_.get())
133 tray_icon_controller_->Hide(); 233 tray_icon_controller_->Hide();
134 if (active_bubble_session_id_ != kNoActiveBubble) { 234 if (bubble_controller_.get())
135 DCHECK(bubble_controller_.get()); 235 bubble_controller_->CloseBubble();
136 bubble_controller_->CloseBubble(active_bubble_session_id_);
137 }
138 } 236 }
139 237
140 void ChromeSpeechRecognitionManagerDelegate::InfoBubbleButtonClicked( 238 void ChromeSpeechRecognitionManagerDelegate::InfoBubbleButtonClicked(
141 int session_id, SpeechRecognitionBubble::Button button) { 239 int session_id, SpeechRecognitionBubble::Button button) {
142 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 240 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
143 DCHECK_EQ(active_bubble_session_id_, session_id);
144 241
145 // Note, the session might have been destroyed, therefore avoid calls to the 242 // Note, the session might have been destroyed, therefore avoid calls to the
146 // manager which imply its existance (e.g., GetSessionContext()). 243 // manager which imply its existance (e.g., GetSessionContext()).
147 244
148 if (button == SpeechRecognitionBubble::BUTTON_CANCEL) { 245 if (button == SpeechRecognitionBubble::BUTTON_CANCEL) {
149 GetBubbleController()->CloseBubble(session_id); 246 GetBubbleController()->CloseBubble();
150 last_session_config_.reset(); 247 last_session_config_.reset();
151 active_bubble_session_id_ = kNoActiveBubble;
152 248
153 // We can safely call AbortSession even if the session has already ended, 249 // 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. 250 // the manager's public methods are reliable and will handle it properly.
155 SpeechRecognitionManager::GetInstance()->AbortSession(session_id); 251 SpeechRecognitionManager::GetInstance()->AbortSession(session_id);
156 } else if (button == SpeechRecognitionBubble::BUTTON_TRY_AGAIN) { 252 } else if (button == SpeechRecognitionBubble::BUTTON_TRY_AGAIN) {
157 GetBubbleController()->CloseBubble(session_id); 253 GetBubbleController()->CloseBubble();
158 active_bubble_session_id_ = kNoActiveBubble;
159 RestartLastSession(); 254 RestartLastSession();
255 } else {
256 NOTREACHED();
160 } 257 }
161 } 258 }
162 259
163 void ChromeSpeechRecognitionManagerDelegate::InfoBubbleFocusChanged( 260 void ChromeSpeechRecognitionManagerDelegate::InfoBubbleFocusChanged(
164 int session_id) { 261 int session_id) {
165 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 262 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
166 DCHECK_EQ(active_bubble_session_id_, session_id); 263
264 // This check is needed since on some systems (MacOS), in rare cases, if the
265 // user clicks repeatedly and fast on the input element, the FocusChanged
266 // event (corresponding to the old session that should be aborted) can be
267 // received after a new session (corresponding to the 2nd click) is started.
268 if (GetBubbleController()->GetActiveSessionID() != session_id)
269 return;
167 270
168 // Note, the session might have been destroyed, therefore avoid calls to the 271 // Note, the session might have been destroyed, therefore avoid calls to the
169 // manager which imply its existance (e.g., GetSessionContext()). 272 // manager which imply its existance (e.g., GetSessionContext()).
170 273 GetBubbleController()->CloseBubble();
171 GetBubbleController()->CloseBubble(session_id);
172 last_session_config_.reset(); 274 last_session_config_.reset();
173 active_bubble_session_id_ = kNoActiveBubble;
174 275
175 // If the user clicks outside the bubble while capturing audio we abort the 276 // 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 277 // session. Otherwise, i.e. audio capture is ended and we are just waiting for
177 // results, this activity is carried silently in background. 278 // results, this activity is carried silently in background.
178 if (SpeechRecognitionManager::GetInstance()->IsCapturingAudio()) 279 if (SpeechRecognitionManager::GetInstance()->IsCapturingAudio())
179 SpeechRecognitionManager::GetInstance()->AbortSession(session_id); 280 SpeechRecognitionManager::GetInstance()->AbortSession(session_id);
180 } 281 }
181 282
182 void ChromeSpeechRecognitionManagerDelegate::RestartLastSession() { 283 void ChromeSpeechRecognitionManagerDelegate::RestartLastSession() {
183 DCHECK(last_session_config_.get()); 284 DCHECK(last_session_config_.get());
184 SpeechRecognitionManager* manager = SpeechRecognitionManager::GetInstance(); 285 SpeechRecognitionManager* manager = SpeechRecognitionManager::GetInstance();
185 const int new_session_id = manager->CreateSession(*last_session_config_); 286 const int new_session_id = manager->CreateSession(*last_session_config_);
186 DCHECK_NE(new_session_id, kNoActiveBubble); 287 DCHECK_NE(SpeechRecognitionManager::kSessionIDInvalid, new_session_id);
187 last_session_config_.reset(); 288 last_session_config_.reset();
188 manager->StartSession(new_session_id); 289 manager->StartSession(new_session_id);
189 } 290 }
190 291
292 void ChromeSpeechRecognitionManagerDelegate::TabClosedCallback(
293 int render_process_id, int render_view_id) {
294 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
295
296 SpeechRecognitionManager* manager = SpeechRecognitionManager::GetInstance();
297 // |manager| becomes NULL if a browser shutdown happens between the post of
298 // this task (from the UI thread) and this call (on the IO thread). In this
299 // case we just return.
300 if (!manager)
301 return;
302
303 manager->AbortAllSessionsForRenderView(render_process_id, render_view_id);
304
305 if (bubble_controller_.get() &&
306 bubble_controller_->IsShowingBubbleForRenderView(render_process_id,
307 render_view_id)) {
308 bubble_controller_->CloseBubble();
309 }
310 }
311
191 void ChromeSpeechRecognitionManagerDelegate::OnRecognitionStart( 312 void ChromeSpeechRecognitionManagerDelegate::OnRecognitionStart(
192 int session_id) { 313 int session_id) {
193 const content::SpeechRecognitionSessionContext& context = 314 const content::SpeechRecognitionSessionContext& context =
194 SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id); 315 SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id);
195 316
196 if (RequiresBubble(session_id)) { 317 if (RequiresBubble(session_id)) {
197 // Copy the configuration of the session (for the "try again" button). 318 // Copy the configuration of the session (for the "try again" button).
198 last_session_config_.reset(new content::SpeechRecognitionSessionConfig( 319 last_session_config_.reset(new content::SpeechRecognitionSessionConfig(
199 SpeechRecognitionManager::GetInstance()->GetSessionConfig(session_id))); 320 SpeechRecognitionManager::GetInstance()->GetSessionConfig(session_id)));
200 321
201 // Create and show the bubble. 322 // 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, 323 GetBubbleController()->CreateBubble(session_id,
205 context.render_process_id, 324 context.render_process_id,
206 context.render_view_id, 325 context.render_view_id,
207 context.element_rect); 326 context.element_rect);
327 }
208 328
209 // TODO(primiano) Why not creating directly the bubble in warmup mode? 329 // Register callback to auto abort session on tab closure.
210 GetBubbleController()->SetBubbleWarmUpMode(session_id); 330 // |tab_watcher_| is lazyly istantiated on the first call.
331 if (!tab_watcher_.get()) {
332 tab_watcher_ = new TabWatcher(
333 base::Bind(&ChromeSpeechRecognitionManagerDelegate::TabClosedCallback,
334 base::Unretained(this)),
335 BrowserThread::IO);
211 } 336 }
337 tab_watcher_->Watch(context.render_process_id, context.render_view_id);
212 } 338 }
213 339
214 void ChromeSpeechRecognitionManagerDelegate::OnAudioStart(int session_id) { 340 void ChromeSpeechRecognitionManagerDelegate::OnAudioStart(int session_id) {
215 if (RequiresBubble(session_id)) { 341 if (RequiresBubble(session_id)) {
216 GetBubbleController()->SetBubbleRecordingMode(session_id); 342 DCHECK_EQ(session_id, GetBubbleController()->GetActiveSessionID());
343 GetBubbleController()->SetBubbleRecordingMode();
217 } else if (RequiresTrayIcon(session_id)) { 344 } else if (RequiresTrayIcon(session_id)) {
218 // We post the action to the UI thread for sessions requiring a tray icon, 345 // We post the action to the UI thread for sessions requiring a tray icon,
219 // since ChromeSpeechRecognitionPreferences (which requires UI thread) is 346 // since ChromeSpeechRecognitionPreferences (which requires UI thread) is
220 // involved for determining whether a security alert balloon is required. 347 // involved for determining whether a security alert balloon is required.
221 const content::SpeechRecognitionSessionContext& context = 348 const content::SpeechRecognitionSessionContext& context =
222 SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id); 349 SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id);
223 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind( 350 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
224 &ChromeSpeechRecognitionManagerDelegate::ShowTrayIconOnUIThread, 351 &ChromeSpeechRecognitionManagerDelegate::ShowTrayIconOnUIThread,
225 context.context_name, 352 context.context_name,
226 context.render_process_id, 353 context.render_process_id,
227 scoped_refptr<SpeechRecognitionTrayIconController>( 354 scoped_refptr<SpeechRecognitionTrayIconController>(
228 GetTrayIconController()))); 355 GetTrayIconController())));
229 } 356 }
230 } 357 }
231 358
232 void ChromeSpeechRecognitionManagerDelegate::OnEnvironmentEstimationComplete( 359 void ChromeSpeechRecognitionManagerDelegate::OnEnvironmentEstimationComplete(
233 int session_id) { 360 int session_id) {
234 } 361 }
235 362
236 void ChromeSpeechRecognitionManagerDelegate::OnSoundStart(int session_id) { 363 void ChromeSpeechRecognitionManagerDelegate::OnSoundStart(int session_id) {
237 } 364 }
238 365
239 void ChromeSpeechRecognitionManagerDelegate::OnSoundEnd(int session_id) { 366 void ChromeSpeechRecognitionManagerDelegate::OnSoundEnd(int session_id) {
240 } 367 }
241 368
242 void ChromeSpeechRecognitionManagerDelegate::OnAudioEnd(int session_id) { 369 void ChromeSpeechRecognitionManagerDelegate::OnAudioEnd(int session_id) {
243 // OnAudioEnd can be also raised after an abort, when the bubble has already 370 // OnAudioEnd can be also raised after an abort, when the bubble has already
244 // been closed. 371 // been closed.
245 if (RequiresBubble(session_id) && active_bubble_session_id_ == session_id) { 372 if (GetBubbleController()->GetActiveSessionID() == session_id) {
246 GetBubbleController()->SetBubbleRecognizingMode(session_id); 373 DCHECK(RequiresBubble(session_id));
374 GetBubbleController()->SetBubbleRecognizingMode();
247 } else if (RequiresTrayIcon(session_id)) { 375 } else if (RequiresTrayIcon(session_id)) {
248 GetTrayIconController()->Hide(); 376 GetTrayIconController()->Hide();
249 } 377 }
250 } 378 }
251 379
252 void ChromeSpeechRecognitionManagerDelegate::OnRecognitionResult( 380 void ChromeSpeechRecognitionManagerDelegate::OnRecognitionResult(
253 int session_id, const content::SpeechRecognitionResult& result) { 381 int session_id, const content::SpeechRecognitionResult& result) {
254 // A result can be dispatched when the bubble is not visible anymore (e.g., 382 // The bubble will be closed upon the OnEnd event, which will follow soon.
255 // lost focus while waiting for a result, thus continuing in background).
256 if (RequiresBubble(session_id) && active_bubble_session_id_ == session_id) {
257 GetBubbleController()->CloseBubble(session_id);
258 last_session_config_.reset();
259 active_bubble_session_id_ = kNoActiveBubble;
260 }
261 } 383 }
262 384
263 void ChromeSpeechRecognitionManagerDelegate::OnRecognitionError( 385 void ChromeSpeechRecognitionManagerDelegate::OnRecognitionError(
264 int session_id, const content::SpeechRecognitionError& error) { 386 int session_id, const content::SpeechRecognitionError& error) {
265 // An error can be dispatched when the bubble is not visible anymore. 387 // An error can be dispatched when the bubble is not visible anymore.
266 if (active_bubble_session_id_ != session_id) 388 if (GetBubbleController()->GetActiveSessionID() != session_id)
267 return; 389 return;
268 DCHECK(RequiresBubble(session_id)); 390 DCHECK(RequiresBubble(session_id));
269 391
270 int error_message_id = 0; 392 int error_message_id = 0;
271 switch (error.code) { 393 switch (error.code) {
272 case content::SPEECH_RECOGNITION_ERROR_AUDIO: 394 case content::SPEECH_RECOGNITION_ERROR_AUDIO:
273 switch (error.details) { 395 switch (error.details) {
274 case content::SPEECH_AUDIO_ERROR_DETAILS_NO_MIC: 396 case content::SPEECH_AUDIO_ERROR_DETAILS_NO_MIC:
275 error_message_id = IDS_SPEECH_INPUT_NO_MIC; 397 error_message_id = IDS_SPEECH_INPUT_NO_MIC;
276 break; 398 break;
(...skipping 15 matching lines...) Expand all
292 error_message_id = IDS_SPEECH_INPUT_NO_RESULTS; 414 error_message_id = IDS_SPEECH_INPUT_NO_RESULTS;
293 break; 415 break;
294 case content::SPEECH_RECOGNITION_ERROR_NETWORK: 416 case content::SPEECH_RECOGNITION_ERROR_NETWORK:
295 error_message_id = IDS_SPEECH_INPUT_NET_ERROR; 417 error_message_id = IDS_SPEECH_INPUT_NET_ERROR;
296 break; 418 break;
297 default: 419 default:
298 NOTREACHED() << "unknown error " << error.code; 420 NOTREACHED() << "unknown error " << error.code;
299 return; 421 return;
300 } 422 }
301 GetBubbleController()->SetBubbleMessage( 423 GetBubbleController()->SetBubbleMessage(
302 session_id, l10n_util::GetStringUTF16(error_message_id)); 424 l10n_util::GetStringUTF16(error_message_id));
303 } 425 }
304 426
305 void ChromeSpeechRecognitionManagerDelegate::OnAudioLevelsChange( 427 void ChromeSpeechRecognitionManagerDelegate::OnAudioLevelsChange(
306 int session_id, float volume, float noise_volume) { 428 int session_id, float volume, float noise_volume) {
307 if (active_bubble_session_id_ == session_id) { 429 if (GetBubbleController()->GetActiveSessionID() == session_id) {
308 DCHECK(RequiresBubble(session_id)); 430 DCHECK(RequiresBubble(session_id));
309 GetBubbleController()->SetBubbleInputVolume(session_id, 431 GetBubbleController()->SetBubbleInputVolume(volume, noise_volume);
310 volume, noise_volume);
311 } else if (RequiresTrayIcon(session_id)) { 432 } else if (RequiresTrayIcon(session_id)) {
312 GetTrayIconController()->SetVUMeterVolume(volume); 433 GetTrayIconController()->SetVUMeterVolume(volume);
313 } 434 }
314 } 435 }
315 436
316 void ChromeSpeechRecognitionManagerDelegate::OnRecognitionEnd(int session_id) { 437 void ChromeSpeechRecognitionManagerDelegate::OnRecognitionEnd(int session_id) {
317 // No need to remove the bubble here, since either one of the following events 438 // The only case in which the OnRecognitionEnd should not close the bubble is
318 // must have happened prior to this callback: 439 // when we are showing an error. In this case the bubble will be closed by
319 // - A previous OnRecognitionResult event already closed the bubble. 440 // the |InfoBubbleFocusChanged| method, when the users clicks either the
320 // - An error occurred, so the bubble is showing the error and will be closed 441 // "Cancel" button or outside of the bubble.
321 // when it will lose focus (by InfoBubbleFocusChanged()). 442 if (GetBubbleController()->GetActiveSessionID() == session_id &&
322 // - The bubble lost focus or the user pressed the Cancel button, thus it has 443 !GetBubbleController()->IsShowingMessage()) {
323 // been closed by InfoBubbleFocusChanged(), which triggered an AbortSession. 444 DCHECK(RequiresBubble(session_id));
445 GetBubbleController()->CloseBubble();
446 }
324 } 447 }
325 448
326 void ChromeSpeechRecognitionManagerDelegate::GetDiagnosticInformation( 449 void ChromeSpeechRecognitionManagerDelegate::GetDiagnosticInformation(
327 bool* can_report_metrics, 450 bool* can_report_metrics,
328 std::string* hardware_info) { 451 std::string* hardware_info) {
329 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 452 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
330 if (!optional_request_info_.get()) { 453 if (!optional_request_info_.get()) {
331 optional_request_info_ = new OptionalRequestInfo(); 454 optional_request_info_ = new OptionalRequestInfo();
332 // Since hardware info is optional with speech input requests, we start an 455 // Since hardware info is optional with speech input requests, we start an
333 // asynchronous fetch here and move on with recording audio. This first 456 // asynchronous fetch here and move on with recording audio. This first
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after
447 570
448 SpeechRecognitionTrayIconController* 571 SpeechRecognitionTrayIconController*
449 ChromeSpeechRecognitionManagerDelegate::GetTrayIconController() { 572 ChromeSpeechRecognitionManagerDelegate::GetTrayIconController() {
450 if (!tray_icon_controller_.get()) 573 if (!tray_icon_controller_.get())
451 tray_icon_controller_ = new SpeechRecognitionTrayIconController(); 574 tray_icon_controller_ = new SpeechRecognitionTrayIconController();
452 return tray_icon_controller_.get(); 575 return tray_icon_controller_.get();
453 } 576 }
454 577
455 578
456 } // namespace speech 579 } // namespace speech
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698