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

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: Created 8 years, 6 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_(),
31 current_bubble_render_view_id_() {
hans 2012/06/26 13:10:44 i'd prefer current_bubble_render_process_id_(0) in
Primiano Tucci (use gerrit) 2012/06/26 14:27:07 Done.
32 }
33
34 SpeechRecognitionBubbleController::~SpeechRecognitionBubbleController() {
35 DCHECK_EQ(kNoBubble, current_bubble_session_id_);
26 } 36 }
27 37
28 void SpeechRecognitionBubbleController::CreateBubble( 38 void SpeechRecognitionBubbleController::CreateBubble(
29 int session_id, 39 int session_id,
30 int render_process_id, 40 int render_process_id,
31 int render_view_id, 41 int render_view_id,
32 const gfx::Rect& element_rect) { 42 const gfx::Rect& element_rect) {
33 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { 43 BrowserThread::CurrentlyOn(BrowserThread::IO);
hans 2012/06/26 13:10:44 is this supposed to be in a DCHECK?
Primiano Tucci (use gerrit) 2012/06/26 14:27:07 Ops, yes! :)
34 BrowserThread::PostTask( 44 DCHECK_EQ(kNoBubble, current_bubble_session_id_);
35 BrowserThread::UI, FROM_HERE, 45 current_bubble_session_id_ = session_id;
36 base::Bind(&SpeechRecognitionBubbleController::CreateBubble, this, 46 current_bubble_render_process_id_ = render_process_id;
37 session_id, render_process_id, render_view_id, 47 current_bubble_render_view_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 }
79
80 void SpeechRecognitionBubbleController::SetBubbleMessage(int session_id,
81 const string16& text) {
82 ProcessRequestInUiThread(session_id, REQUEST_SET_MESSAGE, text, 0, 0);
83 } 68 }
84 69
85 void SpeechRecognitionBubbleController::SetBubbleInputVolume( 70 void SpeechRecognitionBubbleController::SetBubbleInputVolume(
86 int session_id, float volume, float noise_volume) { 71 float volume, float noise_volume) {
87 ProcessRequestInUiThread(session_id, REQUEST_SET_INPUT_VOLUME, string16(), 72 UIRequest request(REQUEST_SET_INPUT_VOLUME);
88 volume, noise_volume); 73 request.volume = volume;
74 request.noise_volume = noise_volume;
75 ProcessRequestInUiThread(request);
89 } 76 }
90 77
91 void SpeechRecognitionBubbleController::CloseBubble(int session_id) { 78 void SpeechRecognitionBubbleController::CloseBubble() {
92 ProcessRequestInUiThread(session_id, REQUEST_CLOSE, string16(), 0, 0); 79 current_bubble_session_id_ = kNoBubble;
80 ProcessRequestInUiThread(UIRequest(REQUEST_CLOSE));
81 }
82
83 int SpeechRecognitionBubbleController::GetActiveSessionID() {
84 return current_bubble_session_id_;
85 }
86
87 bool SpeechRecognitionBubbleController::IsShowingBubbleOn(int render_process_id,
88 int render_view_id) {
89 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
90 return (current_bubble_session_id_ != kNoBubble) &&
91 (current_bubble_render_process_id_ == render_process_id) &&
92 (current_bubble_render_view_id_ == render_view_id);
93 } 93 }
94 94
95 void SpeechRecognitionBubbleController::InfoBubbleButtonClicked( 95 void SpeechRecognitionBubbleController::InfoBubbleButtonClicked(
96 SpeechRecognitionBubble::Button button) { 96 SpeechRecognitionBubble::Button button) {
97 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 97 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
98 DCHECK(current_bubble_session_id_);
99
100 BrowserThread::PostTask( 98 BrowserThread::PostTask(
101 BrowserThread::IO, FROM_HERE, 99 BrowserThread::IO, FROM_HERE,
102 base::Bind( 100 base::Bind(
103 &SpeechRecognitionBubbleController::InvokeDelegateButtonClicked, 101 &SpeechRecognitionBubbleController::InvokeDelegateButtonClicked,
104 this, current_bubble_session_id_, button)); 102 this, button));
105 } 103 }
106 104
107 void SpeechRecognitionBubbleController::InfoBubbleFocusChanged() { 105 void SpeechRecognitionBubbleController::InfoBubbleFocusChanged() {
108 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 106 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( 107 BrowserThread::PostTask(
115 BrowserThread::IO, FROM_HERE, 108 BrowserThread::IO, FROM_HERE,
116 base::Bind( 109 base::Bind(
117 &SpeechRecognitionBubbleController::InvokeDelegateFocusChanged, 110 &SpeechRecognitionBubbleController::InvokeDelegateFocusChanged,
118 this, old_bubble_session_id)); 111 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 } 112 }
151 113
152 void SpeechRecognitionBubbleController::InvokeDelegateButtonClicked( 114 void SpeechRecognitionBubbleController::InvokeDelegateButtonClicked(
153 int session_id, SpeechRecognitionBubble::Button button) { 115 SpeechRecognitionBubble::Button button) {
154 delegate_->InfoBubbleButtonClicked(session_id, button); 116 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
117 DCHECK_NE(kNoBubble, current_bubble_session_id_);
118 delegate_->InfoBubbleButtonClicked(current_bubble_session_id_, button);
155 } 119 }
156 120
157 void SpeechRecognitionBubbleController::InvokeDelegateFocusChanged( 121 void SpeechRecognitionBubbleController::InvokeDelegateFocusChanged() {
158 int session_id) { 122 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
159 delegate_->InfoBubbleFocusChanged(session_id); 123 DCHECK_NE(kNoBubble, current_bubble_session_id_);
124 delegate_->InfoBubbleFocusChanged(current_bubble_session_id_);
160 } 125 }
161 126
162 void SpeechRecognitionBubbleController::ProcessRequestInUiThread( 127 void SpeechRecognitionBubbleController::ProcessRequestInUiThread(
163 int session_id, RequestType type, const string16& text, float volume, 128 const UIRequest& request) {
164 float noise_volume) {
165 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { 129 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
166 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind( 130 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
167 &SpeechRecognitionBubbleController::ProcessRequestInUiThread, this, 131 &SpeechRecognitionBubbleController::ProcessRequestInUiThread,
168 session_id, type, text, volume, noise_volume)); 132 this,
133 request));
169 return; 134 return;
170 } 135 }
136
171 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 137 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 138
177 bool change_active_bubble = (type == REQUEST_SET_WARM_UP_MODE || 139 switch (request.type) {
178 type == REQUEST_SET_MESSAGE); 140 case REQUEST_CREATE:
179 if (change_active_bubble) { 141 bubble_.reset(SpeechRecognitionBubble::Create(
180 if (current_bubble_session_id_ && current_bubble_session_id_ != session_id) 142 tab_util::GetWebContentsByID(request.render_process_id,
181 bubbles_[current_bubble_session_id_]->Hide(); 143 request.render_view_id),
182 current_bubble_session_id_ = session_id; 144 this,
183 } 145 request.element_rect));
184 146
185 SpeechRecognitionBubble* bubble = bubbles_[session_id]; 147 if (!bubble_.get()) {
186 switch (type) { 148 // Could be null if tab or display rect were invalid.
187 case REQUEST_SET_WARM_UP_MODE: 149 // Simulate the cancel button being clicked to inform the delegate.
188 bubble->SetWarmUpMode(); 150 BrowserThread::PostTask(
151 BrowserThread::IO, FROM_HERE, base::Bind(
152 &SpeechRecognitionBubbleController::InvokeDelegateButtonClicked,
153 this, SpeechRecognitionBubble::BUTTON_CANCEL));
154 return;
155 }
156 bubble_->Show();
157 bubble_->SetWarmUpMode();
189 break; 158 break;
190 case REQUEST_SET_RECORDING_MODE: 159 case REQUEST_SET_RECORDING_MODE:
191 bubble->SetRecordingMode(); 160 DCHECK(bubble_.get());
161 bubble_->SetRecordingMode();
192 break; 162 break;
193 case REQUEST_SET_RECOGNIZING_MODE: 163 case REQUEST_SET_RECOGNIZING_MODE:
194 bubble->SetRecognizingMode(); 164 DCHECK(bubble_.get());
165 bubble_->SetRecognizingMode();
195 break; 166 break;
196 case REQUEST_SET_MESSAGE: 167 case REQUEST_SET_MESSAGE:
197 bubble->SetMessage(text); 168 DCHECK(bubble_.get());
169 bubble_->SetMessage(request.message);
198 break; 170 break;
199 case REQUEST_SET_INPUT_VOLUME: 171 case REQUEST_SET_INPUT_VOLUME:
200 bubble->SetInputVolume(volume, noise_volume); 172 DCHECK(bubble_.get());
173 bubble_->SetInputVolume(request.volume, request.noise_volume);
201 break; 174 break;
202 case REQUEST_CLOSE: 175 case REQUEST_CLOSE:
203 if (current_bubble_session_id_ == session_id) 176 bubble_.reset();
204 current_bubble_session_id_ = 0;
205 UpdateTabContentsSubscription(session_id, BUBBLE_REMOVED);
206 delete bubble;
207 bubbles_.erase(session_id);
208 break; 177 break;
209 default: 178 default:
210 NOTREACHED(); 179 NOTREACHED();
211 break; 180 break;
212 } 181 }
213
214 if (change_active_bubble)
215 bubble->Show();
216 } 182 }
217 183
218 void SpeechRecognitionBubbleController::UpdateTabContentsSubscription( 184 SpeechRecognitionBubbleController::UIRequest::UIRequest(RequestType type_value)
219 int session_id, ManageSubscriptionAction action) { 185 : type(type_value),
220 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 186 volume(0.0F),
187 noise_volume(0.0F),
188 render_process_id(0),
189 render_view_id(0) {
190 }
221 191
222 // If there are any other bubbles existing for the same WebContents, we would 192 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 } 193 }
244 194
245 } // namespace speech 195 } // namespace speech
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698