Home | History | Annotate | Download | only in speech
      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       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 
     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   {
     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 
     58 void SpeechRecognitionBubbleController::SetBubbleRecordingMode() {
     59   ProcessRequestInUiThread(UIRequest(REQUEST_SET_RECORDING_MODE));
     60 }
     61 
     62 void SpeechRecognitionBubbleController::SetBubbleRecognizingMode() {
     63   ProcessRequestInUiThread(UIRequest(REQUEST_SET_RECOGNIZING_MODE));
     64 }
     65 
     66 void SpeechRecognitionBubbleController::SetBubbleMessage(
     67     const base::string16& text) {
     68   UIRequest request(REQUEST_SET_MESSAGE);
     69   request.message = text;
     70   ProcessRequestInUiThread(request);
     71 }
     72 
     73 bool SpeechRecognitionBubbleController::IsShowingMessage() const {
     74   return last_request_issued_ == REQUEST_SET_MESSAGE;
     75 }
     76 
     77 void 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 
     86 void SpeechRecognitionBubbleController::CloseBubble() {
     87   {
     88     base::AutoLock auto_lock(lock_);
     89     current_bubble_session_id_ = kInvalidSessionId;
     90   }
     91   ProcessRequestInUiThread(UIRequest(REQUEST_CLOSE));
     92 }
     93 
     94 void 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 
    108 int SpeechRecognitionBubbleController::GetActiveSessionID() {
    109   base::AutoLock auto_lock(lock_);
    110   return current_bubble_session_id_;
    111 }
    112 
    113 void 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 
    122 void SpeechRecognitionBubbleController::InfoBubbleFocusChanged() {
    123   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    124   BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
    125       base::Bind(&SpeechRecognitionBubbleController::InvokeDelegateFocusChanged,
    126                  this));
    127 }
    128 
    129 void 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 
    140 void 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 
    150 void 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 
    207 SpeechRecognitionBubbleController::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 
    215 SpeechRecognitionBubbleController::UIRequest::~UIRequest() {
    216 }
    217 
    218 }  // namespace speech
    219