diff options
author | satish@chromium.org <satish@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-08-27 11:59:03 +0000 |
---|---|---|
committer | satish@chromium.org <satish@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-08-27 11:59:03 +0000 |
commit | 6a7746dbcef8cfcef182887a337eb297d476f98e (patch) | |
tree | 2ef8870775cd910bc965bbd98b3a01c5627d67ec /chrome/browser/speech | |
parent | 32a99f81432bcc1a8ee515b34e6dfdf81c3fa090 (diff) | |
download | chromium_src-6a7746dbcef8cfcef182887a337eb297d476f98e.zip chromium_src-6a7746dbcef8cfcef182887a337eb297d476f98e.tar.gz chromium_src-6a7746dbcef8cfcef182887a337eb297d476f98e.tar.bz2 |
Displays a speech input UI bubble during speech recognition.
The webkit code passes in display rect of the input element requesting speech input
and we create a UI bubble pointing at this element when starting speech input. The
user can click outside the bubble to close it, which aborts recognition if we were
still recording audio. The user can also click the cancel link in the bubble which
aborts recognition irrespective of what state it is in now.
Added a SpeechInputBubbleController class to take care of marshalling the requests
between the speech input code in IO thread and the UI bubble in the UI thread. Also
added a unit test for this class.
BUG=none
TEST=unit_tests --gtest_filter=SpeechInputBubbleControllerTest.*
Review URL: http://codereview.chromium.org/3156048
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@57666 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/speech')
-rw-r--r-- | chrome/browser/speech/speech_input_browsertest.cc | 6 | ||||
-rw-r--r-- | chrome/browser/speech/speech_input_bubble.cc | 27 | ||||
-rw-r--r-- | chrome/browser/speech/speech_input_bubble.h | 27 | ||||
-rw-r--r-- | chrome/browser/speech/speech_input_bubble_controller.cc | 108 | ||||
-rw-r--r-- | chrome/browser/speech/speech_input_bubble_controller.h | 81 | ||||
-rw-r--r-- | chrome/browser/speech/speech_input_bubble_controller_unittest.cc | 131 | ||||
-rw-r--r-- | chrome/browser/speech/speech_input_dispatcher_host.cc | 10 | ||||
-rw-r--r-- | chrome/browser/speech/speech_input_dispatcher_host.h | 3 | ||||
-rw-r--r-- | chrome/browser/speech/speech_input_manager.cc | 54 | ||||
-rw-r--r-- | chrome/browser/speech/speech_input_manager.h | 12 |
10 files changed, 447 insertions, 12 deletions
diff --git a/chrome/browser/speech/speech_input_browsertest.cc b/chrome/browser/speech/speech_input_browsertest.cc index 8c5bc6d..dea65d6 100644 --- a/chrome/browser/speech/speech_input_browsertest.cc +++ b/chrome/browser/speech/speech_input_browsertest.cc @@ -35,7 +35,11 @@ class FakeSpeechInputManager : public SpeechInputManager { } // SpeechInputManager methods. - void StartRecognition(Delegate* delegate, int caller_id) { + void StartRecognition(Delegate* delegate, + int caller_id, + int render_process_id, + int render_view_id, + const gfx::Rect& element_rect) { EXPECT_EQ(0, caller_id_); EXPECT_EQ(NULL, delegate_); caller_id_ = caller_id; diff --git a/chrome/browser/speech/speech_input_bubble.cc b/chrome/browser/speech/speech_input_bubble.cc new file mode 100644 index 0000000..8df9d7d --- /dev/null +++ b/chrome/browser/speech/speech_input_bubble.cc @@ -0,0 +1,27 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/tab_contents/tab_contents.h" +#include "chrome/browser/speech/speech_input_bubble.h" +#include "gfx/rect.h" + +SpeechInputBubble::FactoryMethod SpeechInputBubble::factory_ = NULL; + +SpeechInputBubble* SpeechInputBubble::Create(TabContents* tab_contents, + Delegate* delegate, + const gfx::Rect& element_rect) { + if (factory_) + return (*factory_)(tab_contents, delegate, element_rect); + + // Has the tab already closed before bubble create request was processed? + if (!tab_contents) + return NULL; + +#if defined(OS_WIN) + return CreateNativeBubble(tab_contents, delegate, element_rect); +#else + // TODO(satish): Remove once the Mac and Linux implementations are ready. + return NULL; +#endif +} diff --git a/chrome/browser/speech/speech_input_bubble.h b/chrome/browser/speech/speech_input_bubble.h index 4ddab1b..b3b010f 100644 --- a/chrome/browser/speech/speech_input_bubble.h +++ b/chrome/browser/speech/speech_input_bubble.h @@ -6,8 +6,9 @@ #define CHROME_BROWSER_SPEECH_SPEECH_INPUT_BUBBLE_H_ #pragma once -#include "gfx/rect.h" - +namespace gfx { +class Rect; +} class TabContents; // SpeechInputBubble displays a popup info bubble during speech recognition, @@ -43,10 +44,32 @@ class SpeechInputBubble { static SpeechInputBubble* Create(TabContents* tab_contents, Delegate* delegate, const gfx::Rect& element_rect); + + // This is implemented by platform specific code to create the underlying + // bubble window. Not to be called directly by users of this class. + static SpeechInputBubble* CreateNativeBubble(TabContents* tab_contents, + Delegate* delegate, + const gfx::Rect& element_rect); + + // |Create| uses the currently registered FactoryMethod to create the
+ // SpeechInputBubble instances. FactoryMethod is intended for testing. + typedef SpeechInputBubble* (*FactoryMethod)(TabContents*, + Delegate*, + const gfx::Rect&); + // Sets the factory used by the static method Create. SpeechInputBubble does
+ // not take ownership of |factory|. A value of NULL results in a
+ // SpeechInputBubble being created directly.
+#if defined(UNIT_TEST)
+ static void set_factory(FactoryMethod factory) { factory_ = factory; } +#endif + virtual ~SpeechInputBubble() {} // Indicates to the user that recognition is in progress. virtual void SetRecognizingMode() = 0; + + private: + static FactoryMethod factory_; }; // This typedef is to workaround the issue with certain versions of diff --git a/chrome/browser/speech/speech_input_bubble_controller.cc b/chrome/browser/speech/speech_input_bubble_controller.cc new file mode 100644 index 0000000..98bf620 --- /dev/null +++ b/chrome/browser/speech/speech_input_bubble_controller.cc @@ -0,0 +1,108 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/speech/speech_input_bubble_controller.h" + +#include "chrome/browser/chrome_thread.h" +#include "chrome/browser/tab_contents/tab_contents.h" +#include "chrome/browser/tab_contents/tab_util.h" +#include "gfx/rect.h" + +namespace speech_input { + +SpeechInputBubbleController::SpeechInputBubbleController(Delegate* delegate) + : delegate_(delegate) { +} + +void SpeechInputBubbleController::CreateBubble(int caller_id, + int render_process_id, + int render_view_id, + const gfx::Rect& element_rect) { + if (!ChromeThread::CurrentlyOn(ChromeThread::UI)) { + ChromeThread::PostTask( + ChromeThread::UI, FROM_HERE, + NewRunnableMethod(this, &SpeechInputBubbleController::CreateBubble, + caller_id, render_process_id, render_view_id, + element_rect)); + return; + } + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); + TabContents* tab_contents = tab_util::GetTabContentsByID(render_process_id, + render_view_id); + + DCHECK(!bubble_.get()); + bubble_.reset(SpeechInputBubble::Create(tab_contents, this, element_rect)); + if (!bubble_.get()) // could be null if tab or display rect were invalid. + return; + + current_bubble_caller_id_ = caller_id; +} + +void SpeechInputBubbleController::CloseBubble(int caller_id) { + if (!ChromeThread::CurrentlyOn(ChromeThread::UI)) { + ChromeThread::PostTask( + ChromeThread::UI, FROM_HERE, + NewRunnableMethod(this, &SpeechInputBubbleController::CloseBubble, + caller_id)); + return; + } + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); + if (current_bubble_caller_id_ != caller_id) + return; + + current_bubble_caller_id_ = 0; + + DCHECK(bubble_.get()); + bubble_.reset(); +} + +void SpeechInputBubbleController::SetBubbleToRecognizingMode(int caller_id) { + if (!ChromeThread::CurrentlyOn(ChromeThread::UI)) { + ChromeThread::PostTask(ChromeThread::UI, FROM_HERE, NewRunnableMethod( + this, &SpeechInputBubbleController::SetBubbleToRecognizingMode, + caller_id)); + return; + } + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); + if (current_bubble_caller_id_ != caller_id) + return; + + DCHECK(bubble_.get()); + bubble_->SetRecognizingMode(); +} + +void SpeechInputBubbleController::RecognitionCancelled() { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); + ChromeThread::PostTask( + ChromeThread::IO, FROM_HERE, + NewRunnableMethod( + this, + &SpeechInputBubbleController::InvokeDelegateRecognitionCancelled, + current_bubble_caller_id_)); + current_bubble_caller_id_ = 0; + bubble_.reset(); +} + +void SpeechInputBubbleController::InfoBubbleClosed() { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); + ChromeThread::PostTask( + ChromeThread::IO, FROM_HERE, + NewRunnableMethod( + this, + &SpeechInputBubbleController::InvokeDelegateFocusChanged, + current_bubble_caller_id_)); + current_bubble_caller_id_ = 0; + bubble_.reset(); +} + +void SpeechInputBubbleController::InvokeDelegateRecognitionCancelled( + int caller_id) { + delegate_->RecognitionCancelled(caller_id); +} + +void SpeechInputBubbleController::InvokeDelegateFocusChanged(int caller_id) { + delegate_->SpeechInputFocusChanged(caller_id); +} + +} // namespace speech_input diff --git a/chrome/browser/speech/speech_input_bubble_controller.h b/chrome/browser/speech/speech_input_bubble_controller.h new file mode 100644 index 0000000..6bd3d6a --- /dev/null +++ b/chrome/browser/speech/speech_input_bubble_controller.h @@ -0,0 +1,81 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_SPEECH_SPEECH_INPUT_BUBBLE_CONTROLLER_H_ +#define CHROME_BROWSER_SPEECH_SPEECH_INPUT_BUBBLE_CONTROLLER_H_ + +#include "base/basictypes.h" +#include "base/ref_counted.h" +#include "base/scoped_ptr.h" +#include "chrome/browser/speech/speech_input_bubble.h" + +namespace gfx { +class Rect; +} + +namespace speech_input { + +// This class handles the speech input popup UI on behalf of SpeechInputManager. +// SpeechInputManager invokes methods in the IO thread and this class processes +// those requests in the UI thread. There is only 1 speech input bubble shown to +// the user at a time. User actions on that bubble are reported to the delegate. +class SpeechInputBubbleController + : public base::RefCountedThreadSafe<SpeechInputBubbleController>, + public SpeechInputBubbleDelegate { + public: + // All methods of this delegate are called in the IO thread. + class Delegate { + public: + // Invoked when the user cancels speech recognition by clicking on the + // cancel button or related action in the speech input UI. + virtual void RecognitionCancelled(int caller_id) = 0; + + // Invoked when the user clicks outside the speech input info bubble causing + // it to close and input focus to change. + virtual void SpeechInputFocusChanged(int caller_id) = 0; + + protected: + virtual ~Delegate() {} + }; + + explicit SpeechInputBubbleController(Delegate* delegate); + + // Creates a new speech input bubble and displays it in the UI. + void CreateBubble(int caller_id, + int render_process_id, + int render_view_id, + const gfx::Rect& element_rect); + + // Sets the bubble to show that recording completed and recognition is in + // progress. + void SetBubbleToRecognizingMode(int caller_id); + + void CloseBubble(int caller_id); + + // SpeechInputBubble::Delegate methods. + virtual void RecognitionCancelled(); + virtual void InfoBubbleClosed(); + + private: + void InvokeDelegateRecognitionCancelled(int caller_id); + void InvokeDelegateFocusChanged(int caller_id); + + // Only accessed in the IO thread. + Delegate* delegate_; + + // Only accessed in the UI thread. + int current_bubble_caller_id_; + scoped_ptr<SpeechInputBubble> bubble_; +}; + +// This typedef is to workaround the issue with certain versions of +// Visual Studio where it gets confused between multiple Delegate +// classes and gives a C2500 error. (I saw this error on the try bots - +// the workaround was not needed for my machine). +typedef SpeechInputBubbleController::Delegate + SpeechInputBubbleControllerDelegate; + +} // namespace speech_input + +#endif // CHROME_BROWSER_SPEECH_SPEECH_INPUT_BUBBLE_CONTROLLER_H_ diff --git a/chrome/browser/speech/speech_input_bubble_controller_unittest.cc b/chrome/browser/speech/speech_input_bubble_controller_unittest.cc new file mode 100644 index 0000000..c8ac5f6 --- /dev/null +++ b/chrome/browser/speech/speech_input_bubble_controller_unittest.cc @@ -0,0 +1,131 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/chrome_thread.h" +#include "chrome/browser/speech/speech_input_bubble_controller.h" +#include "gfx/rect.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace speech_input { + +// A mock bubble class which fakes a focus change or recognition cancel by the +// user and closing of the info bubble. +class MockSpeechInputBubble : public SpeechInputBubble { + public: + enum BubbleType { + BUBBLE_TEST_FOCUS_CHANGED, + BUBBLE_TEST_RECOGNITION_CANCELLED + }; + + MockSpeechInputBubble(TabContents*, Delegate* delegate, const gfx::Rect&) { + MessageLoop::current()->PostTask( + FROM_HERE, NewRunnableFunction(&InvokeDelegate, delegate)); + } + + static void InvokeDelegate(Delegate* delegate) { + if (type_ == BUBBLE_TEST_FOCUS_CHANGED) + delegate->InfoBubbleClosed(); + else + delegate->RecognitionCancelled(); + } + + static void set_type(BubbleType type) { + type_ = type; + } + + virtual void SetRecognizingMode() {} + + private: + static BubbleType type_; +}; + +// The test fixture. +class SpeechInputBubbleControllerTest + : public SpeechInputBubbleControllerDelegate, + public testing::Test { + public: + SpeechInputBubbleControllerTest() + : io_loop_(MessageLoop::TYPE_IO), + ui_thread_(ChromeThread::UI), // constructs a new thread and loop + io_thread_(ChromeThread::IO, &io_loop_), // resuses main thread loop + recognition_cancelled_(false), + focus_changed_(false) { + } + + // SpeechInputBubbleControllerDelegate methods. + virtual void RecognitionCancelled(int caller_id) { + EXPECT_TRUE(ChromeThread::CurrentlyOn(ChromeThread::IO)); + recognition_cancelled_ = true; + MessageLoop::current()->Quit(); + } + + virtual void SpeechInputFocusChanged(int caller_id) { + EXPECT_TRUE(ChromeThread::CurrentlyOn(ChromeThread::IO)); + focus_changed_ = true; + MessageLoop::current()->Quit(); + } + + // testing::Test methods. + virtual void SetUp() { + SpeechInputBubble::set_factory( + &SpeechInputBubbleControllerTest::CreateBubble); + ui_thread_.Start(); + } + + virtual void TearDown() { + SpeechInputBubble::set_factory(NULL); + ui_thread_.Stop(); + } + + static SpeechInputBubble* CreateBubble(TabContents* tab_contents, + SpeechInputBubble::Delegate* delegate, + const gfx::Rect& element_rect) { + EXPECT_TRUE(ChromeThread::CurrentlyOn(ChromeThread::UI)); + return new MockSpeechInputBubble(tab_contents, delegate, element_rect); + } + + protected: + // The main thread of the test is marked as the IO thread and we create a new + // one for the UI thread. + MessageLoop io_loop_; + ChromeThread ui_thread_; + ChromeThread io_thread_; + bool recognition_cancelled_; + bool focus_changed_; +}; + +MockSpeechInputBubble::BubbleType MockSpeechInputBubble::type_ = + MockSpeechInputBubble::BUBBLE_TEST_FOCUS_CHANGED; + +// Test that the speech bubble UI gets created in the UI thread and that the +// focus changed callback comes back in the IO thread. +TEST_F(SpeechInputBubbleControllerTest, TestFocusChanged) { + MockSpeechInputBubble::set_type( + MockSpeechInputBubble::BUBBLE_TEST_FOCUS_CHANGED); + + scoped_refptr<SpeechInputBubbleController> controller( + new SpeechInputBubbleController(this)); + + controller->CreateBubble(0, 1, 1, gfx::Rect(1, 1)); + MessageLoop::current()->Run(); + EXPECT_TRUE(focus_changed_); + EXPECT_FALSE(recognition_cancelled_); +} + +// Test that the speech bubble UI gets created in the UI thread and that the +// recognition cancelled callback comes back in the IO thread. +TEST_F(SpeechInputBubbleControllerTest, TestRecognitionCancelled) { + MockSpeechInputBubble::set_type( + MockSpeechInputBubble::BUBBLE_TEST_RECOGNITION_CANCELLED); + + scoped_refptr<SpeechInputBubbleController> controller( + new SpeechInputBubbleController(this)); + + controller->CreateBubble(0, 1, 1, gfx::Rect(1, 1)); + MessageLoop::current()->Run(); + EXPECT_TRUE(recognition_cancelled_); + EXPECT_FALSE(focus_changed_); +} + +} // namespace speech_input diff --git a/chrome/browser/speech/speech_input_dispatcher_host.cc b/chrome/browser/speech/speech_input_dispatcher_host.cc index bec08c4..24205cb 100644 --- a/chrome/browser/speech/speech_input_dispatcher_host.cc +++ b/chrome/browser/speech/speech_input_dispatcher_host.cc @@ -133,13 +133,17 @@ bool SpeechInputDispatcherHost::OnMessageReceived( return handled; } -void SpeechInputDispatcherHost::OnStartRecognition(int render_view_id, - int request_id) { +void SpeechInputDispatcherHost::OnStartRecognition( + int render_view_id, + int request_id, + const gfx::Rect& element_rect) { LOG(INFO) << "SpeechInputDispatcherHost: start recognition" << render_view_id; int caller_id = callers_->CreateId(resource_message_filter_process_id_, render_view_id, request_id); - manager()->StartRecognition(this, caller_id); + manager()->StartRecognition(this, caller_id, + resource_message_filter_process_id_, + render_view_id, element_rect); } void SpeechInputDispatcherHost::OnCancelRecognition(int render_view_id, diff --git a/chrome/browser/speech/speech_input_dispatcher_host.h b/chrome/browser/speech/speech_input_dispatcher_host.h index b55f558..ec039f0 100644 --- a/chrome/browser/speech/speech_input_dispatcher_host.h +++ b/chrome/browser/speech/speech_input_dispatcher_host.h @@ -43,7 +43,8 @@ class SpeechInputDispatcherHost virtual ~SpeechInputDispatcherHost(); void SendMessageToRenderView(IPC::Message* message, int render_view_id); - void OnStartRecognition(int render_view_id, int request_id); + void OnStartRecognition(int render_view_id, int request_id, + const gfx::Rect& element_rect); void OnCancelRecognition(int render_view_id, int request_id); void OnStopRecording(int render_view_id, int request_id); diff --git a/chrome/browser/speech/speech_input_manager.cc b/chrome/browser/speech/speech_input_manager.cc index d8d0c55..c22d732 100644 --- a/chrome/browser/speech/speech_input_manager.cc +++ b/chrome/browser/speech/speech_input_manager.cc @@ -6,16 +6,25 @@ #include "base/ref_counted.h" #include "base/singleton.h" +#include "chrome/browser/chrome_thread.h" +#include "chrome/browser/speech/speech_input_bubble_controller.h" +#include "chrome/browser/speech/speech_recognizer.h" +#include "chrome/browser/tab_contents/tab_contents.h" +#include "chrome/browser/tab_contents/tab_util.h" #include <map> namespace speech_input { class SpeechInputManagerImpl : public SpeechInputManager, + public SpeechInputBubbleControllerDelegate, public SpeechRecognizerDelegate { public: // SpeechInputManager methods. virtual void StartRecognition(SpeechInputManagerDelegate* delegate, - int caller_id); + int caller_id, + int render_process_id, + int render_view_id, + const gfx::Rect& element_rect); virtual void CancelRecognition(int caller_id); virtual void StopRecording(int caller_id); @@ -25,6 +34,10 @@ class SpeechInputManagerImpl : public SpeechInputManager, virtual void DidCompleteRecording(int caller_id); virtual void DidCompleteRecognition(int caller_id); + // SpeechInputBubbleController::Delegate methods. + virtual void RecognitionCancelled(int caller_id); + virtual void SpeechInputFocusChanged(int caller_id); + private: // Private constructor to enforce singleton. friend struct DefaultSingletonTraits<SpeechInputManagerImpl>; @@ -43,6 +56,7 @@ class SpeechInputManagerImpl : public SpeechInputManager, typedef std::map<int, SpeechInputRequest> SpeechRecognizerMap; SpeechRecognizerMap requests_; int recording_caller_id_; + scoped_refptr<SpeechInputBubbleController> bubble_controller_; }; SpeechInputManager* SpeechInputManager::Get() { @@ -50,7 +64,9 @@ SpeechInputManager* SpeechInputManager::Get() { } SpeechInputManagerImpl::SpeechInputManagerImpl() - : recording_caller_id_(0) { + : recording_caller_id_(0), + bubble_controller_(new SpeechInputBubbleController( + ALLOW_THIS_IN_INITIALIZER_LIST(this))) { } SpeechInputManagerImpl::~SpeechInputManagerImpl() { @@ -73,13 +89,19 @@ SpeechRecognizer* SpeechInputManagerImpl::GetRecognizer(int caller_id) const { void SpeechInputManagerImpl::StartRecognition( SpeechInputManagerDelegate* delegate, - int caller_id) { + int caller_id, + int render_process_id, + int render_view_id, + const gfx::Rect& element_rect) { DCHECK(!HasPendingRequest(caller_id)); // If we are currently recording audio for another caller, abort that cleanly. if (recording_caller_id_) CancelRecognitionAndInformDelegate(recording_caller_id_); + bubble_controller_->CreateBubble(caller_id, render_process_id, + render_view_id, element_rect); + recording_caller_id_ = caller_id; scoped_refptr<SpeechRecognizer> recognizer(new SpeechRecognizer(this, caller_id)); @@ -93,6 +115,7 @@ void SpeechInputManagerImpl::CancelRecognition(int caller_id) { requests_.erase(caller_id); if (recording_caller_id_ == caller_id) recording_caller_id_ = 0; + bubble_controller_->CloseBubble(caller_id); } void SpeechInputManagerImpl::StopRecording(int caller_id) { @@ -113,11 +136,13 @@ void SpeechInputManagerImpl::DidCompleteRecording(int caller_id) { DCHECK(HasPendingRequest(caller_id)); recording_caller_id_ = 0; GetDelegate(caller_id)->DidCompleteRecording(caller_id); + bubble_controller_->SetBubbleToRecognizingMode(caller_id); } void SpeechInputManagerImpl::DidCompleteRecognition(int caller_id) { GetDelegate(caller_id)->DidCompleteRecognition(caller_id); requests_.erase(caller_id); + bubble_controller_->CloseBubble(caller_id); } void SpeechInputManagerImpl::CancelRecognitionAndInformDelegate(int caller_id) { @@ -127,4 +152,27 @@ void SpeechInputManagerImpl::CancelRecognitionAndInformDelegate(int caller_id) { cur_delegate->DidCompleteRecognition(caller_id); } +void SpeechInputManagerImpl::RecognitionCancelled(int caller_id) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + // Ignore if the caller id was not in our active recognizers list because the + // user might have clicked more than once, or recognition could have been + // cancelled due to other reasons before the user click was processed. + if (HasPendingRequest(caller_id)) + CancelRecognitionAndInformDelegate(caller_id); +} + +void SpeechInputManagerImpl::SpeechInputFocusChanged(int caller_id) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + // Ignore if the caller id was not in our active recognizers list because the + // user might have clicked more than once, or recognition could have been + // ended due to other reasons before the user click was processed. + if (HasPendingRequest(caller_id)) { + // If this is an ongoing recording, abort it since user has switched focus. + // Otherwise recognition has started and keep that going so user can start + // speaking to another element while this gets the results in parallel. + if (recording_caller_id_ == caller_id) + CancelRecognitionAndInformDelegate(caller_id); + } +} + } // namespace speech_input diff --git a/chrome/browser/speech/speech_input_manager.h b/chrome/browser/speech/speech_input_manager.h index 787cbdd..c220506 100644 --- a/chrome/browser/speech/speech_input_manager.h +++ b/chrome/browser/speech/speech_input_manager.h @@ -6,7 +6,7 @@ #define CHROME_BROWSER_SPEECH_SPEECH_INPUT_MANAGER_H_ #include "base/basictypes.h" -#include "chrome/browser/speech/speech_recognizer.h" +#include "gfx/rect.h" #include "ipc/ipc_message.h" namespace speech_input { @@ -42,7 +42,15 @@ class SpeechInputManager { // |delegate| is a weak pointer and should remain valid until // its |DidCompleteRecognition| method is called or recognition is cancelled. - virtual void StartRecognition(Delegate* delegate, int caller_id) = 0; + // |render_process_id| is the ID of the renderer process initiating the + // request. + // |element_rect| is the display bounds of the html element requesting speech + // input (in page coordinates). + virtual void StartRecognition(Delegate* delegate, + int caller_id, + int render_process_id, + int render_view_id, + const gfx::Rect& element_rect) = 0; virtual void CancelRecognition(int caller_id) = 0; virtual void StopRecording(int caller_id) = 0; }; |