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

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: Moved TabWatcher as a private class in chrome_speech_recognition_manager_delegate.cc 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 kInvalidSessionId = 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_(kInvalidSessionId),
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(kInvalidSessionId, 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 current_bubble_session_id_ = session_id;
34 BrowserThread::PostTask( 45 current_bubble_render_process_id_ = render_process_id;
35 BrowserThread::UI, FROM_HERE, 46 current_bubble_render_view_id_ = render_view_id;
36 base::Bind(&SpeechRecognitionBubbleController::CreateBubble, this,
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 47
45 DCHECK_EQ(0u, bubbles_.count(session_id)); 48 UIRequest request(REQUEST_CREATE);
46 SpeechRecognitionBubble* bubble = SpeechRecognitionBubble::Create( 49 request.render_process_id = render_process_id;
47 web_contents, this, element_rect); 50 request.render_view_id = render_view_id;
48 if (!bubble) { 51 request.element_rect = element_rect;
49 // Could be null if tab or display rect were invalid. 52 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 } 53 }
63 54
64 void SpeechRecognitionBubbleController::SetBubbleWarmUpMode(int session_id) { 55 void SpeechRecognitionBubbleController::SetBubbleRecordingMode() {
65 ProcessRequestInUiThread(session_id, REQUEST_SET_WARM_UP_MODE, 56 ProcessRequestInUiThread(UIRequest(REQUEST_SET_RECORDING_MODE));
66 string16(), 0, 0);
67 } 57 }
68 58
69 void SpeechRecognitionBubbleController::SetBubbleRecordingMode(int session_id) { 59 void SpeechRecognitionBubbleController::SetBubbleRecognizingMode() {
70 ProcessRequestInUiThread(session_id, REQUEST_SET_RECORDING_MODE, 60 ProcessRequestInUiThread(UIRequest(REQUEST_SET_RECOGNIZING_MODE));
71 string16(), 0, 0);
72 } 61 }
73 62
74 void SpeechRecognitionBubbleController::SetBubbleRecognizingMode( 63 void SpeechRecognitionBubbleController::SetBubbleMessage(const string16& text) {
75 int session_id) { 64 UIRequest request(REQUEST_SET_MESSAGE);
76 ProcessRequestInUiThread(session_id, REQUEST_SET_RECOGNIZING_MODE, 65 request.message = text;
77 string16(), 0, 0); 66 ProcessRequestInUiThread(request);
78 } 67 }
79 68
80 void SpeechRecognitionBubbleController::SetBubbleMessage(int session_id, 69 bool SpeechRecognitionBubbleController::IsShowingMessage() const {
81 const string16& text) { 70 return last_request_issued_ == REQUEST_SET_MESSAGE;
82 ProcessRequestInUiThread(session_id, REQUEST_SET_MESSAGE, text, 0, 0);
83 } 71 }
84 72
85 void SpeechRecognitionBubbleController::SetBubbleInputVolume( 73 void SpeechRecognitionBubbleController::SetBubbleInputVolume(
86 int session_id, float volume, float noise_volume) { 74 float volume, float noise_volume) {
87 ProcessRequestInUiThread(session_id, REQUEST_SET_INPUT_VOLUME, string16(), 75 UIRequest request(REQUEST_SET_INPUT_VOLUME);
88 volume, noise_volume); 76 request.volume = volume;
77 request.noise_volume = noise_volume;
78 ProcessRequestInUiThread(request);
89 } 79 }
90 80
91 void SpeechRecognitionBubbleController::CloseBubble(int session_id) { 81 void SpeechRecognitionBubbleController::CloseBubble() {
92 ProcessRequestInUiThread(session_id, REQUEST_CLOSE, string16(), 0, 0); 82 current_bubble_session_id_ = kInvalidSessionId;
83 ProcessRequestInUiThread(UIRequest(REQUEST_CLOSE));
84 }
85
86 int SpeechRecognitionBubbleController::GetActiveSessionID() const {
87 return current_bubble_session_id_;
88 }
89
90 bool SpeechRecognitionBubbleController::IsShowingBubbleForRenderView(
91 int render_process_id, int render_view_id) {
92 return (current_bubble_session_id_ != kInvalidSessionId) &&
93 (current_bubble_render_process_id_ == render_process_id) &&
94 (current_bubble_render_view_id_ == render_view_id);
93 } 95 }
94 96
95 void SpeechRecognitionBubbleController::InfoBubbleButtonClicked( 97 void SpeechRecognitionBubbleController::InfoBubbleButtonClicked(
96 SpeechRecognitionBubble::Button button) { 98 SpeechRecognitionBubble::Button button) {
97 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 99 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
98 DCHECK(current_bubble_session_id_);
99
100 BrowserThread::PostTask( 100 BrowserThread::PostTask(
101 BrowserThread::IO, FROM_HERE, 101 BrowserThread::IO, FROM_HERE,
102 base::Bind( 102 base::Bind(
103 &SpeechRecognitionBubbleController::InvokeDelegateButtonClicked, 103 &SpeechRecognitionBubbleController::InvokeDelegateButtonClicked,
104 this, current_bubble_session_id_, button)); 104 this, button));
105 } 105 }
106 106
107 void SpeechRecognitionBubbleController::InfoBubbleFocusChanged() { 107 void SpeechRecognitionBubbleController::InfoBubbleFocusChanged() {
108 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 108 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( 109 BrowserThread::PostTask(
115 BrowserThread::IO, FROM_HERE, 110 BrowserThread::IO, FROM_HERE,
116 base::Bind( 111 base::Bind(
117 &SpeechRecognitionBubbleController::InvokeDelegateFocusChanged, 112 &SpeechRecognitionBubbleController::InvokeDelegateFocusChanged,
118 this, old_bubble_session_id)); 113 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 } 114 }
151 115
152 void SpeechRecognitionBubbleController::InvokeDelegateButtonClicked( 116 void SpeechRecognitionBubbleController::InvokeDelegateButtonClicked(
153 int session_id, SpeechRecognitionBubble::Button button) { 117 SpeechRecognitionBubble::Button button) {
154 delegate_->InfoBubbleButtonClicked(session_id, button); 118 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
119 DCHECK_NE(kInvalidSessionId, current_bubble_session_id_);
120 delegate_->InfoBubbleButtonClicked(current_bubble_session_id_, button);
155 } 121 }
156 122
157 void SpeechRecognitionBubbleController::InvokeDelegateFocusChanged( 123 void SpeechRecognitionBubbleController::InvokeDelegateFocusChanged() {
158 int session_id) { 124 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
159 delegate_->InfoBubbleFocusChanged(session_id); 125 DCHECK_NE(kInvalidSessionId, current_bubble_session_id_);
126 delegate_->InfoBubbleFocusChanged(current_bubble_session_id_);
160 } 127 }
161 128
162 void SpeechRecognitionBubbleController::ProcessRequestInUiThread( 129 void SpeechRecognitionBubbleController::ProcessRequestInUiThread(
163 int session_id, RequestType type, const string16& text, float volume, 130 const UIRequest& request) {
164 float noise_volume) {
165 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { 131 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
132 last_request_issued_ = request.type;
166 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind( 133 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
167 &SpeechRecognitionBubbleController::ProcessRequestInUiThread, this, 134 &SpeechRecognitionBubbleController::ProcessRequestInUiThread,
168 session_id, type, text, volume, noise_volume)); 135 this,
136 request));
169 return; 137 return;
170 } 138 }
139
171 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 140 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 141
177 bool change_active_bubble = (type == REQUEST_SET_WARM_UP_MODE || 142 switch (request.type) {
178 type == REQUEST_SET_MESSAGE); 143 case REQUEST_CREATE:
179 if (change_active_bubble) { 144 bubble_.reset(SpeechRecognitionBubble::Create(
180 if (current_bubble_session_id_ && current_bubble_session_id_ != session_id) 145 tab_util::GetWebContentsByID(request.render_process_id,
181 bubbles_[current_bubble_session_id_]->Hide(); 146 request.render_view_id),
182 current_bubble_session_id_ = session_id; 147 this,
183 } 148 request.element_rect));
184 149
185 SpeechRecognitionBubble* bubble = bubbles_[session_id]; 150 if (!bubble_.get()) {
186 switch (type) { 151 // Could be null if tab or display rect were invalid.
187 case REQUEST_SET_WARM_UP_MODE: 152 // Simulate the cancel button being clicked to inform the delegate.
188 bubble->SetWarmUpMode(); 153 BrowserThread::PostTask(
154 BrowserThread::IO, FROM_HERE, base::Bind(
155 &SpeechRecognitionBubbleController::InvokeDelegateButtonClicked,
156 this, SpeechRecognitionBubble::BUTTON_CANCEL));
157 return;
158 }
159 bubble_->Show();
160 bubble_->SetWarmUpMode();
189 break; 161 break;
190 case REQUEST_SET_RECORDING_MODE: 162 case REQUEST_SET_RECORDING_MODE:
191 bubble->SetRecordingMode(); 163 DCHECK(bubble_.get());
164 bubble_->SetRecordingMode();
192 break; 165 break;
193 case REQUEST_SET_RECOGNIZING_MODE: 166 case REQUEST_SET_RECOGNIZING_MODE:
194 bubble->SetRecognizingMode(); 167 DCHECK(bubble_.get());
168 bubble_->SetRecognizingMode();
195 break; 169 break;
196 case REQUEST_SET_MESSAGE: 170 case REQUEST_SET_MESSAGE:
197 bubble->SetMessage(text); 171 DCHECK(bubble_.get());
172 bubble_->SetMessage(request.message);
198 break; 173 break;
199 case REQUEST_SET_INPUT_VOLUME: 174 case REQUEST_SET_INPUT_VOLUME:
200 bubble->SetInputVolume(volume, noise_volume); 175 DCHECK(bubble_.get());
176 bubble_->SetInputVolume(request.volume, request.noise_volume);
201 break; 177 break;
202 case REQUEST_CLOSE: 178 case REQUEST_CLOSE:
203 if (current_bubble_session_id_ == session_id) 179 bubble_.reset();
204 current_bubble_session_id_ = 0;
205 UpdateTabContentsSubscription(session_id, BUBBLE_REMOVED);
206 delete bubble;
207 bubbles_.erase(session_id);
208 break; 180 break;
209 default: 181 default:
210 NOTREACHED(); 182 NOTREACHED();
211 break; 183 break;
212 } 184 }
213
214 if (change_active_bubble)
215 bubble->Show();
216 } 185 }
217 186
218 void SpeechRecognitionBubbleController::UpdateTabContentsSubscription( 187 SpeechRecognitionBubbleController::UIRequest::UIRequest(RequestType type_value)
219 int session_id, ManageSubscriptionAction action) { 188 : type(type_value),
220 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 189 volume(0.0F),
190 noise_volume(0.0F),
191 render_process_id(0),
192 render_view_id(0) {
193 }
221 194
222 // If there are any other bubbles existing for the same WebContents, we would 195 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 } 196 }
244 197
245 } // namespace speech 198 } // namespace speech
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698