Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / speech / chrome_speech_recognition_manager_delegate_bubble_ui.cc
blobda18bd4beba74e85c40db740ae7694b814abbf83
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/speech/chrome_speech_recognition_manager_delegate_bubble_ui.h"
7 #include "base/strings/utf_string_conversions.h"
8 #include "content/public/browser/browser_thread.h"
9 #include "content/public/browser/speech_recognition_manager.h"
10 #include "content/public/browser/speech_recognition_session_context.h"
11 #include "content/public/common/speech_recognition_error.h"
12 #include "grit/generated_resources.h"
13 #include "ui/base/l10n/l10n_util.h"
15 using content::BrowserThread;
16 using content::SpeechRecognitionManager;
18 namespace {
20 bool RequiresBubble(int session_id) {
21 return SpeechRecognitionManager::GetInstance()->
22 GetSessionContext(session_id).requested_by_page_element;
25 } // namespace
27 namespace speech {
29 ChromeSpeechRecognitionManagerDelegateBubbleUI
30 ::ChromeSpeechRecognitionManagerDelegateBubbleUI() {
33 ChromeSpeechRecognitionManagerDelegateBubbleUI
34 ::~ChromeSpeechRecognitionManagerDelegateBubbleUI() {
35 if (bubble_controller_.get())
36 bubble_controller_->CloseBubble();
39 void ChromeSpeechRecognitionManagerDelegateBubbleUI::InfoBubbleButtonClicked(
40 int session_id, SpeechRecognitionBubble::Button button) {
41 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
43 // Note, the session might have been destroyed, therefore avoid calls to the
44 // manager which imply its existance (e.g., GetSessionContext()).
46 if (button == SpeechRecognitionBubble::BUTTON_CANCEL) {
47 GetBubbleController()->CloseBubble();
48 last_session_config_.reset();
50 // We can safely call AbortSession even if the session has already ended,
51 // the manager's public methods are reliable and will handle it properly.
52 SpeechRecognitionManager::GetInstance()->AbortSession(session_id);
53 } else if (button == SpeechRecognitionBubble::BUTTON_TRY_AGAIN) {
54 GetBubbleController()->CloseBubble();
55 RestartLastSession();
56 } else {
57 NOTREACHED();
61 void ChromeSpeechRecognitionManagerDelegateBubbleUI::InfoBubbleFocusChanged(
62 int session_id) {
63 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
65 // This check is needed since on some systems (MacOS), in rare cases, if the
66 // user clicks repeatedly and fast on the input element, the FocusChanged
67 // event (corresponding to the old session that should be aborted) can be
68 // received after a new session (corresponding to the 2nd click) is started.
69 if (GetBubbleController()->GetActiveSessionID() != session_id)
70 return;
72 // Note, the session might have been destroyed, therefore avoid calls to the
73 // manager which imply its existance (e.g., GetSessionContext()).
74 GetBubbleController()->CloseBubble();
75 last_session_config_.reset();
77 // Clicking outside the bubble means we should abort.
78 SpeechRecognitionManager::GetInstance()->AbortSession(session_id);
81 void ChromeSpeechRecognitionManagerDelegateBubbleUI::OnRecognitionStart(
82 int session_id) {
83 ChromeSpeechRecognitionManagerDelegate::OnRecognitionStart(session_id);
85 const content::SpeechRecognitionSessionContext& context =
86 SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id);
88 if (RequiresBubble(session_id)) {
89 // Copy the configuration of the session (for the "try again" button).
90 last_session_config_.reset(new content::SpeechRecognitionSessionConfig(
91 SpeechRecognitionManager::GetInstance()->GetSessionConfig(session_id)));
93 // Create and show the bubble. It will be closed upon the OnEnd event.
94 GetBubbleController()->CreateBubble(session_id,
95 context.render_process_id,
96 context.render_view_id,
97 context.element_rect);
101 void ChromeSpeechRecognitionManagerDelegateBubbleUI::OnAudioStart(
102 int session_id) {
103 ChromeSpeechRecognitionManagerDelegate::OnAudioStart(session_id);
105 if (RequiresBubble(session_id)) {
106 DCHECK_EQ(session_id, GetBubbleController()->GetActiveSessionID());
107 GetBubbleController()->SetBubbleRecordingMode();
111 void ChromeSpeechRecognitionManagerDelegateBubbleUI::OnAudioEnd(
112 int session_id) {
113 ChromeSpeechRecognitionManagerDelegate::OnAudioEnd(session_id);
115 // OnAudioEnd can be also raised after an abort, when the bubble has already
116 // been closed.
117 if (GetBubbleController()->GetActiveSessionID() == session_id) {
118 DCHECK(RequiresBubble(session_id));
119 GetBubbleController()->SetBubbleRecognizingMode();
123 void ChromeSpeechRecognitionManagerDelegateBubbleUI::OnRecognitionError(
124 int session_id, const content::SpeechRecognitionError& error) {
125 ChromeSpeechRecognitionManagerDelegate::OnRecognitionError(session_id, error);
127 // An error can be dispatched when the bubble is not visible anymore.
128 if (GetBubbleController()->GetActiveSessionID() != session_id)
129 return;
130 DCHECK(RequiresBubble(session_id));
132 int error_message_id = 0;
133 switch (error.code) {
134 case content::SPEECH_RECOGNITION_ERROR_AUDIO:
135 switch (error.details) {
136 case content::SPEECH_AUDIO_ERROR_DETAILS_NO_MIC:
137 error_message_id = IDS_SPEECH_INPUT_NO_MIC;
138 break;
139 default:
140 error_message_id = IDS_SPEECH_INPUT_MIC_ERROR;
141 break;
143 break;
144 case content::SPEECH_RECOGNITION_ERROR_ABORTED:
145 error_message_id = IDS_SPEECH_INPUT_ABORTED;
146 break;
147 case content::SPEECH_RECOGNITION_ERROR_NO_SPEECH:
148 error_message_id = IDS_SPEECH_INPUT_NO_SPEECH;
149 break;
150 case content::SPEECH_RECOGNITION_ERROR_NO_MATCH:
151 error_message_id = IDS_SPEECH_INPUT_NO_RESULTS;
152 break;
153 case content::SPEECH_RECOGNITION_ERROR_NETWORK:
154 error_message_id = IDS_SPEECH_INPUT_NET_ERROR;
155 break;
156 default:
157 NOTREACHED() << "unknown error " << error.code;
158 return;
160 GetBubbleController()->SetBubbleMessage(
161 l10n_util::GetStringUTF16(error_message_id));
165 void ChromeSpeechRecognitionManagerDelegateBubbleUI::OnAudioLevelsChange(
166 int session_id, float volume, float noise_volume) {
167 ChromeSpeechRecognitionManagerDelegate::OnAudioLevelsChange(
168 session_id, volume, noise_volume);
170 if (GetBubbleController()->GetActiveSessionID() == session_id) {
171 DCHECK(RequiresBubble(session_id));
172 GetBubbleController()->SetBubbleInputVolume(volume, noise_volume);
176 void ChromeSpeechRecognitionManagerDelegateBubbleUI::OnRecognitionEnd(
177 int session_id) {
178 ChromeSpeechRecognitionManagerDelegate::OnRecognitionEnd(session_id);
180 // The only case in which the OnRecognitionEnd should not close the bubble is
181 // when we are showing an error. In this case the bubble will be closed by
182 // the |InfoBubbleFocusChanged| method, when the users clicks either the
183 // "Cancel" button or outside of the bubble.
184 if (GetBubbleController()->GetActiveSessionID() == session_id &&
185 !GetBubbleController()->IsShowingMessage()) {
186 DCHECK(RequiresBubble(session_id));
187 GetBubbleController()->CloseBubble();
191 void ChromeSpeechRecognitionManagerDelegateBubbleUI::TabClosedCallback(
192 int render_process_id, int render_view_id) {
193 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
194 ChromeSpeechRecognitionManagerDelegate::TabClosedCallback(
195 render_process_id, render_view_id);
197 // Avoid instantiating a bubble_controller_ if not needed. Thus, prefer a
198 // checked access to bubble_controller_ to GetBubbleController().
199 if (bubble_controller_.get())
200 bubble_controller_->CloseBubbleForRenderViewOnUIThread(render_process_id,
201 render_view_id);
204 SpeechRecognitionBubbleController*
205 ChromeSpeechRecognitionManagerDelegateBubbleUI::GetBubbleController() {
206 if (!bubble_controller_.get())
207 bubble_controller_ = new SpeechRecognitionBubbleController(this);
208 return bubble_controller_.get();
211 void ChromeSpeechRecognitionManagerDelegateBubbleUI::RestartLastSession() {
212 DCHECK(last_session_config_.get());
213 SpeechRecognitionManager* manager = SpeechRecognitionManager::GetInstance();
214 const int new_session_id = manager->CreateSession(*last_session_config_);
215 DCHECK_NE(SpeechRecognitionManager::kSessionIDInvalid, new_session_id);
216 last_session_config_.reset();
217 manager->StartSession(new_session_id);
220 } // namespace speech