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 17 using content::BrowserThread; 18 using content::WebContents; 19 20 namespace { 21 const int kInvalidSessionId = 0; 22 } 23 24 namespace speech { 25 26 SpeechRecognitionBubbleController::SpeechRecognitionBubbleController( 27 Delegate* delegate) 28 : delegate_(delegate), 29 current_bubble_session_id_(kInvalidSessionId), 30 current_bubble_render_process_id_(0), 31 current_bubble_render_view_id_(0), 32 last_request_issued_(REQUEST_CLOSE) { 33 } 34 35 SpeechRecognitionBubbleController::~SpeechRecognitionBubbleController() { 36 DCHECK_EQ(kInvalidSessionId, current_bubble_session_id_); 37 } 38 39 void SpeechRecognitionBubbleController::CreateBubble( 40 int session_id, 41 int render_process_id, 42 int render_view_id, 43 const gfx::Rect& element_rect) { 44 current_bubble_session_id_ = session_id; 45 current_bubble_render_process_id_ = render_process_id; 46 current_bubble_render_view_id_ = render_view_id; 47 48 UIRequest request(REQUEST_CREATE); 49 request.render_process_id = render_process_id; 50 request.render_view_id = render_view_id; 51 request.element_rect = element_rect; 52 ProcessRequestInUiThread(request); 53 } 54 55 void SpeechRecognitionBubbleController::SetBubbleRecordingMode() { 56 ProcessRequestInUiThread(UIRequest(REQUEST_SET_RECORDING_MODE)); 57 } 58 59 void SpeechRecognitionBubbleController::SetBubbleRecognizingMode() { 60 ProcessRequestInUiThread(UIRequest(REQUEST_SET_RECOGNIZING_MODE)); 61 } 62 63 void SpeechRecognitionBubbleController::SetBubbleMessage(const string16& text) { 64 UIRequest request(REQUEST_SET_MESSAGE); 65 request.message = text; 66 ProcessRequestInUiThread(request); 67 } 68 69 bool SpeechRecognitionBubbleController::IsShowingMessage() const { 70 return last_request_issued_ == REQUEST_SET_MESSAGE; 71 } 72 73 void SpeechRecognitionBubbleController::SetBubbleInputVolume( 74 float volume, 75 float noise_volume) { 76 UIRequest request(REQUEST_SET_INPUT_VOLUME); 77 request.volume = volume; 78 request.noise_volume = noise_volume; 79 ProcessRequestInUiThread(request); 80 } 81 82 void SpeechRecognitionBubbleController::CloseBubble() { 83 current_bubble_session_id_ = kInvalidSessionId; 84 ProcessRequestInUiThread(UIRequest(REQUEST_CLOSE)); 85 } 86 87 int SpeechRecognitionBubbleController::GetActiveSessionID() const { 88 return current_bubble_session_id_; 89 } 90 91 bool SpeechRecognitionBubbleController::IsShowingBubbleForRenderView( 92 int render_process_id, 93 int render_view_id) { 94 return (current_bubble_session_id_ != kInvalidSessionId) && 95 (current_bubble_render_process_id_ == render_process_id) && 96 (current_bubble_render_view_id_ == render_view_id); 97 } 98 99 void SpeechRecognitionBubbleController::InfoBubbleButtonClicked( 100 SpeechRecognitionBubble::Button button) { 101 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 102 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, 103 base::Bind( 104 &SpeechRecognitionBubbleController::InvokeDelegateButtonClicked, this, 105 button)); 106 } 107 108 void SpeechRecognitionBubbleController::InfoBubbleFocusChanged() { 109 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 110 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, 111 base::Bind(&SpeechRecognitionBubbleController::InvokeDelegateFocusChanged, 112 this)); 113 } 114 115 void SpeechRecognitionBubbleController::InvokeDelegateButtonClicked( 116 SpeechRecognitionBubble::Button button) { 117 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 118 DCHECK_NE(kInvalidSessionId, current_bubble_session_id_); 119 delegate_->InfoBubbleButtonClicked(current_bubble_session_id_, button); 120 } 121 122 void SpeechRecognitionBubbleController::InvokeDelegateFocusChanged() { 123 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 124 DCHECK_NE(kInvalidSessionId, current_bubble_session_id_); 125 delegate_->InfoBubbleFocusChanged(current_bubble_session_id_); 126 } 127 128 void SpeechRecognitionBubbleController::ProcessRequestInUiThread( 129 const UIRequest& request) { 130 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { 131 last_request_issued_ = request.type; 132 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 133 base::Bind(&SpeechRecognitionBubbleController::ProcessRequestInUiThread, 134 this, request)); 135 return; 136 } 137 138 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 139 140 switch (request.type) { 141 case REQUEST_CREATE: 142 bubble_.reset(SpeechRecognitionBubble::Create( 143 tab_util::GetWebContentsByID(request.render_process_id, 144 request.render_view_id), 145 this, request.element_rect)); 146 147 if (!bubble_.get()) { 148 // Could be null if tab or display rect were invalid. 149 // Simulate the cancel button being clicked to inform the delegate. 150 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, 151 base::Bind( 152 &SpeechRecognitionBubbleController::InvokeDelegateButtonClicked, 153 this, SpeechRecognitionBubble::BUTTON_CANCEL)); 154 return; 155 } 156 bubble_->Show(); 157 bubble_->SetWarmUpMode(); 158 break; 159 case REQUEST_SET_RECORDING_MODE: 160 if (!bubble_.get()) { 161 // We've seen this on crash/ but don't yet understand why this happen. 162 // TODO(tommi): It would be nice to figure this out properly and fix 163 // but since this feature is being deprecated, removing the code 164 // altogether is probably a simpler and more permanent fix :) 165 DLOG(ERROR) << "NULL bubble in REQUEST_SET_RECORDING_MODE!"; 166 } else { 167 bubble_->SetRecordingMode(); 168 } 169 break; 170 case REQUEST_SET_RECOGNIZING_MODE: 171 DCHECK(bubble_.get()); 172 bubble_->SetRecognizingMode(); 173 break; 174 case REQUEST_SET_MESSAGE: 175 DCHECK(bubble_.get()); 176 bubble_->SetMessage(request.message); 177 break; 178 case REQUEST_SET_INPUT_VOLUME: 179 DCHECK(bubble_.get()); 180 bubble_->SetInputVolume(request.volume, request.noise_volume); 181 break; 182 case REQUEST_CLOSE: 183 bubble_.reset(); 184 break; 185 default: 186 NOTREACHED(); 187 break; 188 } 189 } 190 191 SpeechRecognitionBubbleController::UIRequest::UIRequest(RequestType type_value) 192 : type(type_value), 193 volume(0.0F), 194 noise_volume(0.0F), 195 render_process_id(0), 196 render_view_id(0) { 197 } 198 199 SpeechRecognitionBubbleController::UIRequest::~UIRequest() { 200 } 201 202 } // namespace speech 203