diff options
17 files changed, 469 insertions, 19 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; }; diff --git a/chrome/browser/views/speech_input_bubble.cc b/chrome/browser/views/speech_input_bubble_view.cc index 1722227..9e74eac 100644 --- a/chrome/browser/views/speech_input_bubble.cc +++ b/chrome/browser/views/speech_input_bubble_view.cc @@ -250,7 +250,7 @@ bool SpeechInputBubbleImpl::FadeInOnShow() { } // namespace -SpeechInputBubble* SpeechInputBubble::Create( +SpeechInputBubble* SpeechInputBubble::CreateNativeBubble( TabContents* tab_contents, SpeechInputBubble::Delegate* delegate, const gfx::Rect& element_rect) { diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index b1f14b2..f5ee2d2 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -2445,6 +2445,9 @@ 'browser/speech/endpointer/energy_endpointer.h', 'browser/speech/endpointer/energy_endpointer_params.h', 'browser/speech/speech_input_bubble.h', + 'browser/speech/speech_input_bubble.cc', + 'browser/speech/speech_input_bubble_controller.cc', + 'browser/speech/speech_input_bubble_controller.h', 'browser/speech/speech_input_dispatcher_host.cc', 'browser/speech/speech_input_dispatcher_host.h', 'browser/speech/speech_input_manager.cc', @@ -2953,7 +2956,7 @@ 'browser/views/sad_tab_view.h', 'browser/views/select_file_dialog.cc', 'browser/views/shell_dialogs_win.cc', - 'browser/views/speech_input_bubble.cc', + 'browser/views/speech_input_bubble_view.cc', 'browser/views/ssl_client_certificate_selector_win.cc', 'browser/views/status_bubble_views.cc', 'browser/views/status_bubble_views.h', diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index 320dda0..34fc4cd 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -1215,6 +1215,7 @@ 'browser/sessions/session_service_unittest.cc', 'browser/shell_integration_unittest.cc', 'browser/speech/endpointer/endpointer_unittest.cc', + 'browser/speech/speech_input_bubble_controller_unittest.cc', 'browser/speech/speech_recognition_request_unittest.cc', 'browser/speech/speech_recognizer_unittest.cc', 'browser/spellchecker_platform_engine_unittest.cc', diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h index 14e1166..bc78fd0 100644 --- a/chrome/common/render_messages_internal.h +++ b/chrome/common/render_messages_internal.h @@ -2665,9 +2665,10 @@ IPC_BEGIN_MESSAGES(ViewHost) // Requests the speech input service to start speech recognition on behalf of // the given |render_view_id|. - IPC_MESSAGE_CONTROL2(ViewHostMsg_SpeechInput_StartRecognition, + IPC_MESSAGE_CONTROL3(ViewHostMsg_SpeechInput_StartRecognition, int /* render_view_id */, - int /* request id */) + int /* request id */, + gfx::Rect /* element rect in render view coordinates */) // Requests the speech input service to cancel speech recognition on behalf of // the given |render_view_id|. If speech recognition is not happening nor or diff --git a/chrome/renderer/speech_input_dispatcher.cc b/chrome/renderer/speech_input_dispatcher.cc index 3aaf15f..54adfa8 100644 --- a/chrome/renderer/speech_input_dispatcher.cc +++ b/chrome/renderer/speech_input_dispatcher.cc @@ -8,6 +8,8 @@ #include "third_party/WebKit/WebKit/chromium/public/WebCString.h" #include "third_party/WebKit/WebKit/chromium/public/WebFrame.h" #include "third_party/WebKit/WebKit/chromium/public/WebSpeechInputListener.h" +#include "third_party/WebKit/WebKit/chromium/public/WebSize.h" +#include "third_party/WebKit/WebKit/chromium/public/WebView.h" using WebKit::WebFrame; @@ -31,9 +33,13 @@ bool SpeechInputDispatcher::OnMessageReceived(const IPC::Message& message) { return handled; } -bool SpeechInputDispatcher::startRecognition(int request_id) { +bool SpeechInputDispatcher::startRecognition( + int request_id, const WebKit::WebRect& element_rect) { + gfx::Size scroll = render_view_->webview()->mainFrame()->scrollOffset(); + gfx::Rect rect = element_rect; + rect.Offset(-scroll.width(), -scroll.height()); render_view_->Send(new ViewHostMsg_SpeechInput_StartRecognition( - render_view_->routing_id(), request_id)); + render_view_->routing_id(), request_id, rect)); return true; } diff --git a/chrome/renderer/speech_input_dispatcher.h b/chrome/renderer/speech_input_dispatcher.h index b6f6c4c..188acaa 100644 --- a/chrome/renderer/speech_input_dispatcher.h +++ b/chrome/renderer/speech_input_dispatcher.h @@ -13,6 +13,7 @@ class GURL; class RenderView; namespace WebKit { +struct WebRect; class WebSpeechInputListener; } @@ -28,7 +29,7 @@ class SpeechInputDispatcher : public WebKit::WebSpeechInputController { bool OnMessageReceived(const IPC::Message& msg); // WebKit::WebSpeechInputController. - bool startRecognition(int request_id); + bool startRecognition(int request_id, const WebKit::WebRect& element_rect); void cancelRecognition(int request_id); void stopRecording(int request_id); diff --git a/media/audio/audio_input_controller.cc b/media/audio/audio_input_controller.cc index d64fb70..9c143c1 100644 --- a/media/audio/audio_input_controller.cc +++ b/media/audio/audio_input_controller.cc @@ -154,6 +154,9 @@ void AudioInputController::OnData(AudioInputStream* stream, const uint8* data, } void AudioInputController::OnClose(AudioInputStream* stream) { + // TODO(satish): Sometimes the device driver closes the input stream without + // us asking for it (may be if the device was unplugged?). Check how to handle + // such cases here. } void AudioInputController::OnError(AudioInputStream* stream, int code) { |