Chromium Code Reviews| Index: chrome/browser/media/media_stream_capture_indicator.cc |
| diff --git a/chrome/browser/media/media_stream_capture_indicator.cc b/chrome/browser/media/media_stream_capture_indicator.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..0a1043af64f82e85c7bd8aa043d31f191ac89d74 |
| --- /dev/null |
| +++ b/chrome/browser/media/media_stream_capture_indicator.cc |
| @@ -0,0 +1,284 @@ |
| +// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "chrome/browser/media/media_stream_capture_indicator.h" |
| + |
| +#include "base/bind.h" |
| +#include "base/utf_string_conversions.h" |
| +#include "chrome/app/chrome_command_ids.h" |
| +#include "chrome/browser/browser_process.h" |
| +#include "chrome/browser/status_icons/status_icon.h" |
| +#include "chrome/browser/status_icons/status_tray.h" |
| +#include "content/public/browser/browser_thread.h" |
| +#include "grit/chromium_strings.h" |
| +#include "grit/generated_resources.h" |
| +#include "grit/theme_resources.h" |
| +#include "ui/base/l10n/l10n_util.h" |
| +#include "ui/base/resource/resource_bundle.h" |
| + |
| +using content::BrowserThread; |
| + |
| +MediaStreamCaptureIndicator::UserEquals::UserEquals( |
| + int render_process_id, |
| + int render_view_id, |
| + const std::string& url, |
| + content::MediaStreamDeviceType type) |
| + : render_process_id_(render_process_id), |
| + render_view_id_(render_view_id), |
| + url_(url), |
| + type_(type) {} |
| + |
| +MediaStreamCaptureIndicator::UserEquals::UserEquals(int render_process_id, |
| + int render_view_id, |
| + const std::string& url) |
| + : render_process_id_(render_process_id), |
| + render_view_id_(render_view_id), |
| + url_(url), |
| + type_(content::MEDIA_STREAM_DEVICE_TYPE_NO_SERVICE) {} |
| + |
| +bool MediaStreamCaptureIndicator::UserEquals::operator() ( |
| + const MediaStreamCaptureIndicator::CaptureDeviceUser& user) { |
| + if (type_ == content::MEDIA_STREAM_DEVICE_TYPE_NO_SERVICE) { |
| + return (render_process_id_ == user.render_process_id && |
| + render_view_id_ == user.render_view_id && |
| + url_ == user.url); |
| + } else { |
| + return (render_process_id_ == user.render_process_id && |
| + render_view_id_ == user.render_view_id && |
| + url_ == user.url && |
| + type_ == user.type); |
| + } |
| +} |
| + |
| +MediaStreamCaptureIndicator::MediaStreamCaptureIndicator() |
| + : status_icon_(NULL) { |
| +} |
| + |
| +MediaStreamCaptureIndicator::~MediaStreamCaptureIndicator() { |
| + // The user is responsible for cleaning up by closing all the opened devices. |
| + DCHECK(users_.empty()); |
| +} |
| + |
| +bool MediaStreamCaptureIndicator::IsCommandIdChecked( |
| + int command_id) const { |
| + NOTIMPLEMENTED() << "There are no checked items in the MediaStream menu."; |
| + return false; |
| +} |
| + |
| +bool MediaStreamCaptureIndicator::IsCommandIdEnabled( |
| + int command_id) const { |
| + return command_id != IDC_MinimumLabelValue; |
| +} |
| + |
| +bool MediaStreamCaptureIndicator::GetAcceleratorForCommandId( |
| + int command_id, ui::Accelerator* accelerator) { |
| + // No accelerators for status icon context menu. |
| + return false; |
| +} |
| + |
| +void MediaStreamCaptureIndicator::ExecuteCommand(int command_id) { |
| + // TODO(xians) : Implement all the following execute command function. |
| + switch (command_id) { |
| + case IDC_MEDIA_STREAM_DEVICE_STATUS_TRAY: |
| + break; |
| + case IDC_MEDIA_CONTEXT_MEDIA_STREAM_CAPTURE_LIST: |
| + break; |
| + default: |
| + NOTREACHED(); |
| + break; |
| + } |
| +} |
| + |
| +void MediaStreamCaptureIndicator::CaptureDevicesOpened( |
| + int render_process_id, |
| + int render_view_id, |
| + const std::string& url, |
| + const content::MediaStreamDevices& devices) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + DCHECK(!url.empty()); |
| + DCHECK(!devices.empty()); |
| + |
| + BrowserThread::PostTask( |
| + BrowserThread::UI, FROM_HERE, |
| + base::Bind(&MediaStreamCaptureIndicator::DoDevicesOpenedOnUIThread, |
| + this, render_process_id, render_view_id, url, devices)); |
| +} |
| + |
| +void MediaStreamCaptureIndicator::CaptureDevicesClosed( |
| + int render_process_id, |
| + int render_view_id, |
| + const std::string& url, |
| + const content::MediaStreamDevices& devices) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + DCHECK(!url.empty()); |
| + DCHECK(!devices.empty()); |
| + |
| + BrowserThread::PostTask( |
| + BrowserThread::UI, FROM_HERE, |
| + base::Bind(&MediaStreamCaptureIndicator::DoDevicesClosedOnUIThread, |
| + this, render_process_id, render_view_id, url, devices)); |
| +} |
| + |
| +void MediaStreamCaptureIndicator::DoDevicesOpenedOnUIThread( |
| + int render_process_id, |
| + int render_view_id, |
| + const std::string& url, |
| + const content::MediaStreamDevices& devices) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + |
| + CreateStatusTray(); |
| + |
| + // If we don't have a status icon or one could not be created successfully, |
| + // then no need to continue. |
| + if (!status_icon_) |
| + return; |
| + |
| + AddCaptureDeviceUser(render_process_id, render_view_id, url, devices); |
| + |
| + ShowBalloon(url); |
| +} |
| + |
| +void MediaStreamCaptureIndicator::DoDevicesClosedOnUIThread( |
| + int render_process_id, |
| + int render_view_id, |
| + const std::string& url, |
| + const content::MediaStreamDevices& devices) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + if (!status_icon_) |
| + return; |
| + |
| + DCHECK(!users_.empty()); |
| + RemoveCaptureDeviceUser(render_process_id, render_view_id, url, devices); |
| + |
| + if (users_.empty()) |
| + Hide(); |
| +} |
| + |
| +void MediaStreamCaptureIndicator::CreateStatusTray() { |
| + if (status_icon_) |
|
tommi (sloooow) - chröme
2012/04/30 10:57:07
DCHECK(...on UI thread ...)
no longer working on chromium
2012/04/30 13:12:54
From Mad: Nit: You already DCHECKed on that in the
|
| + return; |
| + |
| + // If there is no browser process, we should not create the status tray. |
| + if (!g_browser_process) |
| + return; |
| + |
| + StatusTray* status_tray = g_browser_process->status_tray(); |
| + if (!status_tray) |
| + return; |
| + |
| + status_icon_ = status_tray->CreateStatusIcon(); |
| + |
| + status_icon_->SetToolTip(l10n_util::GetStringUTF16( |
| + IDS_MEDIA_STREAM_STATUS_TRAY_TOOLTIP)); |
| + |
| + EnsureStatusTrayIcon(); |
| + DCHECK(!icon_image_.empty()); |
| + |
| + status_icon_->SetImage(icon_image_); |
| +} |
| + |
| +void MediaStreamCaptureIndicator::EnsureStatusTrayIcon() { |
| + if (icon_image_.empty()) { |
| + icon_image_ = *ResourceBundle::GetSharedInstance().GetBitmapNamed( |
| + IDR_MEDIA_STREAM_CAPTURE_LED); |
| + } |
| +} |
| + |
| +void MediaStreamCaptureIndicator::ShowBalloon( |
| + const std::string& url) { |
| + string16 title = l10n_util::GetStringUTF16( |
| + IDS_MEDIA_STREAM_STATUS_TRAY_BALLOON_TITLE); |
| + |
| + string16 message = l10n_util::GetStringFUTF16( |
| + IDS_MEDIA_STREAM_STATUS_TRAY_BALLOON_BODY, ASCIIToUTF16(url)); |
| + |
| + status_icon_->DisplayBalloon(icon_image_, title, message); |
| +} |
| + |
| +void MediaStreamCaptureIndicator::Hide() { |
| + if (!status_icon_) |
|
tommi (sloooow) - chröme
2012/04/30 10:57:07
missing thread dcheck since this method accesses v
no longer working on chromium
2012/04/30 13:12:54
See my answers above.
|
| + return; |
| + |
| + // If there is no browser process, we should not do anything. |
| + if (!g_browser_process) |
| + return; |
| + |
| + StatusTray* status_tray = g_browser_process->status_tray(); |
| + if (status_tray != NULL) { |
| + status_tray->RemoveStatusIcon(status_icon_); |
| + status_icon_ = NULL; |
| + } |
| +} |
| + |
| +void MediaStreamCaptureIndicator::UpdateStatusTrayIconContextMenu() { |
| + scoped_ptr<ui::SimpleMenuModel> menu(new ui::SimpleMenuModel(this)); |
| + menu->AddItem(IDC_MEDIA_STREAM_DEVICE_STATUS_TRAY, |
| + l10n_util::GetStringUTF16(IDS_MEDIA_STREAM_STATUS_TRAY_TITLE)); |
|
tommi (sloooow) - chröme
2012/04/30 10:57:07
I don't think a menu should have a title.
no longer working on chromium
2012/04/30 13:12:54
Done, I changed it to IDS_MEDIA_STREAM_STATUS_TRAY
|
| + menu->AddSeparator(); |
| + |
| + for (CaptureDeviceUserList::iterator iter = users_.begin(); |
|
tommi (sloooow) - chröme
2012/04/30 10:57:07
missing thread dcheck for users_
no longer working on chromium
2012/04/30 13:12:54
See my answer in other comments.
|
| + iter != users_.end(); ++iter) { |
| + // Search backward to see if the user information has been added. |
| + CaptureDeviceUserList::iterator iter_backward = std::find_if( |
| + users_.begin(), iter, UserEquals(iter->render_process_id, |
| + iter->render_view_id, |
| + iter->url)); |
| + // Do nothing if the user information has been added to the menu. |
| + if (iter_backward != iter) |
| + continue; |
| + |
| + int command_id = IDC_MEDIA_CONTEXT_MEDIA_STREAM_CAPTURE_LIST; |
|
tommi (sloooow) - chröme
2012/04/30 10:57:07
nit: no need for these two temporaries
no longer working on chromium
2012/04/30 13:12:54
Done.
|
| + int message_id = IDS_MEDIA_STREAM_STATUS_TRAY_ITEM; |
| + string16 message = l10n_util::GetStringFUTF16(message_id, |
| + ASCIIToUTF16(iter->url)); |
| + menu->AddItem(command_id, message); |
| + menu->AddSeparator(); |
| + } |
| + |
| + // The icon will take the ownership of the passed context menu. |
| + status_icon_->SetContextMenu(menu.release()); |
| +} |
| + |
| +void MediaStreamCaptureIndicator::AddCaptureDeviceUser( |
| + int render_process_id, |
| + int render_view_id, |
| + const std::string& url, |
| + const content::MediaStreamDevices& devices) { |
| + content::MediaStreamDevices::const_iterator dev = devices.begin(); |
|
tommi (sloooow) - chröme
2012/04/30 10:57:07
missing thread dcheck in this function
no longer working on chromium
2012/04/30 13:12:54
See my answer in other comments.
|
| + for (; dev != devices.end(); ++dev) { |
| + DCHECK(dev->type == content::MEDIA_STREAM_DEVICE_TYPE_AUDIO_CAPTURE || |
| + dev->type == content::MEDIA_STREAM_DEVICE_TYPE_VIDEO_CAPTURE); |
| + users_.push_back(CaptureDeviceUser(render_process_id, |
|
tommi (sloooow) - chröme
2012/04/30 10:57:07
do we need to first check if we've already got thi
no longer working on chromium
2012/04/30 13:12:54
Not for the current solution, we save the informat
|
| + render_view_id, |
| + url, |
| + dev->type)); |
| + } |
| + |
| + UpdateStatusTrayIconContextMenu(); |
| +} |
| + |
| +void MediaStreamCaptureIndicator::RemoveCaptureDeviceUser( |
| + int render_process_id, |
| + int render_view_id, |
| + const std::string& url, |
| + const content::MediaStreamDevices& devices) { |
| + content::MediaStreamDevices::const_iterator dev = devices.begin(); |
| + for (; dev != devices.end(); ++dev) { |
| + CaptureDeviceUserList::iterator iter = std::find_if( |
| + users_.begin(), users_.end(), UserEquals(render_process_id, |
|
tommi (sloooow) - chröme
2012/04/30 10:57:07
missing thread dcheck for users_
no longer working on chromium
2012/04/30 13:12:54
See answer in other comments.
|
| + render_view_id, |
| + url, |
| + dev->type)); |
| + if (iter != users_.end()) { |
| + users_.erase(iter); |
| + } else { |
| + DLOG(ERROR) << "Failed to find MediaStream host " << url |
| + << " for device " << dev->name |
| + << " for type " << dev->type; |
| + } |
| + } |
| + |
| + if (!users_.empty()) |
| + UpdateStatusTrayIconContextMenu(); |
| +} |