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 UpdateTabContentsSubscription(caller_id, BUBBLE_ADDED); |
46 } | 52 } |
47 | 53 |
48 void SpeechInputBubbleController::CloseBubble(int caller_id) { | 54 void SpeechInputBubbleController::CloseBubble(int caller_id) { |
49 ProcessRequestInUiThread(caller_id, REQUEST_CLOSE, string16(), 0); | 55 ProcessRequestInUiThread(caller_id, REQUEST_CLOSE, string16(), 0); |
50 } | 56 } |
51 | 57 |
52 void SpeechInputBubbleController::SetBubbleRecordingMode(int caller_id) { | 58 void SpeechInputBubbleController::SetBubbleRecordingMode(int caller_id) { |
53 ProcessRequestInUiThread(caller_id, REQUEST_SET_RECORDING_MODE, | 59 ProcessRequestInUiThread(caller_id, REQUEST_SET_RECORDING_MODE, |
54 string16(), 0); | 60 string16(), 0); |
55 } | 61 } |
56 | 62 |
57 void SpeechInputBubbleController::SetBubbleRecognizingMode(int caller_id) { | 63 void SpeechInputBubbleController::SetBubbleRecognizingMode(int caller_id) { |
58 ProcessRequestInUiThread(caller_id, REQUEST_SET_RECOGNIZING_MODE, | 64 ProcessRequestInUiThread(caller_id, REQUEST_SET_RECOGNIZING_MODE, |
59 string16(), 0); | 65 string16(), 0); |
60 } | 66 } |
61 | 67 |
62 void SpeechInputBubbleController::SetBubbleInputVolume(int caller_id, | 68 void SpeechInputBubbleController::SetBubbleInputVolume(int caller_id, |
63 float volume) { | 69 float volume) { |
64 ProcessRequestInUiThread(caller_id, REQUEST_SET_INPUT_VOLUME, string16(), | 70 ProcessRequestInUiThread(caller_id, REQUEST_SET_INPUT_VOLUME, string16(), |
65 volume); | 71 volume); |
66 } | 72 } |
67 | 73 |
68 void SpeechInputBubbleController::SetBubbleMessage(int caller_id, | 74 void SpeechInputBubbleController::SetBubbleMessage(int caller_id, |
69 const string16& text) { | 75 const string16& text) { |
70 ProcessRequestInUiThread(caller_id, REQUEST_SET_MESSAGE, text, 0); | 76 ProcessRequestInUiThread(caller_id, REQUEST_SET_MESSAGE, text, 0); |
71 } | 77 } |
72 | 78 |
| 79 void SpeechInputBubbleController::UpdateTabContentsSubscription( |
| 80 int caller_id, ManageSubscriptionAction action) { |
| 81 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 82 |
| 83 // If there are any other bubbles existing for the same TabContents, we would |
| 84 // have subscribed to tab close notifications on their behalf and we need to |
| 85 // stay registered. So we don't change the subscription in such cases. |
| 86 TabContents* tab_contents = bubbles_[caller_id]->tab_contents(); |
| 87 for (BubbleCallerIdMap::iterator iter = bubbles_.begin(); |
| 88 iter != bubbles_.end(); ++iter) { |
| 89 if (iter->second->tab_contents() == tab_contents && |
| 90 iter->first != caller_id) { |
| 91 // At least one other bubble exists for the same TabContents. So don't |
| 92 // make any change to the subscription. |
| 93 return; |
| 94 } |
| 95 } |
| 96 |
| 97 if (action == BUBBLE_ADDED) { |
| 98 registrar_->Add(this, NotificationType::TAB_CONTENTS_DESTROYED, |
| 99 Source<TabContents>(tab_contents)); |
| 100 } else { |
| 101 registrar_->Remove(this, NotificationType::TAB_CONTENTS_DESTROYED, |
| 102 Source<TabContents>(tab_contents)); |
| 103 } |
| 104 } |
| 105 |
| 106 void SpeechInputBubbleController::Observe(NotificationType type, |
| 107 const NotificationSource& source, |
| 108 const NotificationDetails& details) { |
| 109 if (type == NotificationType::TAB_CONTENTS_DESTROYED) { |
| 110 // Cancel all bubbles and active recognition sessions for this tab. |
| 111 TabContents* tab_contents = Source<TabContents>(source).ptr(); |
| 112 BubbleCallerIdMap::iterator iter = bubbles_.begin(); |
| 113 while (iter != bubbles_.end()) { |
| 114 if (iter->second->tab_contents() == tab_contents) { |
| 115 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
| 116 NewRunnableMethod( |
| 117 this, |
| 118 &SpeechInputBubbleController::InvokeDelegateButtonClicked, |
| 119 iter->first, SpeechInputBubble::BUTTON_CANCEL)); |
| 120 CloseBubble(iter->first); |
| 121 // We expect to have a very small number of items in this map so |
| 122 // redo-ing from start is ok. |
| 123 iter = bubbles_.begin(); |
| 124 } else { |
| 125 ++iter; |
| 126 } |
| 127 } |
| 128 } else { |
| 129 NOTREACHED() << "Unknown notification"; |
| 130 } |
| 131 } |
| 132 |
73 void SpeechInputBubbleController::ProcessRequestInUiThread( | 133 void SpeechInputBubbleController::ProcessRequestInUiThread( |
74 int caller_id, RequestType type, const string16& text, float volume) { | 134 int caller_id, RequestType type, const string16& text, float volume) { |
75 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { | 135 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { |
76 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, NewRunnableMethod( | 136 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, NewRunnableMethod( |
77 this, &SpeechInputBubbleController::ProcessRequestInUiThread, | 137 this, &SpeechInputBubbleController::ProcessRequestInUiThread, |
78 caller_id, type, text, volume)); | 138 caller_id, type, text, volume)); |
79 return; | 139 return; |
80 } | 140 } |
81 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 141 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
82 // The bubble may have been closed before we got a chance to process this | 142 // The bubble may have been closed before we got a chance to process this |
(...skipping 19 matching lines...) Expand all Loading... |
102 break; | 162 break; |
103 case REQUEST_SET_MESSAGE: | 163 case REQUEST_SET_MESSAGE: |
104 bubble->SetMessage(text); | 164 bubble->SetMessage(text); |
105 break; | 165 break; |
106 case REQUEST_SET_INPUT_VOLUME: | 166 case REQUEST_SET_INPUT_VOLUME: |
107 bubble->SetInputVolume(volume); | 167 bubble->SetInputVolume(volume); |
108 break; | 168 break; |
109 case REQUEST_CLOSE: | 169 case REQUEST_CLOSE: |
110 if (current_bubble_caller_id_ == caller_id) | 170 if (current_bubble_caller_id_ == caller_id) |
111 current_bubble_caller_id_ = 0; | 171 current_bubble_caller_id_ = 0; |
| 172 UpdateTabContentsSubscription(caller_id, BUBBLE_REMOVED); |
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 |