| // Copyright (c) 2012 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_recognition_bubble_controller.h" |
| |
| #include "base/bind.h" |
| #include "chrome/browser/tab_contents/tab_util.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "content/public/browser/notification_registrar.h" |
| #include "content/public/browser/notification_source.h" |
| #include "content/public/browser/notification_types.h" |
| #include "content/public/browser/render_process_host.h" |
| #include "content/public/browser/render_view_host.h" |
| #include "content/public/browser/web_contents.h" |
| |
| using content::BrowserThread; |
| using content::WebContents; |
| |
| namespace { |
| const int kInvalidSessionId = 0; |
| } |
| |
| namespace speech { |
| |
| SpeechRecognitionBubbleController::SpeechRecognitionBubbleController( |
| Delegate* delegate) |
| : delegate_(delegate), |
| last_request_issued_(REQUEST_CLOSE), |
| current_bubble_session_id_(kInvalidSessionId), |
| current_bubble_render_process_id_(0), |
| current_bubble_render_view_id_(0) { |
| } |
| |
| SpeechRecognitionBubbleController::~SpeechRecognitionBubbleController() { |
| DCHECK_EQ(kInvalidSessionId, current_bubble_session_id_); |
| } |
| |
| void SpeechRecognitionBubbleController::CreateBubble( |
| int session_id, |
| int render_process_id, |
| int render_view_id, |
| const gfx::Rect& element_rect) { |
| { |
| base::AutoLock auto_lock(lock_); |
| current_bubble_session_id_ = session_id; |
| current_bubble_render_process_id_ = render_process_id; |
| current_bubble_render_view_id_ = render_view_id; |
| } |
| |
| UIRequest request(REQUEST_CREATE); |
| request.render_process_id = render_process_id; |
| request.render_view_id = render_view_id; |
| request.element_rect = element_rect; |
| ProcessRequestInUiThread(request); |
| } |
| |
| void SpeechRecognitionBubbleController::SetBubbleRecordingMode() { |
| ProcessRequestInUiThread(UIRequest(REQUEST_SET_RECORDING_MODE)); |
| } |
| |
| void SpeechRecognitionBubbleController::SetBubbleRecognizingMode() { |
| ProcessRequestInUiThread(UIRequest(REQUEST_SET_RECOGNIZING_MODE)); |
| } |
| |
| void SpeechRecognitionBubbleController::SetBubbleMessage(const string16& text) { |
| UIRequest request(REQUEST_SET_MESSAGE); |
| request.message = text; |
| ProcessRequestInUiThread(request); |
| } |
| |
| bool SpeechRecognitionBubbleController::IsShowingMessage() const { |
| return last_request_issued_ == REQUEST_SET_MESSAGE; |
| } |
| |
| void SpeechRecognitionBubbleController::SetBubbleInputVolume( |
| float volume, |
| float noise_volume) { |
| UIRequest request(REQUEST_SET_INPUT_VOLUME); |
| request.volume = volume; |
| request.noise_volume = noise_volume; |
| ProcessRequestInUiThread(request); |
| } |
| |
| void SpeechRecognitionBubbleController::CloseBubble() { |
| { |
| base::AutoLock auto_lock(lock_); |
| current_bubble_session_id_ = kInvalidSessionId; |
| } |
| ProcessRequestInUiThread(UIRequest(REQUEST_CLOSE)); |
| } |
| |
| void SpeechRecognitionBubbleController::CloseBubbleForRenderViewOnUIThread( |
| int render_process_id, int render_view_id) { |
| { |
| base::AutoLock auto_lock(lock_); |
| if (current_bubble_session_id_ == kInvalidSessionId || |
| current_bubble_render_process_id_ != render_process_id || |
| current_bubble_render_view_id_ != render_view_id) { |
| return; |
| } |
| current_bubble_session_id_ = kInvalidSessionId; |
| } |
| ProcessRequestInUiThread(UIRequest(REQUEST_CLOSE)); |
| } |
| |
| int SpeechRecognitionBubbleController::GetActiveSessionID() { |
| base::AutoLock auto_lock(lock_); |
| return current_bubble_session_id_; |
| } |
| |
| void SpeechRecognitionBubbleController::InfoBubbleButtonClicked( |
| SpeechRecognitionBubble::Button button) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
| base::Bind( |
| &SpeechRecognitionBubbleController::InvokeDelegateButtonClicked, this, |
| button)); |
| } |
| |
| void SpeechRecognitionBubbleController::InfoBubbleFocusChanged() { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
| base::Bind(&SpeechRecognitionBubbleController::InvokeDelegateFocusChanged, |
| this)); |
| } |
| |
| void SpeechRecognitionBubbleController::InvokeDelegateButtonClicked( |
| SpeechRecognitionBubble::Button button) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| { |
| base::AutoLock auto_lock(lock_); |
| if (kInvalidSessionId == current_bubble_session_id_) |
| return; |
| } |
| delegate_->InfoBubbleButtonClicked(current_bubble_session_id_, button); |
| } |
| |
| void SpeechRecognitionBubbleController::InvokeDelegateFocusChanged() { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| { |
| base::AutoLock auto_lock(lock_); |
| if (kInvalidSessionId == current_bubble_session_id_) |
| return; |
| } |
| delegate_->InfoBubbleFocusChanged(current_bubble_session_id_); |
| } |
| |
| void SpeechRecognitionBubbleController::ProcessRequestInUiThread( |
| const UIRequest& request) { |
| if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { |
| last_request_issued_ = request.type; |
| BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| base::Bind(&SpeechRecognitionBubbleController::ProcessRequestInUiThread, |
| this, request)); |
| return; |
| } |
| |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| |
| // In the case of a tab closed or crashed, the bubble can have been destroyed |
| // earlier on the UI thread, while other tasks were being enqueued from the IO |
| // to the UI thread. Simply return in such cases. |
| if (request.type != REQUEST_CREATE && !bubble_.get()) |
| return; |
| |
| switch (request.type) { |
| case REQUEST_CREATE: |
| bubble_.reset(SpeechRecognitionBubble::Create( |
| tab_util::GetWebContentsByID(request.render_process_id, |
| request.render_view_id), |
| this, request.element_rect)); |
| |
| if (!bubble_.get()) { |
| // Could be null if tab or display rect were invalid. |
| // Simulate the cancel button being clicked to inform the delegate. |
| BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
| base::Bind( |
| &SpeechRecognitionBubbleController::InvokeDelegateButtonClicked, |
| this, SpeechRecognitionBubble::BUTTON_CANCEL)); |
| return; |
| } |
| bubble_->Show(); |
| bubble_->SetWarmUpMode(); |
| break; |
| case REQUEST_SET_RECORDING_MODE: |
| bubble_->SetRecordingMode(); |
| break; |
| case REQUEST_SET_RECOGNIZING_MODE: |
| bubble_->SetRecognizingMode(); |
| break; |
| case REQUEST_SET_MESSAGE: |
| bubble_->SetMessage(request.message); |
| break; |
| case REQUEST_SET_INPUT_VOLUME: |
| bubble_->SetInputVolume(request.volume, request.noise_volume); |
| break; |
| case REQUEST_CLOSE: |
| bubble_.reset(); |
| break; |
| default: |
| NOTREACHED(); |
| break; |
| } |
| } |
| |
| SpeechRecognitionBubbleController::UIRequest::UIRequest(RequestType type_value) |
| : type(type_value), |
| volume(0.0F), |
| noise_volume(0.0F), |
| render_process_id(0), |
| render_view_id(0) { |
| } |
| |
| SpeechRecognitionBubbleController::UIRequest::~UIRequest() { |
| } |
| |
| } // namespace speech |