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

Side by Side Diff: chrome/browser/media/media_stream_capture_indicator.cc

Issue 10168008: Show camera and microphone status indicators. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: updated the media_stream_dispatcher_unittest Created 8 years, 7 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
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "chrome/browser/media/media_stream_capture_indicator.h"
6
7 #include "base/bind.h"
8 #include "base/i18n/rtl.h"
9 #include "base/utf_string_conversions.h"
10 #include "chrome/app/chrome_command_ids.h"
11 #include "chrome/browser/browser_process.h"
12 #include "chrome/browser/status_icons/status_icon.h"
13 #include "chrome/browser/status_icons/status_tray.h"
14 #include "chrome/browser/tab_contents/tab_util.h"
15 #include "content/public/browser/browser_thread.h"
16 #include "content/public/browser/web_contents.h"
17 #include "grit/chromium_strings.h"
18 #include "grit/generated_resources.h"
19 #include "grit/theme_resources.h"
20 #include "ui/base/l10n/l10n_util.h"
21 #include "ui/base/resource/resource_bundle.h"
22
23 using content::BrowserThread;
24 using content::WebContents;
25
26 MediaStreamCaptureIndicator::TabEquals::TabEquals(
27 int render_process_id,
28 int render_view_id,
29 content::MediaStreamDeviceType type)
30 : render_process_id_(render_process_id),
31 render_view_id_(render_view_id),
32 type_(type) {}
33
34 MediaStreamCaptureIndicator::TabEquals::TabEquals(int render_process_id,
35 int render_view_id)
36 : render_process_id_(render_process_id),
37 render_view_id_(render_view_id),
38 type_(content::MEDIA_STREAM_DEVICE_TYPE_NO_SERVICE) {}
39
40 bool MediaStreamCaptureIndicator::TabEquals::operator() (
41 const MediaStreamCaptureIndicator::CaptureDeviceTab& tab) {
42 if (type_ == content::MEDIA_STREAM_DEVICE_TYPE_NO_SERVICE) {
43 return (render_process_id_ == tab.render_process_id &&
44 render_view_id_ == tab.render_view_id);
45 } else {
46 return (render_process_id_ == tab.render_process_id &&
47 render_view_id_ == tab.render_view_id &&
48 type_ == tab.type);
49 }
50 }
51
52 MediaStreamCaptureIndicator::MediaStreamCaptureIndicator()
53 : status_icon_(NULL) {
54 }
55
56 MediaStreamCaptureIndicator::~MediaStreamCaptureIndicator() {
57 // The user is responsible for cleaning up by closing all the opened devices.
58 DCHECK(tabs_.empty());
59 }
60
61 bool MediaStreamCaptureIndicator::IsCommandIdChecked(
62 int command_id) const {
63 NOTIMPLEMENTED() << "There are no checked items in the MediaStream menu.";
64 return false;
65 }
66
67 bool MediaStreamCaptureIndicator::IsCommandIdEnabled(
68 int command_id) const {
69 return command_id != IDC_MinimumLabelValue;
70 }
71
72 bool MediaStreamCaptureIndicator::GetAcceleratorForCommandId(
73 int command_id, ui::Accelerator* accelerator) {
74 // No accelerators for status icon context menu.
75 return false;
76 }
77
78 void MediaStreamCaptureIndicator::ExecuteCommand(int command_id) {
79 // TODO(xians) : Implement all the following execute command function.
80 switch (command_id) {
81 case IDC_MEDIA_CONTEXT_MEDIA_STREAM_CAPTURE_LIST_FIRST:
82 break;
83 default:
84 NOTREACHED();
85 break;
86 }
87 }
88
89 void MediaStreamCaptureIndicator::CaptureDevicesOpened(
90 int render_process_id,
91 int render_view_id,
92 const content::MediaStreamDevices& devices) {
93 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
94 DCHECK(!devices.empty());
95
96 BrowserThread::PostTask(
97 BrowserThread::UI, FROM_HERE,
98 base::Bind(&MediaStreamCaptureIndicator::DoDevicesOpenedOnUIThread,
99 this, render_process_id, render_view_id, devices));
100 }
101
102 void MediaStreamCaptureIndicator::CaptureDevicesClosed(
103 int render_process_id,
104 int render_view_id,
105 const content::MediaStreamDevices& devices) {
106 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
107 DCHECK(!devices.empty());
108
109 BrowserThread::PostTask(
110 BrowserThread::UI, FROM_HERE,
111 base::Bind(&MediaStreamCaptureIndicator::DoDevicesClosedOnUIThread,
112 this, render_process_id, render_view_id, devices));
113 }
114
115 void MediaStreamCaptureIndicator::DoDevicesOpenedOnUIThread(
116 int render_process_id,
117 int render_view_id,
118 const content::MediaStreamDevices& devices) {
119 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
120
121 CreateStatusTray();
122
123 // If we don't have a status icon or one could not be created successfully,
124 // then no need to continue.
125 if (!status_icon_)
126 return;
127
128 AddCaptureDeviceTab(render_process_id, render_view_id, devices);
129
130 ShowBalloon(render_process_id, render_view_id, devices);
131 }
132
133 void MediaStreamCaptureIndicator::DoDevicesClosedOnUIThread(
134 int render_process_id,
135 int render_view_id,
136 const content::MediaStreamDevices& devices) {
137 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
138 if (!status_icon_)
139 return;
140
141 DCHECK(!tabs_.empty());
142 RemoveCaptureDeviceTab(render_process_id, render_view_id, devices);
143
144 if (tabs_.empty())
145 Hide();
146 }
147
148 void MediaStreamCaptureIndicator::CreateStatusTray() {
149 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
150 if (status_icon_)
151 return;
152
153 // If there is no browser process, we should not create the status tray.
154 if (!g_browser_process)
155 return;
156
157 StatusTray* status_tray = g_browser_process->status_tray();
158 if (!status_tray)
159 return;
160
161 status_icon_ = status_tray->CreateStatusIcon();
162
163 status_icon_->SetToolTip(l10n_util::GetStringFUTF16(
164 IDS_MEDIA_STREAM_STATUS_TRAY_TOOLTIP,
165 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)));
166
167 EnsureStatusTrayIcon();
168 DCHECK(!icon_image_.empty());
169
170 status_icon_->SetImage(icon_image_);
171 }
172
173 void MediaStreamCaptureIndicator::EnsureStatusTrayIcon() {
174 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
175 if (icon_image_.empty()) {
176 icon_image_ = *ResourceBundle::GetSharedInstance().GetBitmapNamed(
177 IDR_MEDIA_STREAM_CAPTURE_LED);
178 }
179 }
180
181 void MediaStreamCaptureIndicator::ShowBalloon(
182 int render_process_id,
183 int render_view_id,
184 const content::MediaStreamDevices& devices) const {
185 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
186 string16 title = l10n_util::GetStringFUTF16(
187 IDS_MEDIA_STREAM_STATUS_TRAY_BALLOON_TITLE,
188 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
189
190 int message_id = IDS_MEDIA_STREAM_STATUS_TRAY_BALLOON_BODY_AUDIO_AND_VIDEO;
191 if (devices.size() == 1) {
192 if (devices.front().type == content::MEDIA_STREAM_DEVICE_TYPE_AUDIO_CAPTURE)
193 message_id = IDS_MEDIA_STREAM_STATUS_TRAY_BALLOON_BODY_AUDIO_ONLY;
194 else
195 message_id = IDS_MEDIA_STREAM_STATUS_TRAY_BALLOON_BODY_VIDEO_ONLY;
196 }
197
198 string16 message = l10n_util::GetStringFUTF16(
199 message_id, GetTitle(render_process_id, render_view_id));
200
201 status_icon_->DisplayBalloon(icon_image_, title, message);
202 }
203
204 void MediaStreamCaptureIndicator::Hide() {
205 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
206 if (!status_icon_)
207 return;
208
209 // If there is no browser process, we should not do anything.
210 if (!g_browser_process)
211 return;
212
213 StatusTray* status_tray = g_browser_process->status_tray();
214 if (status_tray != NULL) {
215 status_tray->RemoveStatusIcon(status_icon_);
216 status_icon_ = NULL;
217 }
218 }
219
220 void MediaStreamCaptureIndicator::UpdateStatusTrayIconContextMenu() {
221 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
222 scoped_ptr<ui::SimpleMenuModel> menu(new ui::SimpleMenuModel(this));
223
224 for (CaptureDeviceTabList::iterator iter = tabs_.begin();
225 iter != tabs_.end(); ++iter) {
226 // Search backward to see if the tab has been added.
227 CaptureDeviceTabList::iterator iter_backward = std::find_if(
228 tabs_.begin(), iter, TabEquals(iter->render_process_id,
229 iter->render_view_id));
230 // Do nothing if the tab has been added to the menu.
231 if (iter_backward != iter)
232 continue;
233
234 string16 tab_title = GetTitle(iter->render_process_id,
235 iter->render_view_id);
236 // The tab has gone away.
237 if (tab_title.empty())
238 continue;
239
240 string16 message = l10n_util::GetStringFUTF16(
241 IDS_MEDIA_STREAM_STATUS_TRAY_MENU_ITEM, tab_title);
242 menu->AddItem(IDC_MEDIA_CONTEXT_MEDIA_STREAM_CAPTURE_LIST_FIRST, message);
243 menu->AddSeparator();
244 }
245
246 // The icon will take the ownership of the passed context menu.
247 status_icon_->SetContextMenu(menu.release());
248 }
249
250 void MediaStreamCaptureIndicator::AddCaptureDeviceTab(
251 int render_process_id,
252 int render_view_id,
253 const content::MediaStreamDevices& devices) {
254 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
255 content::MediaStreamDevices::const_iterator dev = devices.begin();
256 for (; dev != devices.end(); ++dev) {
257 DCHECK(dev->type == content::MEDIA_STREAM_DEVICE_TYPE_AUDIO_CAPTURE ||
258 dev->type == content::MEDIA_STREAM_DEVICE_TYPE_VIDEO_CAPTURE);
259 tabs_.push_back(CaptureDeviceTab(render_process_id,
260 render_view_id,
261 dev->type));
262 }
263
264 UpdateStatusTrayIconContextMenu();
265 }
266
267 void MediaStreamCaptureIndicator::RemoveCaptureDeviceTab(
268 int render_process_id,
269 int render_view_id,
270 const content::MediaStreamDevices& devices) {
271 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
272 content::MediaStreamDevices::const_iterator dev = devices.begin();
273 for (; dev != devices.end(); ++dev) {
274 CaptureDeviceTabList::iterator iter = std::find_if(
275 tabs_.begin(), tabs_.end(), TabEquals(render_process_id,
276 render_view_id,
277 dev->type));
278 if (iter != tabs_.end()) {
279 tabs_.erase(iter);
280 } else {
281 DLOG(ERROR) << "Failed to find MediaStream host "
282 << GetTitle(render_process_id, render_view_id)
283 << " for device " << dev->name
284 << " for type " << dev->type;
285 }
286 }
287
288 if (!tabs_.empty())
289 UpdateStatusTrayIconContextMenu();
290 }
291
292 string16 MediaStreamCaptureIndicator::GetTitle(int render_process_id,
293 int render_view_id) const {
294 WebContents* tab_content = tab_util::GetWebContentsByID(
295 render_process_id, render_view_id);
296 if (!tab_content)
297 return NULL;
298
299 string16 tab_title = tab_content->GetTitle();
300 if (tab_title.empty()) {
301 GURL url = tab_content->GetURL();
302 tab_title = UTF8ToUTF16(url.spec());
303 // Force URL to be LTR.
304 tab_title = base::i18n::GetDisplayStringInLTRDirectionality(tab_title);
305 } else {
306 // Sets the title explicitly as LTR format. Please look at the comments in
307 // TaskManagerTabContentsResource::GetTitle() for the reasons of doing this.
308 base::i18n::AdjustStringForLocaleDirection(&tab_title);
309 }
310
311 return tab_title;
312 }
OLDNEW
« no previous file with comments | « chrome/browser/media/media_stream_capture_indicator.h ('k') | chrome/browser/status_icons/desktop_notification_balloon.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698