| 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/speech_input_extension_manager.h" | 5 #include "chrome/browser/speech/speech_input_extension_manager.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/json/json_writer.h" | 8 #include "base/json/json_writer.h" |
| 9 #include "base/utf_string_conversions.h" | 9 #include "base/utf_string_conversions.h" |
| 10 #include "base/values.h" | 10 #include "base/values.h" |
| 11 #include "chrome/browser/extensions/extension_event_router.h" | 11 #include "chrome/browser/extensions/extension_event_router.h" |
| 12 #include "chrome/browser/extensions/extension_host.h" |
| 13 #include "chrome/browser/extensions/extension_process_manager.h" |
| 12 #include "chrome/browser/extensions/extension_service.h" | 14 #include "chrome/browser/extensions/extension_service.h" |
| 13 #include "chrome/browser/prefs/pref_service.h" | 15 #include "chrome/browser/extensions/extension_system.h" |
| 14 #include "chrome/browser/profiles/profile.h" | 16 #include "chrome/browser/profiles/profile.h" |
| 15 #include "chrome/browser/profiles/profile_dependency_manager.h" | 17 #include "chrome/browser/profiles/profile_dependency_manager.h" |
| 16 #include "chrome/browser/profiles/profile_keyed_service.h" | 18 #include "chrome/browser/profiles/profile_keyed_service.h" |
| 17 #include "chrome/browser/profiles/profile_keyed_service_factory.h" | 19 #include "chrome/browser/profiles/profile_keyed_service_factory.h" |
| 18 #include "chrome/common/chrome_notification_types.h" | 20 #include "chrome/common/chrome_notification_types.h" |
| 19 #include "chrome/common/extensions/extension.h" | 21 #include "chrome/common/extensions/extension.h" |
| 20 #include "chrome/common/pref_names.h" | |
| 21 #include "content/public/browser/browser_thread.h" | 22 #include "content/public/browser/browser_thread.h" |
| 22 #include "content/public/browser/notification_registrar.h" | 23 #include "content/public/browser/notification_registrar.h" |
| 23 #include "content/public/browser/notification_service.h" | 24 #include "content/public/browser/notification_service.h" |
| 25 #include "content/public/browser/render_process_host.h" |
| 24 #include "content/public/browser/speech_recognition_manager.h" | 26 #include "content/public/browser/speech_recognition_manager.h" |
| 25 #include "content/public/browser/speech_recognition_session_config.h" | 27 #include "content/public/browser/speech_recognition_session_config.h" |
| 26 #include "content/public/browser/speech_recognition_session_context.h" | 28 #include "content/public/browser/speech_recognition_session_context.h" |
| 27 #include "content/public/common/speech_recognition_error.h" | 29 #include "content/public/common/speech_recognition_error.h" |
| 28 #include "content/public/common/speech_recognition_result.h" | 30 #include "content/public/common/speech_recognition_result.h" |
| 29 #include "net/url_request/url_request_context_getter.h" | 31 #include "net/url_request/url_request_context_getter.h" |
| 30 | 32 |
| 31 using content::BrowserThread; | 33 using content::BrowserThread; |
| 32 using content::SpeechRecognitionHypothesis; | 34 using content::SpeechRecognitionHypothesis; |
| 33 using content::SpeechRecognitionManager; | 35 using content::SpeechRecognitionManager; |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 88 | 90 |
| 89 private: | 91 private: |
| 90 friend struct DefaultSingletonTraits<Factory>; | 92 friend struct DefaultSingletonTraits<Factory>; |
| 91 | 93 |
| 92 Factory(); | 94 Factory(); |
| 93 virtual ~Factory(); | 95 virtual ~Factory(); |
| 94 | 96 |
| 95 // ProfileKeyedServiceFactory methods: | 97 // ProfileKeyedServiceFactory methods: |
| 96 virtual ProfileKeyedService* BuildServiceInstanceFor( | 98 virtual ProfileKeyedService* BuildServiceInstanceFor( |
| 97 Profile* profile) const OVERRIDE; | 99 Profile* profile) const OVERRIDE; |
| 98 virtual void RegisterUserPrefs(PrefService* prefs) OVERRIDE; | |
| 99 virtual bool ServiceRedirectedInIncognito() OVERRIDE { return false; } | 100 virtual bool ServiceRedirectedInIncognito() OVERRIDE { return false; } |
| 100 virtual bool ServiceIsNULLWhileTesting() OVERRIDE { return true; } | 101 virtual bool ServiceIsNULLWhileTesting() OVERRIDE { return true; } |
| 101 virtual bool ServiceIsCreatedWithProfile() OVERRIDE { return true; } | 102 virtual bool ServiceIsCreatedWithProfile() OVERRIDE { return true; } |
| 102 | 103 |
| 103 DISALLOW_COPY_AND_ASSIGN(Factory); | 104 DISALLOW_COPY_AND_ASSIGN(Factory); |
| 104 }; | 105 }; |
| 105 | 106 |
| 106 void SpeechInputExtensionManager::Factory::Initialize() { | 107 void SpeechInputExtensionManager::Factory::Initialize() { |
| 107 GetInstance(); | 108 GetInstance(); |
| 108 } | 109 } |
| (...skipping 19 matching lines...) Expand all Loading... |
| 128 } | 129 } |
| 129 | 130 |
| 130 ProfileKeyedService* | 131 ProfileKeyedService* |
| 131 SpeechInputExtensionManager::Factory::BuildServiceInstanceFor( | 132 SpeechInputExtensionManager::Factory::BuildServiceInstanceFor( |
| 132 Profile* profile) const { | 133 Profile* profile) const { |
| 133 scoped_refptr<SpeechInputExtensionManager> manager( | 134 scoped_refptr<SpeechInputExtensionManager> manager( |
| 134 new SpeechInputExtensionManager(profile)); | 135 new SpeechInputExtensionManager(profile)); |
| 135 return new SpeechInputExtensionManagerWrapper(manager); | 136 return new SpeechInputExtensionManagerWrapper(manager); |
| 136 } | 137 } |
| 137 | 138 |
| 138 void SpeechInputExtensionManager::Factory::RegisterUserPrefs( | |
| 139 PrefService* prefs) { | |
| 140 prefs->RegisterBooleanPref(prefs::kSpeechInputTrayNotificationShown, | |
| 141 false, | |
| 142 PrefService::UNSYNCABLE_PREF); | |
| 143 } | |
| 144 | |
| 145 SpeechInputExtensionInterface::SpeechInputExtensionInterface() { | 139 SpeechInputExtensionInterface::SpeechInputExtensionInterface() { |
| 146 } | 140 } |
| 147 | 141 |
| 148 SpeechInputExtensionInterface::~SpeechInputExtensionInterface() { | 142 SpeechInputExtensionInterface::~SpeechInputExtensionInterface() { |
| 149 } | 143 } |
| 150 | 144 |
| 151 SpeechInputExtensionManager::SpeechInputExtensionManager(Profile* profile) | 145 SpeechInputExtensionManager::SpeechInputExtensionManager(Profile* profile) |
| 152 : profile_(profile), | 146 : profile_(profile), |
| 153 state_(kIdle), | 147 state_(kIdle), |
| 154 registrar_(new content::NotificationRegistrar), | 148 registrar_(new content::NotificationRegistrar), |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 234 VLOG(1) << "Extension unloaded. Requesting to enforce stop..."; | 228 VLOG(1) << "Extension unloaded. Requesting to enforce stop..."; |
| 235 if (extension_id_in_use_ == extension_id) { | 229 if (extension_id_in_use_ == extension_id) { |
| 236 if (state_ != kIdle) { | 230 if (state_ != kIdle) { |
| 237 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | 231 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
| 238 base::Bind(&SpeechInputExtensionManager::ForceStopOnIOThread, this)); | 232 base::Bind(&SpeechInputExtensionManager::ForceStopOnIOThread, this)); |
| 239 } | 233 } |
| 240 } | 234 } |
| 241 } | 235 } |
| 242 | 236 |
| 243 void SpeechInputExtensionManager::SetSpeechInputExtensionInterface( | 237 void SpeechInputExtensionManager::SetSpeechInputExtensionInterface( |
| 244 SpeechInputExtensionInterface* interface) { | 238 SpeechInputExtensionInterface* speech_interface) { |
| 245 speech_interface_ = interface; | 239 speech_interface_ = speech_interface; |
| 246 } | 240 } |
| 247 | 241 |
| 248 SpeechInputExtensionInterface* | 242 SpeechInputExtensionInterface* |
| 249 SpeechInputExtensionManager::GetSpeechInputExtensionInterface() { | 243 SpeechInputExtensionManager::GetSpeechInputExtensionInterface() { |
| 250 return speech_interface_ ? speech_interface_ : this; | 244 return speech_interface_ ? speech_interface_ : this; |
| 251 } | 245 } |
| 252 | 246 |
| 253 void SpeechInputExtensionManager::ResetToIdleState() { | 247 void SpeechInputExtensionManager::ResetToIdleState() { |
| 254 VLOG(1) << "State changed to idle. Deassociating any extensions."; | 248 VLOG(1) << "State changed to idle. Deassociating any extensions."; |
| 255 state_ = kIdle; | 249 state_ = kIdle; |
| 256 extension_id_in_use_.clear(); | 250 extension_id_in_use_.clear(); |
| 257 } | 251 } |
| 258 | 252 |
| 253 int SpeechInputExtensionManager::GetRenderProcessIDForExtension( |
| 254 const std::string& extension_id) const { |
| 255 ExtensionProcessManager* epm = |
| 256 ExtensionSystem::Get(profile_)->process_manager(); |
| 257 DCHECK(epm); |
| 258 ExtensionHost* eh = epm->GetBackgroundHostForExtension(extension_id); |
| 259 DCHECK(eh); |
| 260 content::RenderProcessHost* rph = eh->render_process_host(); |
| 261 DCHECK(rph); |
| 262 return rph->GetID(); |
| 263 } |
| 264 |
| 259 void SpeechInputExtensionManager::OnRecognitionResult( | 265 void SpeechInputExtensionManager::OnRecognitionResult( |
| 260 int session_id, | 266 int session_id, |
| 261 const content::SpeechRecognitionResult& result) { | 267 const content::SpeechRecognitionResult& result) { |
| 262 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 268 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 263 DCHECK_EQ(session_id, speech_recognition_session_id_); | 269 DCHECK_EQ(session_id, speech_recognition_session_id_); |
| 264 | 270 |
| 265 // Stopping will start the disassociation with the extension. | 271 // Stopping will start the disassociation with the extension. |
| 266 // Make a copy to report the results to the proper one. | 272 // Make a copy to report the results to the proper one. |
| 267 std::string extension_id = extension_id_in_use_; | 273 std::string extension_id = extension_id_in_use_; |
| 268 ForceStopOnIOThread(); | 274 ForceStopOnIOThread(); |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 334 | 340 |
| 335 base::AutoLock auto_lock(state_lock_); | 341 base::AutoLock auto_lock(state_lock_); |
| 336 if (state_ == kShutdown) | 342 if (state_ == kShutdown) |
| 337 return; | 343 return; |
| 338 | 344 |
| 339 DCHECK_EQ(state_, kStarting); | 345 DCHECK_EQ(state_, kStarting); |
| 340 VLOG(1) << "State changed to recording"; | 346 VLOG(1) << "State changed to recording"; |
| 341 state_ = kRecording; | 347 state_ = kRecording; |
| 342 | 348 |
| 343 DCHECK(profile_); | 349 DCHECK(profile_); |
| 344 profile_->GetPrefs()->SetBoolean( | |
| 345 prefs::kSpeechInputTrayNotificationShown, true); | |
| 346 | 350 |
| 347 VLOG(1) << "Sending start notification"; | 351 VLOG(1) << "Sending start notification"; |
| 348 content::NotificationService::current()->Notify( | 352 content::NotificationService::current()->Notify( |
| 349 chrome::NOTIFICATION_EXTENSION_SPEECH_INPUT_RECORDING_STARTED, | 353 chrome::NOTIFICATION_EXTENSION_SPEECH_INPUT_RECORDING_STARTED, |
| 350 content::Source<Profile>(profile_), | 354 content::Source<Profile>(profile_), |
| 351 content::Details<std::string>(&extension_id_in_use_)); | 355 content::Details<std::string>(&extension_id_in_use_)); |
| 352 } | 356 } |
| 353 | 357 |
| 354 void SpeechInputExtensionManager::OnRecognitionError( | 358 void SpeechInputExtensionManager::OnRecognitionError( |
| 355 int session_id, const content::SpeechRecognitionError& error) { | 359 int session_id, const content::SpeechRecognitionError& error) { |
| (...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 531 *error = kErrorInvalidOperation; | 535 *error = kErrorInvalidOperation; |
| 532 return false; | 536 return false; |
| 533 | 537 |
| 534 default: | 538 default: |
| 535 NOTREACHED(); | 539 NOTREACHED(); |
| 536 } | 540 } |
| 537 | 541 |
| 538 const extensions::Extension* extension = profile_->GetExtensionService()-> | 542 const extensions::Extension* extension = profile_->GetExtensionService()-> |
| 539 GetExtensionById(extension_id, true); | 543 GetExtensionById(extension_id, true); |
| 540 DCHECK(extension); | 544 DCHECK(extension); |
| 541 const string16& extension_name = UTF8ToUTF16(extension->name()); | 545 const std::string& extension_name = extension->name(); |
| 542 | 546 |
| 543 extension_id_in_use_ = extension_id; | 547 extension_id_in_use_ = extension_id; |
| 544 VLOG(1) << "State changed to starting"; | 548 VLOG(1) << "State changed to starting"; |
| 545 state_ = kStarting; | 549 state_ = kStarting; |
| 546 | 550 |
| 547 // Checks if the security notification balloon has been already shown (only | |
| 548 // once for a profile). It is reset on DidStartReceivingAudioOnUIThread. | |
| 549 scoped_refptr<net::URLRequestContextGetter> url_request_context_getter = | 551 scoped_refptr<net::URLRequestContextGetter> url_request_context_getter = |
| 550 profile_->GetRequestContext(); | 552 profile_->GetRequestContext(); |
| 551 const bool show_notification = !profile_->GetPrefs()->GetBoolean( | 553 |
| 552 prefs::kSpeechInputTrayNotificationShown); | 554 const int render_process_id = GetRenderProcessIDForExtension(extension_id); |
| 553 | 555 |
| 554 BrowserThread::PostTask( | 556 BrowserThread::PostTask( |
| 555 BrowserThread::IO, FROM_HERE, | 557 BrowserThread::IO, FROM_HERE, |
| 556 base::Bind(&SpeechInputExtensionManager::StartOnIOThread, this, | 558 base::Bind(&SpeechInputExtensionManager::StartOnIOThread, this, |
| 557 url_request_context_getter, extension_name, language, grammar, | 559 url_request_context_getter, extension_name, language, grammar, |
| 558 filter_profanities, show_notification)); | 560 filter_profanities, render_process_id)); |
| 559 return true; | 561 return true; |
| 560 } | 562 } |
| 561 | 563 |
| 562 void SpeechInputExtensionManager::StartOnIOThread( | 564 void SpeechInputExtensionManager::StartOnIOThread( |
| 563 scoped_refptr<net::URLRequestContextGetter> context_getter, | 565 scoped_refptr<net::URLRequestContextGetter> context_getter, |
| 564 const string16& extension_name, | 566 const std::string& extension_name, |
| 565 const std::string& language, | 567 const std::string& language, |
| 566 const std::string& grammar, | 568 const std::string& grammar, |
| 567 bool filter_profanities, | 569 bool filter_profanities, |
| 568 bool show_notification) { | 570 int render_process_id) { |
| 569 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 571 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 570 VLOG(1) << "Requesting start (IO thread)"; | 572 VLOG(1) << "Requesting start (IO thread)"; |
| 571 | 573 |
| 572 // Everything put inside the lock to ensure the validity of context_getter, | 574 // Everything put inside the lock to ensure the validity of context_getter, |
| 573 // guaranteed while not in the shutdown state. Any ongoing or recognition | 575 // guaranteed while not in the shutdown state. Any ongoing or recognition |
| 574 // request will be requested to be aborted when entering the shutdown state. | 576 // request will be requested to be aborted when entering the shutdown state. |
| 575 base::AutoLock auto_lock(state_lock_); | 577 base::AutoLock auto_lock(state_lock_); |
| 576 if (state_ == kShutdown) | 578 if (state_ == kShutdown) |
| 577 return; | 579 return; |
| 578 | 580 |
| (...skipping 17 matching lines...) Expand all Loading... |
| 596 std::string(kErrorRecordingDeviceInUse), false)); | 598 std::string(kErrorRecordingDeviceInUse), false)); |
| 597 return; | 599 return; |
| 598 } | 600 } |
| 599 | 601 |
| 600 GetSpeechInputExtensionInterface()->StartRecording(this, | 602 GetSpeechInputExtensionInterface()->StartRecording(this, |
| 601 context_getter, | 603 context_getter, |
| 602 extension_name, | 604 extension_name, |
| 603 language, | 605 language, |
| 604 grammar, | 606 grammar, |
| 605 filter_profanities, | 607 filter_profanities, |
| 606 show_notification); | 608 render_process_id); |
| 607 } | 609 } |
| 608 | 610 |
| 609 bool SpeechInputExtensionManager::HasAudioInputDevices() { | 611 bool SpeechInputExtensionManager::HasAudioInputDevices() { |
| 610 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 612 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 611 return SpeechRecognitionManager::GetInstance()->HasAudioInputDevices(); | 613 return SpeechRecognitionManager::GetInstance()->HasAudioInputDevices(); |
| 612 } | 614 } |
| 613 | 615 |
| 614 bool SpeechInputExtensionManager::IsCapturingAudio() { | 616 bool SpeechInputExtensionManager::IsCapturingAudio() { |
| 615 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 617 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 616 return SpeechRecognitionManager::GetInstance()->IsCapturingAudio(); | 618 return SpeechRecognitionManager::GetInstance()->IsCapturingAudio(); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 640 void SpeechInputExtensionManager::IsRecordingOnUIThread( | 642 void SpeechInputExtensionManager::IsRecordingOnUIThread( |
| 641 const IsRecordingCallback& callback, | 643 const IsRecordingCallback& callback, |
| 642 bool result) { | 644 bool result) { |
| 643 BrowserThread::CurrentlyOn(BrowserThread::UI); | 645 BrowserThread::CurrentlyOn(BrowserThread::UI); |
| 644 callback.Run(result); | 646 callback.Run(result); |
| 645 } | 647 } |
| 646 | 648 |
| 647 void SpeechInputExtensionManager::StartRecording( | 649 void SpeechInputExtensionManager::StartRecording( |
| 648 content::SpeechRecognitionEventListener* listener, | 650 content::SpeechRecognitionEventListener* listener, |
| 649 net::URLRequestContextGetter* context_getter, | 651 net::URLRequestContextGetter* context_getter, |
| 650 const string16& extension_name, | 652 const std::string& extension_name, |
| 651 const std::string& language, | 653 const std::string& language, |
| 652 const std::string& grammar, | 654 const std::string& grammar, |
| 653 bool filter_profanities, | 655 bool filter_profanities, |
| 654 bool show_notification) { | 656 int render_process_id) { |
| 655 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 657 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 656 | 658 |
| 657 content::SpeechRecognitionSessionContext context; | 659 content::SpeechRecognitionSessionContext context; |
| 658 context.requested_by_page_element = false; | 660 context.requested_by_page_element = false; |
| 659 context.is_first_request_for_context = show_notification; | 661 context.render_process_id = render_process_id; |
| 660 context.context_name = extension_name; | 662 context.context_name = extension_name; |
| 661 | 663 |
| 662 content::SpeechRecognitionSessionConfig config; | 664 content::SpeechRecognitionSessionConfig config; |
| 663 // config.is_one_shot = true; // TODO(primiano) Uncomment when CL2.0 lands. | 665 // config.is_one_shot = true; // TODO(primiano) Uncomment when CL2.0 lands. |
| 664 config.language = language; | 666 config.language = language; |
| 665 config.grammars.push_back(content::SpeechRecognitionGrammar(grammar)); | 667 config.grammars.push_back(content::SpeechRecognitionGrammar(grammar)); |
| 666 config.initial_context = context; | 668 config.initial_context = context; |
| 667 config.url_request_context_getter = context_getter; | 669 config.url_request_context_getter = context_getter; |
| 668 config.filter_profanities = filter_profanities; | 670 config.filter_profanities = filter_profanities; |
| 669 config.event_listener = listener; | 671 config.event_listener = listener; |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 765 content::NotificationService::current()->Notify( | 767 content::NotificationService::current()->Notify( |
| 766 chrome::NOTIFICATION_EXTENSION_SPEECH_INPUT_RECORDING_STOPPED, | 768 chrome::NOTIFICATION_EXTENSION_SPEECH_INPUT_RECORDING_STOPPED, |
| 767 // Guarded by the state_ == kShutdown check. | 769 // Guarded by the state_ == kShutdown check. |
| 768 content::Source<Profile>(profile_), | 770 content::Source<Profile>(profile_), |
| 769 content::Details<std::string>(&extension_id)); | 771 content::Details<std::string>(&extension_id)); |
| 770 } | 772 } |
| 771 | 773 |
| 772 void SpeechInputExtensionManager::OnAudioLevelsChange(int session_id, | 774 void SpeechInputExtensionManager::OnAudioLevelsChange(int session_id, |
| 773 float volume, | 775 float volume, |
| 774 float noise_volume) {} | 776 float noise_volume) {} |
| OLD | NEW |