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 3// found in the LICENSE file. 4 5#include "chrome/browser/speech/speech_recognition_bubble_controller.h" 6 7#include "base/bind.h" 8#include "chrome/browser/tab_contents/tab_util.h" 9#include "content/public/browser/browser_thread.h" 10#include "content/public/browser/notification_registrar.h" 11#include "content/public/browser/notification_source.h" 12#include "content/public/browser/notification_types.h" 13#include "content/public/browser/render_process_host.h" 14#include "content/public/browser/render_view_host.h" 15#include "content/public/browser/web_contents.h" 16 17using content::BrowserThread; 18using content::WebContents; 19 20namespace { 21const int kInvalidSessionId = 0; 22} 23 24namespace speech { 25 26SpeechRecognitionBubbleController::SpeechRecognitionBubbleController( 27 Delegate* delegate) 28 : delegate_(delegate), 29 last_request_issued_(REQUEST_CLOSE), 30 current_bubble_session_id_(kInvalidSessionId), 31 current_bubble_render_process_id_(0), 32 current_bubble_render_view_id_(0) { 33} 34 35SpeechRecognitionBubbleController::~SpeechRecognitionBubbleController() { 36 DCHECK_EQ(kInvalidSessionId, current_bubble_session_id_); 37} 38 39void SpeechRecognitionBubbleController::CreateBubble( 40 int session_id, 41 int render_process_id, 42 int render_view_id, 43 const gfx::Rect& element_rect) { 44 { 45 base::AutoLock auto_lock(lock_); 46 current_bubble_session_id_ = session_id; 47 current_bubble_render_process_id_ = render_process_id; 48 current_bubble_render_view_id_ = render_view_id; 49 } 50 51 UIRequest request(REQUEST_CREATE); 52 request.render_process_id = render_process_id; 53 request.render_view_id = render_view_id; 54 request.element_rect = element_rect; 55 ProcessRequestInUiThread(request); 56} 57 58void SpeechRecognitionBubbleController::SetBubbleRecordingMode() { 59 ProcessRequestInUiThread(UIRequest(REQUEST_SET_RECORDING_MODE)); 60} 61 62void SpeechRecognitionBubbleController::SetBubbleRecognizingMode() { 63 ProcessRequestInUiThread(UIRequest(REQUEST_SET_RECOGNIZING_MODE)); 64} 65 66void SpeechRecognitionBubbleController::SetBubbleMessage( 67 const base::string16& text) { 68 UIRequest request(REQUEST_SET_MESSAGE); 69 request.message = text; 70 ProcessRequestInUiThread(request); 71} 72 73bool SpeechRecognitionBubbleController::IsShowingMessage() const { 74 return last_request_issued_ == REQUEST_SET_MESSAGE; 75} 76 77void SpeechRecognitionBubbleController::SetBubbleInputVolume( 78 float volume, 79 float noise_volume) { 80 UIRequest request(REQUEST_SET_INPUT_VOLUME); 81 request.volume = volume; 82 request.noise_volume = noise_volume; 83 ProcessRequestInUiThread(request); 84} 85 86void SpeechRecognitionBubbleController::CloseBubble() { 87 { 88 base::AutoLock auto_lock(lock_); 89 current_bubble_session_id_ = kInvalidSessionId; 90 } 91 ProcessRequestInUiThread(UIRequest(REQUEST_CLOSE)); 92} 93 94void SpeechRecognitionBubbleController::CloseBubbleForRenderViewOnUIThread( 95 int render_process_id, int render_view_id) { 96 { 97 base::AutoLock auto_lock(lock_); 98 if (current_bubble_session_id_ == kInvalidSessionId || 99 current_bubble_render_process_id_ != render_process_id || 100 current_bubble_render_view_id_ != render_view_id) { 101 return; 102 } 103 current_bubble_session_id_ = kInvalidSessionId; 104 } 105 ProcessRequestInUiThread(UIRequest(REQUEST_CLOSE)); 106} 107 108int SpeechRecognitionBubbleController::GetActiveSessionID() { 109 base::AutoLock auto_lock(lock_); 110 return current_bubble_session_id_; 111} 112 113void SpeechRecognitionBubbleController::InfoBubbleButtonClicked( 114 SpeechRecognitionBubble::Button button) { 115 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 116 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, 117 base::Bind( 118 &SpeechRecognitionBubbleController::InvokeDelegateButtonClicked, this, 119 button)); 120} 121 122void SpeechRecognitionBubbleController::InfoBubbleFocusChanged() { 123 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 124 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, 125 base::Bind(&SpeechRecognitionBubbleController::InvokeDelegateFocusChanged, 126 this)); 127} 128 129void SpeechRecognitionBubbleController::InvokeDelegateButtonClicked( 130 SpeechRecognitionBubble::Button button) { 131 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 132 { 133 base::AutoLock auto_lock(lock_); 134 if (kInvalidSessionId == current_bubble_session_id_) 135 return; 136 } 137 delegate_->InfoBubbleButtonClicked(current_bubble_session_id_, button); 138} 139 140void SpeechRecognitionBubbleController::InvokeDelegateFocusChanged() { 141 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 142 { 143 base::AutoLock auto_lock(lock_); 144 if (kInvalidSessionId == current_bubble_session_id_) 145 return; 146 } 147 delegate_->InfoBubbleFocusChanged(current_bubble_session_id_); 148} 149 150void SpeechRecognitionBubbleController::ProcessRequestInUiThread( 151 const UIRequest& request) { 152 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { 153 last_request_issued_ = request.type; 154 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 155 base::Bind(&SpeechRecognitionBubbleController::ProcessRequestInUiThread, 156 this, request)); 157 return; 158 } 159 160 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 161 162 // In the case of a tab closed or crashed, the bubble can have been destroyed 163 // earlier on the UI thread, while other tasks were being enqueued from the IO 164 // to the UI thread. Simply return in such cases. 165 if (request.type != REQUEST_CREATE && !bubble_.get()) 166 return; 167 168 switch (request.type) { 169 case REQUEST_CREATE: 170 bubble_.reset(SpeechRecognitionBubble::Create( 171 request.render_process_id, request.render_view_id, 172 this, request.element_rect)); 173 174 if (!bubble_.get()) { 175 // Could be null if tab or display rect were invalid. 176 // Simulate the cancel button being clicked to inform the delegate. 177 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, 178 base::Bind( 179 &SpeechRecognitionBubbleController::InvokeDelegateButtonClicked, 180 this, SpeechRecognitionBubble::BUTTON_CANCEL)); 181 return; 182 } 183 bubble_->Show(); 184 bubble_->SetWarmUpMode(); 185 break; 186 case REQUEST_SET_RECORDING_MODE: 187 bubble_->SetRecordingMode(); 188 break; 189 case REQUEST_SET_RECOGNIZING_MODE: 190 bubble_->SetRecognizingMode(); 191 break; 192 case REQUEST_SET_MESSAGE: 193 bubble_->SetMessage(request.message); 194 break; 195 case REQUEST_SET_INPUT_VOLUME: 196 bubble_->SetInputVolume(request.volume, request.noise_volume); 197 break; 198 case REQUEST_CLOSE: 199 bubble_.reset(); 200 break; 201 default: 202 NOTREACHED(); 203 break; 204 } 205} 206 207SpeechRecognitionBubbleController::UIRequest::UIRequest(RequestType type_value) 208 : type(type_value), 209 volume(0.0F), 210 noise_volume(0.0F), 211 render_process_id(0), 212 render_view_id(0) { 213} 214 215SpeechRecognitionBubbleController::UIRequest::~UIRequest() { 216} 217 218} // namespace speech 219