Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(290)

Side by Side Diff: chrome/browser/speech/speech_recognition_bubble_controller.cc

Issue 10663018: Changing tab closure handling logic in speech recognition code and cleaning bubble controller. (Spe… (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Slight refactor to fix a bug on mac + rebase Created 8 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 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_recognition_bubble_controller.h" 5 #include "chrome/browser/speech/speech_recognition_bubble_controller.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "chrome/browser/tab_contents/tab_util.h" 8 #include "chrome/browser/tab_contents/tab_util.h"
9 #include "content/public/browser/browser_thread.h" 9 #include "content/public/browser/browser_thread.h"
10 #include "content/public/browser/notification_registrar.h" 10 #include "content/public/browser/notification_registrar.h"
11 #include "content/public/browser/notification_source.h" 11 #include "content/public/browser/notification_source.h"
12 #include "content/public/browser/notification_types.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"
13 #include "content/public/browser/web_contents.h" 15 #include "content/public/browser/web_contents.h"
14 #include "ui/gfx/rect.h"
15 16
16 using content::BrowserThread; 17 using content::BrowserThread;
17 using content::WebContents; 18 using content::WebContents;
18 19
20 namespace {
21 const int kNoBubble = 0;
22 }
23
19 namespace speech { 24 namespace speech {
20 25
21 SpeechRecognitionBubbleController::SpeechRecognitionBubbleController( 26 SpeechRecognitionBubbleController::SpeechRecognitionBubbleController(
22 Delegate* delegate) 27 Delegate* delegate)
23 : delegate_(delegate), 28 : delegate_(delegate),
24 current_bubble_session_id_(0), 29 current_bubble_session_id_(kNoBubble),
25 registrar_(new content::NotificationRegistrar) { 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(kNoBubble, current_bubble_session_id_);
26 } 37 }
27 38
28 void SpeechRecognitionBubbleController::CreateBubble( 39 void SpeechRecognitionBubbleController::CreateBubble(
29 int session_id, 40 int session_id,
30 int render_process_id, 41 int render_process_id,
31 int render_view_id, 42 int render_view_id,
32 const gfx::Rect& element_rect) { 43 const gfx::Rect& element_rect) {
33 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { 44 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
34 BrowserThread::PostTask( 45 current_bubble_session_id_ = session_id;
35 BrowserThread::UI, FROM_HERE, 46 current_bubble_render_process_id_ = render_process_id;
36 base::Bind(&SpeechRecognitionBubbleController::CreateBubble, this, 47 current_bubble_render_view_id_ = render_view_id;
37 session_id, render_process_id, render_view_id,
38 element_rect));
39 return;
40 }
41 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
42 WebContents* web_contents = tab_util::GetWebContentsByID(render_process_id,
43 render_view_id);
44 48
45 DCHECK_EQ(0u, bubbles_.count(session_id)); 49 UIRequest request(REQUEST_CREATE);
46 SpeechRecognitionBubble* bubble = SpeechRecognitionBubble::Create( 50 request.render_process_id = render_process_id;
47 web_contents, this, element_rect); 51 request.render_view_id = render_view_id;
48 if (!bubble) { 52 request.element_rect = element_rect;
49 // Could be null if tab or display rect were invalid. 53 ProcessRequestInUiThread(request);
50 // Simulate the cancel button being clicked to inform the delegate.
51 BrowserThread::PostTask(
52 BrowserThread::IO, FROM_HERE,
53 base::Bind(
54 &SpeechRecognitionBubbleController::InvokeDelegateButtonClicked,
55 this, session_id, SpeechRecognitionBubble::BUTTON_CANCEL));
56 return;
57 }
58
59 bubbles_[session_id] = bubble;
60
61 UpdateTabContentsSubscription(session_id, BUBBLE_ADDED);
62 } 54 }
63 55
64 void SpeechRecognitionBubbleController::SetBubbleWarmUpMode(int session_id) { 56 void SpeechRecognitionBubbleController::SetBubbleRecordingMode() {
65 ProcessRequestInUiThread(session_id, REQUEST_SET_WARM_UP_MODE, 57 ProcessRequestInUiThread(UIRequest(REQUEST_SET_RECORDING_MODE));
66 string16(), 0, 0);
67 } 58 }
68 59
69 void SpeechRecognitionBubbleController::SetBubbleRecordingMode(int session_id) { 60 void SpeechRecognitionBubbleController::SetBubbleRecognizingMode() {
70 ProcessRequestInUiThread(session_id, REQUEST_SET_RECORDING_MODE, 61 ProcessRequestInUiThread(UIRequest(REQUEST_SET_RECOGNIZING_MODE));
71 string16(), 0, 0);
72 } 62 }
73 63
74 void SpeechRecognitionBubbleController::SetBubbleRecognizingMode( 64 void SpeechRecognitionBubbleController::SetBubbleMessage(const string16& text) {
75 int session_id) { 65 UIRequest request(REQUEST_SET_MESSAGE);
76 ProcessRequestInUiThread(session_id, REQUEST_SET_RECOGNIZING_MODE, 66 request.message = text;
77 string16(), 0, 0); 67 ProcessRequestInUiThread(request);
78 } 68 }
79 69
80 void SpeechRecognitionBubbleController::SetBubbleMessage(int session_id, 70 bool SpeechRecognitionBubbleController::IsShowingMessage() const {
81 const string16& text) { 71 return last_request_issued_ == REQUEST_SET_MESSAGE;
82 ProcessRequestInUiThread(session_id, REQUEST_SET_MESSAGE, text, 0, 0);
83 } 72 }
84 73
85 void SpeechRecognitionBubbleController::SetBubbleInputVolume( 74 void SpeechRecognitionBubbleController::SetBubbleInputVolume(
86 int session_id, float volume, float noise_volume) { 75 float volume, float noise_volume) {
87 ProcessRequestInUiThread(session_id, REQUEST_SET_INPUT_VOLUME, string16(), 76 UIRequest request(REQUEST_SET_INPUT_VOLUME);
88 volume, noise_volume); 77 request.volume = volume;
78 request.noise_volume = noise_volume;
79 ProcessRequestInUiThread(request);
89 } 80 }
90 81
91 void SpeechRecognitionBubbleController::CloseBubble(int session_id) { 82 void SpeechRecognitionBubbleController::CloseBubble() {
92 ProcessRequestInUiThread(session_id, REQUEST_CLOSE, string16(), 0, 0); 83 current_bubble_session_id_ = kNoBubble;
84 ProcessRequestInUiThread(UIRequest(REQUEST_CLOSE));
85 }
86
87 int SpeechRecognitionBubbleController::GetActiveSessionID() const {
88 return current_bubble_session_id_;
89 }
90
91 bool SpeechRecognitionBubbleController::IsShowingBubbleOn(int render_process_id,
92 int render_view_id) {
93 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
94 return (current_bubble_session_id_ != kNoBubble) &&
95 (current_bubble_render_process_id_ == render_process_id) &&
96 (current_bubble_render_view_id_ == render_view_id);
93 } 97 }
94 98
95 void SpeechRecognitionBubbleController::InfoBubbleButtonClicked( 99 void SpeechRecognitionBubbleController::InfoBubbleButtonClicked(
96 SpeechRecognitionBubble::Button button) { 100 SpeechRecognitionBubble::Button button) {
97 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 101 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
98 DCHECK(current_bubble_session_id_);
99
100 BrowserThread::PostTask( 102 BrowserThread::PostTask(
101 BrowserThread::IO, FROM_HERE, 103 BrowserThread::IO, FROM_HERE,
102 base::Bind( 104 base::Bind(
103 &SpeechRecognitionBubbleController::InvokeDelegateButtonClicked, 105 &SpeechRecognitionBubbleController::InvokeDelegateButtonClicked,
104 this, current_bubble_session_id_, button)); 106 this, button));
105 } 107 }
106 108
107 void SpeechRecognitionBubbleController::InfoBubbleFocusChanged() { 109 void SpeechRecognitionBubbleController::InfoBubbleFocusChanged() {
108 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 110 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
109 DCHECK(current_bubble_session_id_);
110
111 int old_bubble_session_id = current_bubble_session_id_;
112 current_bubble_session_id_ = 0;
113
114 BrowserThread::PostTask( 111 BrowserThread::PostTask(
115 BrowserThread::IO, FROM_HERE, 112 BrowserThread::IO, FROM_HERE,
116 base::Bind( 113 base::Bind(
117 &SpeechRecognitionBubbleController::InvokeDelegateFocusChanged, 114 &SpeechRecognitionBubbleController::InvokeDelegateFocusChanged,
118 this, old_bubble_session_id)); 115 this));
119 }
120
121 void SpeechRecognitionBubbleController::Observe(
122 int type,
123 const content::NotificationSource& source,
124 const content::NotificationDetails& details) {
125 if (type == content::NOTIFICATION_WEB_CONTENTS_DESTROYED) {
126 // Cancel all bubbles and active recognition sessions for this tab.
127 WebContents* web_contents = content::Source<WebContents>(source).ptr();
128 BubbleSessionIdMap::iterator iter = bubbles_.begin();
129 while (iter != bubbles_.end()) {
130 if (iter->second->GetWebContents() == web_contents) {
131 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
132 base::Bind(
133 &SpeechRecognitionBubbleController::InvokeDelegateButtonClicked,
134 this, iter->first, SpeechRecognitionBubble::BUTTON_CANCEL));
135 CloseBubble(iter->first);
136 // We expect to have a very small number of items in this map so
137 // redo-ing from start is ok.
138 iter = bubbles_.begin();
139 } else {
140 ++iter;
141 }
142 }
143 } else {
144 NOTREACHED() << "Unknown notification";
145 }
146 }
147
148 SpeechRecognitionBubbleController::~SpeechRecognitionBubbleController() {
149 DCHECK(bubbles_.empty());
150 } 116 }
151 117
152 void SpeechRecognitionBubbleController::InvokeDelegateButtonClicked( 118 void SpeechRecognitionBubbleController::InvokeDelegateButtonClicked(
153 int session_id, SpeechRecognitionBubble::Button button) { 119 SpeechRecognitionBubble::Button button) {
154 delegate_->InfoBubbleButtonClicked(session_id, button); 120 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
121 DCHECK_NE(kNoBubble, current_bubble_session_id_);
122 delegate_->InfoBubbleButtonClicked(current_bubble_session_id_, button);
155 } 123 }
156 124
157 void SpeechRecognitionBubbleController::InvokeDelegateFocusChanged( 125 void SpeechRecognitionBubbleController::InvokeDelegateFocusChanged() {
158 int session_id) { 126 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
159 delegate_->InfoBubbleFocusChanged(session_id); 127 DCHECK_NE(kNoBubble, current_bubble_session_id_);
128 delegate_->InfoBubbleFocusChanged(current_bubble_session_id_);
160 } 129 }
161 130
162 void SpeechRecognitionBubbleController::ProcessRequestInUiThread( 131 void SpeechRecognitionBubbleController::ProcessRequestInUiThread(
163 int session_id, RequestType type, const string16& text, float volume, 132 const UIRequest& request) {
164 float noise_volume) {
165 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { 133 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
134 last_request_issued_ = request.type;
166 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind( 135 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
167 &SpeechRecognitionBubbleController::ProcessRequestInUiThread, this, 136 &SpeechRecognitionBubbleController::ProcessRequestInUiThread,
168 session_id, type, text, volume, noise_volume)); 137 this,
138 request));
169 return; 139 return;
170 } 140 }
141
171 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 142 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
172 // The bubble may have been closed before we got a chance to process this
173 // request. So check before proceeding.
174 if (!bubbles_.count(session_id))
175 return;
176 143
177 bool change_active_bubble = (type == REQUEST_SET_WARM_UP_MODE || 144 switch (request.type) {
178 type == REQUEST_SET_MESSAGE); 145 case REQUEST_CREATE:
179 if (change_active_bubble) { 146 bubble_.reset(SpeechRecognitionBubble::Create(
180 if (current_bubble_session_id_ && current_bubble_session_id_ != session_id) 147 tab_util::GetWebContentsByID(request.render_process_id,
181 bubbles_[current_bubble_session_id_]->Hide(); 148 request.render_view_id),
182 current_bubble_session_id_ = session_id; 149 this,
183 } 150 request.element_rect));
184 151
185 SpeechRecognitionBubble* bubble = bubbles_[session_id]; 152 if (!bubble_.get()) {
186 switch (type) { 153 // Could be null if tab or display rect were invalid.
187 case REQUEST_SET_WARM_UP_MODE: 154 // Simulate the cancel button being clicked to inform the delegate.
188 bubble->SetWarmUpMode(); 155 BrowserThread::PostTask(
156 BrowserThread::IO, FROM_HERE, base::Bind(
157 &SpeechRecognitionBubbleController::InvokeDelegateButtonClicked,
158 this, SpeechRecognitionBubble::BUTTON_CANCEL));
159 return;
160 }
161 bubble_->Show();
162 bubble_->SetWarmUpMode();
189 break; 163 break;
190 case REQUEST_SET_RECORDING_MODE: 164 case REQUEST_SET_RECORDING_MODE:
191 bubble->SetRecordingMode(); 165 DCHECK(bubble_.get());
166 bubble_->SetRecordingMode();
192 break; 167 break;
193 case REQUEST_SET_RECOGNIZING_MODE: 168 case REQUEST_SET_RECOGNIZING_MODE:
194 bubble->SetRecognizingMode(); 169 DCHECK(bubble_.get());
170 bubble_->SetRecognizingMode();
195 break; 171 break;
196 case REQUEST_SET_MESSAGE: 172 case REQUEST_SET_MESSAGE:
197 bubble->SetMessage(text); 173 DCHECK(bubble_.get());
174 bubble_->SetMessage(request.message);
198 break; 175 break;
199 case REQUEST_SET_INPUT_VOLUME: 176 case REQUEST_SET_INPUT_VOLUME:
200 bubble->SetInputVolume(volume, noise_volume); 177 DCHECK(bubble_.get());
178 bubble_->SetInputVolume(request.volume, request.noise_volume);
201 break; 179 break;
202 case REQUEST_CLOSE: 180 case REQUEST_CLOSE:
203 if (current_bubble_session_id_ == session_id) 181 bubble_.reset();
204 current_bubble_session_id_ = 0;
205 UpdateTabContentsSubscription(session_id, BUBBLE_REMOVED);
206 delete bubble;
207 bubbles_.erase(session_id);
208 break; 182 break;
209 default: 183 default:
210 NOTREACHED(); 184 NOTREACHED();
211 break; 185 break;
212 } 186 }
213
214 if (change_active_bubble)
215 bubble->Show();
216 } 187 }
217 188
218 void SpeechRecognitionBubbleController::UpdateTabContentsSubscription( 189 SpeechRecognitionBubbleController::UIRequest::UIRequest(RequestType type_value)
219 int session_id, ManageSubscriptionAction action) { 190 : type(type_value),
220 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 191 volume(0.0F),
192 noise_volume(0.0F),
193 render_process_id(0),
194 render_view_id(0) {
195 }
221 196
222 // If there are any other bubbles existing for the same WebContents, we would 197 SpeechRecognitionBubbleController::UIRequest::~UIRequest() {
223 // have subscribed to tab close notifications on their behalf and we need to
224 // stay registered. So we don't change the subscription in such cases.
225 WebContents* web_contents = bubbles_[session_id]->GetWebContents();
226 for (BubbleSessionIdMap::iterator iter = bubbles_.begin();
227 iter != bubbles_.end(); ++iter) {
228 if (iter->second->GetWebContents() == web_contents &&
229 iter->first != session_id) {
230 // At least one other bubble exists for the same WebContents. So don't
231 // make any change to the subscription.
232 return;
233 }
234 }
235
236 if (action == BUBBLE_ADDED) {
237 registrar_->Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
238 content::Source<WebContents>(web_contents));
239 } else {
240 registrar_->Remove(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
241 content::Source<WebContents>(web_contents));
242 }
243 } 198 }
244 199
245 } // namespace speech 200 } // namespace speech
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698