summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/speech/speech_input_browsertest.cc6
-rw-r--r--chrome/browser/speech/speech_input_bubble.cc27
-rw-r--r--chrome/browser/speech/speech_input_bubble.h27
-rw-r--r--chrome/browser/speech/speech_input_bubble_controller.cc108
-rw-r--r--chrome/browser/speech/speech_input_bubble_controller.h81
-rw-r--r--chrome/browser/speech/speech_input_bubble_controller_unittest.cc131
-rw-r--r--chrome/browser/speech/speech_input_dispatcher_host.cc10
-rw-r--r--chrome/browser/speech/speech_input_dispatcher_host.h3
-rw-r--r--chrome/browser/speech/speech_input_manager.cc54
-rw-r--r--chrome/browser/speech/speech_input_manager.h12
-rw-r--r--chrome/browser/views/speech_input_bubble_view.cc (renamed from chrome/browser/views/speech_input_bubble.cc)2
-rw-r--r--chrome/chrome_browser.gypi5
-rw-r--r--chrome/chrome_tests.gypi1
-rw-r--r--chrome/common/render_messages_internal.h5
-rw-r--r--chrome/renderer/speech_input_dispatcher.cc10
-rw-r--r--chrome/renderer/speech_input_dispatcher.h3
-rw-r--r--media/audio/audio_input_controller.cc3
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) {