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

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: jochen review 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 <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 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
116 114
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
127 : active_bubble_session_id_(kNoActiveBubble) { 125 ::ChromeSpeechRecognitionManagerDelegate() {
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())
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();
153 } else {
154 NOTREACHED();
160 } 155 }
161 } 156 }
162 157
163 void ChromeSpeechRecognitionManagerDelegate::InfoBubbleFocusChanged( 158 void ChromeSpeechRecognitionManagerDelegate::InfoBubbleFocusChanged(
164 int session_id) { 159 int session_id) {
165 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 160 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
166 DCHECK_EQ(active_bubble_session_id_, session_id); 161
162 // This check is needed since on some systems (MacOS), in rare cases, if the
163 // user clicks repeatedly and fast on the input element, the FocusChanged
164 // event (corresponding to the old session that should be aborted) can be
165 // received after a new session (corresponding to the 2nd click) is started.
166 if (GetBubbleController()->GetActiveSessionID() != session_id)
167 return;
167 168
168 // Note, the session might have been destroyed, therefore avoid calls to the 169 // Note, the session might have been destroyed, therefore avoid calls to the
169 // manager which imply its existance (e.g., GetSessionContext()). 170 // manager which imply its existance (e.g., GetSessionContext()).
170 171 GetBubbleController()->CloseBubble();
171 GetBubbleController()->CloseBubble(session_id);
172 last_session_config_.reset(); 172 last_session_config_.reset();
173 active_bubble_session_id_ = kNoActiveBubble;
174 173
175 // If the user clicks outside the bubble while capturing audio we abort the 174 // 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 175 // session. Otherwise, i.e. audio capture is ended and we are just waiting for
177 // results, this activity is carried silently in background. 176 // results, this activity is carried silently in background.
178 if (SpeechRecognitionManager::GetInstance()->IsCapturingAudio()) 177 if (SpeechRecognitionManager::GetInstance()->IsCapturingAudio())
179 SpeechRecognitionManager::GetInstance()->AbortSession(session_id); 178 SpeechRecognitionManager::GetInstance()->AbortSession(session_id);
180 } 179 }
181 180
182 void ChromeSpeechRecognitionManagerDelegate::RestartLastSession() { 181 void ChromeSpeechRecognitionManagerDelegate::RestartLastSession() {
183 DCHECK(last_session_config_.get()); 182 DCHECK(last_session_config_.get());
184 SpeechRecognitionManager* manager = SpeechRecognitionManager::GetInstance(); 183 SpeechRecognitionManager* manager = SpeechRecognitionManager::GetInstance();
185 const int new_session_id = manager->CreateSession(*last_session_config_); 184 const int new_session_id = manager->CreateSession(*last_session_config_);
186 DCHECK_NE(new_session_id, kNoActiveBubble); 185 DCHECK_NE(SpeechRecognitionManager::kSessionIDInvalid, new_session_id);
187 last_session_config_.reset(); 186 last_session_config_.reset();
188 manager->StartSession(new_session_id); 187 manager->StartSession(new_session_id);
189 } 188 }
190 189
190 void ChromeSpeechRecognitionManagerDelegate::TabClosedCallback(
191 int render_process_id, int render_view_id) {
192 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
193
194 if (SpeechRecognitionManager* manager =
195 SpeechRecognitionManager::GetInstance()) {
196 manager->AbortAllSessionsForRenderView(render_process_id, render_view_id);
197 }
198
199 if (bubble_controller_.get() &&
200 bubble_controller_->IsShowingBubbleForRenderView(render_process_id,
201 render_view_id)) {
202 bubble_controller_->CloseBubble();
203 }
204 }
205
191 void ChromeSpeechRecognitionManagerDelegate::OnRecognitionStart( 206 void ChromeSpeechRecognitionManagerDelegate::OnRecognitionStart(
192 int session_id) { 207 int session_id) {
193 const content::SpeechRecognitionSessionContext& context = 208 const content::SpeechRecognitionSessionContext& context =
194 SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id); 209 SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id);
195 210
196 if (RequiresBubble(session_id)) { 211 if (RequiresBubble(session_id)) {
197 // Copy the configuration of the session (for the "try again" button). 212 // Copy the configuration of the session (for the "try again" button).
198 last_session_config_.reset(new content::SpeechRecognitionSessionConfig( 213 last_session_config_.reset(new content::SpeechRecognitionSessionConfig(
199 SpeechRecognitionManager::GetInstance()->GetSessionConfig(session_id))); 214 SpeechRecognitionManager::GetInstance()->GetSessionConfig(session_id)));
200 215
201 // Create and show the bubble. 216 // 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, 217 GetBubbleController()->CreateBubble(session_id,
205 context.render_process_id, 218 context.render_process_id,
206 context.render_view_id, 219 context.render_view_id,
207 context.element_rect); 220 context.element_rect);
221 }
208 222
209 // TODO(primiano) Why not creating directly the bubble in warmup mode? 223 // Register callback to auto abort session on tab closure.
210 GetBubbleController()->SetBubbleWarmUpMode(session_id); 224 // |tab_watcher_| is lazyly istantiated on the first call.
225 if (!tab_watcher_.get()) {
226 tab_watcher_ = new TabWatcher(
227 base::Bind(&ChromeSpeechRecognitionManagerDelegate::TabClosedCallback,
228 base::Unretained(this)),
229 BrowserThread::IO);
211 } 230 }
231 tab_watcher_->Watch(context.render_process_id, context.render_view_id);
212 } 232 }
213 233
214 void ChromeSpeechRecognitionManagerDelegate::OnAudioStart(int session_id) { 234 void ChromeSpeechRecognitionManagerDelegate::OnAudioStart(int session_id) {
215 if (RequiresBubble(session_id)) { 235 if (RequiresBubble(session_id)) {
216 GetBubbleController()->SetBubbleRecordingMode(session_id); 236 DCHECK_EQ(session_id, GetBubbleController()->GetActiveSessionID());
237 GetBubbleController()->SetBubbleRecordingMode();
217 } else if (RequiresTrayIcon(session_id)) { 238 } else if (RequiresTrayIcon(session_id)) {
218 // We post the action to the UI thread for sessions requiring a tray icon, 239 // We post the action to the UI thread for sessions requiring a tray icon,
219 // since ChromeSpeechRecognitionPreferences (which requires UI thread) is 240 // since ChromeSpeechRecognitionPreferences (which requires UI thread) is
220 // involved for determining whether a security alert balloon is required. 241 // involved for determining whether a security alert balloon is required.
221 const content::SpeechRecognitionSessionContext& context = 242 const content::SpeechRecognitionSessionContext& context =
222 SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id); 243 SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id);
223 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind( 244 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
224 &ChromeSpeechRecognitionManagerDelegate::ShowTrayIconOnUIThread, 245 &ChromeSpeechRecognitionManagerDelegate::ShowTrayIconOnUIThread,
225 context.context_name, 246 context.context_name,
226 context.render_process_id, 247 context.render_process_id,
227 scoped_refptr<SpeechRecognitionTrayIconController>( 248 scoped_refptr<SpeechRecognitionTrayIconController>(
228 GetTrayIconController()))); 249 GetTrayIconController())));
229 } 250 }
230 } 251 }
231 252
232 void ChromeSpeechRecognitionManagerDelegate::OnEnvironmentEstimationComplete( 253 void ChromeSpeechRecognitionManagerDelegate::OnEnvironmentEstimationComplete(
233 int session_id) { 254 int session_id) {
234 } 255 }
235 256
236 void ChromeSpeechRecognitionManagerDelegate::OnSoundStart(int session_id) { 257 void ChromeSpeechRecognitionManagerDelegate::OnSoundStart(int session_id) {
237 } 258 }
238 259
239 void ChromeSpeechRecognitionManagerDelegate::OnSoundEnd(int session_id) { 260 void ChromeSpeechRecognitionManagerDelegate::OnSoundEnd(int session_id) {
240 } 261 }
241 262
242 void ChromeSpeechRecognitionManagerDelegate::OnAudioEnd(int session_id) { 263 void ChromeSpeechRecognitionManagerDelegate::OnAudioEnd(int session_id) {
243 // OnAudioEnd can be also raised after an abort, when the bubble has already 264 // OnAudioEnd can be also raised after an abort, when the bubble has already
244 // been closed. 265 // been closed.
245 if (RequiresBubble(session_id) && active_bubble_session_id_ == session_id) { 266 if (GetBubbleController()->GetActiveSessionID() == session_id) {
246 GetBubbleController()->SetBubbleRecognizingMode(session_id); 267 DCHECK(RequiresBubble(session_id));
268 GetBubbleController()->SetBubbleRecognizingMode();
247 } else if (RequiresTrayIcon(session_id)) { 269 } else if (RequiresTrayIcon(session_id)) {
248 GetTrayIconController()->Hide(); 270 GetTrayIconController()->Hide();
249 } 271 }
250 } 272 }
251 273
252 void ChromeSpeechRecognitionManagerDelegate::OnRecognitionResult( 274 void ChromeSpeechRecognitionManagerDelegate::OnRecognitionResult(
253 int session_id, const content::SpeechRecognitionResult& result) { 275 int session_id, const content::SpeechRecognitionResult& result) {
254 // A result can be dispatched when the bubble is not visible anymore (e.g., 276 // 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 } 277 }
262 278
263 void ChromeSpeechRecognitionManagerDelegate::OnRecognitionError( 279 void ChromeSpeechRecognitionManagerDelegate::OnRecognitionError(
264 int session_id, const content::SpeechRecognitionError& error) { 280 int session_id, const content::SpeechRecognitionError& error) {
265 // An error can be dispatched when the bubble is not visible anymore. 281 // An error can be dispatched when the bubble is not visible anymore.
266 if (active_bubble_session_id_ != session_id) 282 if (GetBubbleController()->GetActiveSessionID() != session_id)
267 return; 283 return;
268 DCHECK(RequiresBubble(session_id)); 284 DCHECK(RequiresBubble(session_id));
269 285
270 int error_message_id = 0; 286 int error_message_id = 0;
271 switch (error.code) { 287 switch (error.code) {
272 case content::SPEECH_RECOGNITION_ERROR_AUDIO: 288 case content::SPEECH_RECOGNITION_ERROR_AUDIO:
273 switch (error.details) { 289 switch (error.details) {
274 case content::SPEECH_AUDIO_ERROR_DETAILS_NO_MIC: 290 case content::SPEECH_AUDIO_ERROR_DETAILS_NO_MIC:
275 error_message_id = IDS_SPEECH_INPUT_NO_MIC; 291 error_message_id = IDS_SPEECH_INPUT_NO_MIC;
276 break; 292 break;
(...skipping 15 matching lines...) Expand all
292 error_message_id = IDS_SPEECH_INPUT_NO_RESULTS; 308 error_message_id = IDS_SPEECH_INPUT_NO_RESULTS;
293 break; 309 break;
294 case content::SPEECH_RECOGNITION_ERROR_NETWORK: 310 case content::SPEECH_RECOGNITION_ERROR_NETWORK:
295 error_message_id = IDS_SPEECH_INPUT_NET_ERROR; 311 error_message_id = IDS_SPEECH_INPUT_NET_ERROR;
296 break; 312 break;
297 default: 313 default:
298 NOTREACHED() << "unknown error " << error.code; 314 NOTREACHED() << "unknown error " << error.code;
299 return; 315 return;
300 } 316 }
301 GetBubbleController()->SetBubbleMessage( 317 GetBubbleController()->SetBubbleMessage(
302 session_id, l10n_util::GetStringUTF16(error_message_id)); 318 l10n_util::GetStringUTF16(error_message_id));
303 } 319 }
304 320
305 void ChromeSpeechRecognitionManagerDelegate::OnAudioLevelsChange( 321 void ChromeSpeechRecognitionManagerDelegate::OnAudioLevelsChange(
306 int session_id, float volume, float noise_volume) { 322 int session_id, float volume, float noise_volume) {
307 if (active_bubble_session_id_ == session_id) { 323 if (GetBubbleController()->GetActiveSessionID() == session_id) {
308 DCHECK(RequiresBubble(session_id)); 324 DCHECK(RequiresBubble(session_id));
309 GetBubbleController()->SetBubbleInputVolume(session_id, 325 GetBubbleController()->SetBubbleInputVolume(volume, noise_volume);
310 volume, noise_volume);
311 } else if (RequiresTrayIcon(session_id)) { 326 } else if (RequiresTrayIcon(session_id)) {
312 GetTrayIconController()->SetVUMeterVolume(volume); 327 GetTrayIconController()->SetVUMeterVolume(volume);
313 } 328 }
314 } 329 }
315 330
316 void ChromeSpeechRecognitionManagerDelegate::OnRecognitionEnd(int session_id) { 331 void ChromeSpeechRecognitionManagerDelegate::OnRecognitionEnd(int session_id) {
317 // No need to remove the bubble here, since either one of the following events 332 // The only case in which the OnRecognitionEnd should not close the bubble is
318 // must have happened prior to this callback: 333 // when we are showing an error. In this case the bubble will be closed by
319 // - A previous OnRecognitionResult event already closed the bubble. 334 // the |InfoBubbleFocusChanged| method, when the users clicks either the
320 // - An error occurred, so the bubble is showing the error and will be closed 335 // "Cancel" button or outside of the bubble.
321 // when it will lose focus (by InfoBubbleFocusChanged()). 336 if (GetBubbleController()->GetActiveSessionID() == session_id &&
322 // - The bubble lost focus or the user pressed the Cancel button, thus it has 337 !GetBubbleController()->IsShowingMessage()) {
323 // been closed by InfoBubbleFocusChanged(), which triggered an AbortSession. 338 DCHECK(RequiresBubble(session_id));
339 GetBubbleController()->CloseBubble();
340 }
324 } 341 }
325 342
326 void ChromeSpeechRecognitionManagerDelegate::GetDiagnosticInformation( 343 void ChromeSpeechRecognitionManagerDelegate::GetDiagnosticInformation(
327 bool* can_report_metrics, 344 bool* can_report_metrics,
328 std::string* hardware_info) { 345 std::string* hardware_info) {
329 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 346 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
330 if (!optional_request_info_.get()) { 347 if (!optional_request_info_.get()) {
331 optional_request_info_ = new OptionalRequestInfo(); 348 optional_request_info_ = new OptionalRequestInfo();
332 // Since hardware info is optional with speech input requests, we start an 349 // Since hardware info is optional with speech input requests, we start an
333 // asynchronous fetch here and move on with recording audio. This first 350 // asynchronous fetch here and move on with recording audio. This first
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after
447 464
448 SpeechRecognitionTrayIconController* 465 SpeechRecognitionTrayIconController*
449 ChromeSpeechRecognitionManagerDelegate::GetTrayIconController() { 466 ChromeSpeechRecognitionManagerDelegate::GetTrayIconController() {
450 if (!tray_icon_controller_.get()) 467 if (!tray_icon_controller_.get())
451 tray_icon_controller_ = new SpeechRecognitionTrayIconController(); 468 tray_icon_controller_ = new SpeechRecognitionTrayIconController();
452 return tray_icon_controller_.get(); 469 return tray_icon_controller_.get();
453 } 470 }
454 471
455 472
456 } // namespace speech 473 } // namespace speech
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698