Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/speech/speech_input_bubble_controller.h" | 5 #include "chrome/browser/speech/speech_input_bubble_controller.h" |
| 6 | 6 |
| 7 #include "chrome/browser/browser_thread.h" | 7 #include "chrome/browser/browser_thread.h" |
| 8 #include "chrome/browser/tab_contents/tab_contents.h" | 8 #include "chrome/browser/tab_contents/tab_contents.h" |
| 9 #include "chrome/browser/tab_contents/tab_util.h" | 9 #include "chrome/browser/tab_contents/tab_util.h" |
| 10 #include "chrome/common/notification_registrar.h" | |
| 11 #include "chrome/common/notification_source.h" | |
| 12 #include "chrome/common/notification_type.h" | |
| 10 #include "gfx/rect.h" | 13 #include "gfx/rect.h" |
| 11 | 14 |
| 12 namespace speech_input { | 15 namespace speech_input { |
| 13 | 16 |
| 14 SpeechInputBubbleController::SpeechInputBubbleController(Delegate* delegate) | 17 SpeechInputBubbleController::SpeechInputBubbleController(Delegate* delegate) |
| 15 : delegate_(delegate), | 18 : delegate_(delegate), |
| 16 current_bubble_caller_id_(0) { | 19 current_bubble_caller_id_(0), |
| 20 registrar_(new NotificationRegistrar) { | |
| 17 } | 21 } |
| 18 | 22 |
| 19 SpeechInputBubbleController::~SpeechInputBubbleController() { | 23 SpeechInputBubbleController::~SpeechInputBubbleController() { |
| 20 DCHECK(bubbles_.size() == 0); | 24 DCHECK(bubbles_.size() == 0); |
| 21 } | 25 } |
| 22 | 26 |
| 23 void SpeechInputBubbleController::CreateBubble(int caller_id, | 27 void SpeechInputBubbleController::CreateBubble(int caller_id, |
| 24 int render_process_id, | 28 int render_process_id, |
| 25 int render_view_id, | 29 int render_view_id, |
| 26 const gfx::Rect& element_rect) { | 30 const gfx::Rect& element_rect) { |
| 27 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { | 31 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { |
| 28 BrowserThread::PostTask( | 32 BrowserThread::PostTask( |
| 29 BrowserThread::UI, FROM_HERE, | 33 BrowserThread::UI, FROM_HERE, |
| 30 NewRunnableMethod(this, &SpeechInputBubbleController::CreateBubble, | 34 NewRunnableMethod(this, &SpeechInputBubbleController::CreateBubble, |
| 31 caller_id, render_process_id, render_view_id, | 35 caller_id, render_process_id, render_view_id, |
| 32 element_rect)); | 36 element_rect)); |
| 33 return; | 37 return; |
| 34 } | 38 } |
| 35 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 39 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 36 TabContents* tab_contents = tab_util::GetTabContentsByID(render_process_id, | 40 TabContents* tab_contents = tab_util::GetTabContentsByID(render_process_id, |
| 37 render_view_id); | 41 render_view_id); |
| 38 | 42 |
| 39 DCHECK_EQ(0u, bubbles_.count(caller_id)); | 43 DCHECK_EQ(0u, bubbles_.count(caller_id)); |
| 40 SpeechInputBubble* bubble = SpeechInputBubble::Create(tab_contents, this, | 44 SpeechInputBubble* bubble = SpeechInputBubble::Create(tab_contents, this, |
| 41 element_rect); | 45 element_rect); |
| 42 if (!bubble) // could be null if tab or display rect were invalid. | 46 if (!bubble) // could be null if tab or display rect were invalid. |
| 43 return; | 47 return; |
| 44 | 48 |
| 45 bubbles_[caller_id] = bubble; | 49 bubbles_[caller_id] = bubble; |
| 50 | |
| 51 // If this is the first bubble in our list for this TabContents, register | |
|
hans
2011/01/06 12:30:54
"First in our list", but the call is to IsOnlyBubb
| |
| 52 // for notifications when the tab closes. This ensures that we can safely | |
| 53 // kill the bubble and recording session even if the user clicked on the | |
| 54 // speech button and immediately closes the tab, or if the tab crashes in | |
|
bulach
2011/01/06 12:32:39
s/in the somewhere/
| |
| 55 // the somewhere while the bubble & recording are active. | |
|
hans
2011/01/06 12:30:54
nit: "crashes in the somewhere" sounds weird
| |
| 56 if (IsOnlyBubbleForTab(caller_id)) { | |
|
bulach
2011/01/06 12:32:39
as we chatted, the "IsOnlyBubbleForTab" is the bes
| |
| 57 registrar_->Add(this, NotificationType::TAB_CONTENTS_DESTROYED, | |
| 58 Source<TabContents>(tab_contents)); | |
| 59 } | |
| 46 } | 60 } |
| 47 | 61 |
| 48 void SpeechInputBubbleController::CloseBubble(int caller_id) { | 62 void SpeechInputBubbleController::CloseBubble(int caller_id) { |
| 49 ProcessRequestInUiThread(caller_id, REQUEST_CLOSE, string16(), 0); | 63 ProcessRequestInUiThread(caller_id, REQUEST_CLOSE, string16(), 0); |
| 50 } | 64 } |
| 51 | 65 |
| 52 void SpeechInputBubbleController::SetBubbleRecordingMode(int caller_id) { | 66 void SpeechInputBubbleController::SetBubbleRecordingMode(int caller_id) { |
| 53 ProcessRequestInUiThread(caller_id, REQUEST_SET_RECORDING_MODE, | 67 ProcessRequestInUiThread(caller_id, REQUEST_SET_RECORDING_MODE, |
| 54 string16(), 0); | 68 string16(), 0); |
| 55 } | 69 } |
| 56 | 70 |
| 57 void SpeechInputBubbleController::SetBubbleRecognizingMode(int caller_id) { | 71 void SpeechInputBubbleController::SetBubbleRecognizingMode(int caller_id) { |
| 58 ProcessRequestInUiThread(caller_id, REQUEST_SET_RECOGNIZING_MODE, | 72 ProcessRequestInUiThread(caller_id, REQUEST_SET_RECOGNIZING_MODE, |
| 59 string16(), 0); | 73 string16(), 0); |
| 60 } | 74 } |
| 61 | 75 |
| 62 void SpeechInputBubbleController::SetBubbleInputVolume(int caller_id, | 76 void SpeechInputBubbleController::SetBubbleInputVolume(int caller_id, |
| 63 float volume) { | 77 float volume) { |
| 64 ProcessRequestInUiThread(caller_id, REQUEST_SET_INPUT_VOLUME, string16(), | 78 ProcessRequestInUiThread(caller_id, REQUEST_SET_INPUT_VOLUME, string16(), |
| 65 volume); | 79 volume); |
| 66 } | 80 } |
| 67 | 81 |
| 68 void SpeechInputBubbleController::SetBubbleMessage(int caller_id, | 82 void SpeechInputBubbleController::SetBubbleMessage(int caller_id, |
| 69 const string16& text) { | 83 const string16& text) { |
| 70 ProcessRequestInUiThread(caller_id, REQUEST_SET_MESSAGE, text, 0); | 84 ProcessRequestInUiThread(caller_id, REQUEST_SET_MESSAGE, text, 0); |
| 71 } | 85 } |
| 72 | 86 |
| 87 bool SpeechInputBubbleController::IsOnlyBubbleForTab(int caller_id) { | |
| 88 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 89 TabContents* tab_contents = bubbles_[caller_id]->tab_contents(); | |
| 90 for (BubbleCallerIdMap::iterator iter = bubbles_.begin(); | |
| 91 iter != bubbles_.end(); ++iter) { | |
| 92 if (iter->second->tab_contents() == tab_contents && | |
| 93 iter->first != caller_id) { | |
| 94 // At least one other bubble exists for the same TabContents. | |
|
bulach
2011/01/06 12:32:39
yeah, as above, this would be the best place to sa
| |
| 95 return false; | |
| 96 } | |
| 97 } | |
| 98 return true; | |
| 99 } | |
| 100 | |
| 101 void SpeechInputBubbleController::Observe(NotificationType type, | |
| 102 const NotificationSource& source, | |
| 103 const NotificationDetails& details) { | |
| 104 if (type == NotificationType::TAB_CONTENTS_DESTROYED) { | |
| 105 // Cancel all bubbles and active recognition sessions for this tab. | |
| 106 TabContents* tab_contents = Source<TabContents>(source).ptr(); | |
| 107 BubbleCallerIdMap::iterator iter = bubbles_.begin(); | |
| 108 while (iter != bubbles_.end()) { | |
| 109 if (iter->second->tab_contents() == tab_contents) { | |
| 110 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | |
| 111 NewRunnableMethod( | |
| 112 this, | |
| 113 &SpeechInputBubbleController::InvokeDelegateButtonClicked, | |
| 114 iter->first, SpeechInputBubble::BUTTON_CANCEL)); | |
| 115 CloseBubble(iter->first); | |
| 116 // We expect to have a very small number of items in this map so | |
| 117 // redo-ing from start is ok. | |
| 118 iter = bubbles_.begin(); | |
| 119 } else { | |
| 120 ++iter; | |
| 121 } | |
| 122 } | |
| 123 } else { | |
| 124 NOTREACHED() << "Unknown notification"; | |
| 125 } | |
| 126 } | |
| 127 | |
| 73 void SpeechInputBubbleController::ProcessRequestInUiThread( | 128 void SpeechInputBubbleController::ProcessRequestInUiThread( |
| 74 int caller_id, RequestType type, const string16& text, float volume) { | 129 int caller_id, RequestType type, const string16& text, float volume) { |
| 75 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { | 130 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { |
| 76 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, NewRunnableMethod( | 131 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, NewRunnableMethod( |
| 77 this, &SpeechInputBubbleController::ProcessRequestInUiThread, | 132 this, &SpeechInputBubbleController::ProcessRequestInUiThread, |
| 78 caller_id, type, text, volume)); | 133 caller_id, type, text, volume)); |
| 79 return; | 134 return; |
| 80 } | 135 } |
| 81 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 136 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 82 // The bubble may have been closed before we got a chance to process this | 137 // The bubble may have been closed before we got a chance to process this |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 102 break; | 157 break; |
| 103 case REQUEST_SET_MESSAGE: | 158 case REQUEST_SET_MESSAGE: |
| 104 bubble->SetMessage(text); | 159 bubble->SetMessage(text); |
| 105 break; | 160 break; |
| 106 case REQUEST_SET_INPUT_VOLUME: | 161 case REQUEST_SET_INPUT_VOLUME: |
| 107 bubble->SetInputVolume(volume); | 162 bubble->SetInputVolume(volume); |
| 108 break; | 163 break; |
| 109 case REQUEST_CLOSE: | 164 case REQUEST_CLOSE: |
| 110 if (current_bubble_caller_id_ == caller_id) | 165 if (current_bubble_caller_id_ == caller_id) |
| 111 current_bubble_caller_id_ = 0; | 166 current_bubble_caller_id_ = 0; |
| 167 // If this is the last bubble for this TabContents, unregister from | |
| 168 // close notifications. | |
| 169 if (IsOnlyBubbleForTab(caller_id)) { | |
| 170 registrar_->Remove(this, NotificationType::TAB_CONTENTS_DESTROYED, | |
| 171 Source<TabContents>(bubble->tab_contents())); | |
| 172 } | |
| 112 delete bubble; | 173 delete bubble; |
| 113 bubbles_.erase(caller_id); | 174 bubbles_.erase(caller_id); |
| 114 break; | 175 break; |
| 115 default: | 176 default: |
| 116 NOTREACHED(); | 177 NOTREACHED(); |
| 117 break; | 178 break; |
| 118 } | 179 } |
| 119 | 180 |
| 120 if (change_active_bubble) | 181 if (change_active_bubble) |
| 121 bubble->Show(); | 182 bubble->Show(); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 153 void SpeechInputBubbleController::InvokeDelegateButtonClicked( | 214 void SpeechInputBubbleController::InvokeDelegateButtonClicked( |
| 154 int caller_id, SpeechInputBubble::Button button) { | 215 int caller_id, SpeechInputBubble::Button button) { |
| 155 delegate_->InfoBubbleButtonClicked(caller_id, button); | 216 delegate_->InfoBubbleButtonClicked(caller_id, button); |
| 156 } | 217 } |
| 157 | 218 |
| 158 void SpeechInputBubbleController::InvokeDelegateFocusChanged(int caller_id) { | 219 void SpeechInputBubbleController::InvokeDelegateFocusChanged(int caller_id) { |
| 159 delegate_->InfoBubbleFocusChanged(caller_id); | 220 delegate_->InfoBubbleFocusChanged(caller_id); |
| 160 } | 221 } |
| 161 | 222 |
| 162 } // namespace speech_input | 223 } // namespace speech_input |
| OLD | NEW |