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

Unified 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, 8 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 side-by-side diff with in-line comments
Download patch
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..64cc0c9d537255202802a5a83fd8831409fcb583
--- /dev/null
+++ b/chrome/browser/media/media_stream_capture_indicator.cc
@@ -0,0 +1,312 @@
+// 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/i18n/rtl.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 "chrome/browser/tab_contents/tab_util.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/web_contents.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;
+using content::WebContents;
+
+MediaStreamCaptureIndicator::TabEquals::TabEquals(
+ int render_process_id,
+ int render_view_id,
+ content::MediaStreamDeviceType type)
+ : render_process_id_(render_process_id),
+ render_view_id_(render_view_id),
+ type_(type) {}
+
+MediaStreamCaptureIndicator::TabEquals::TabEquals(int render_process_id,
+ int render_view_id)
+ : render_process_id_(render_process_id),
+ render_view_id_(render_view_id),
+ type_(content::MEDIA_STREAM_DEVICE_TYPE_NO_SERVICE) {}
+
+bool MediaStreamCaptureIndicator::TabEquals::operator() (
+ const MediaStreamCaptureIndicator::CaptureDeviceTab& tab) {
+ if (type_ == content::MEDIA_STREAM_DEVICE_TYPE_NO_SERVICE) {
+ return (render_process_id_ == tab.render_process_id &&
+ render_view_id_ == tab.render_view_id);
+ } else {
+ return (render_process_id_ == tab.render_process_id &&
+ render_view_id_ == tab.render_view_id &&
+ type_ == tab.type);
+ }
+}
+
+MediaStreamCaptureIndicator::MediaStreamCaptureIndicator()
+ : status_icon_(NULL) {
+}
+
+MediaStreamCaptureIndicator::~MediaStreamCaptureIndicator() {
+ // The user is responsible for cleaning up by closing all the opened devices.
+ DCHECK(tabs_.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_CONTEXT_MEDIA_STREAM_CAPTURE_LIST_FIRST:
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+}
+
+void MediaStreamCaptureIndicator::CaptureDevicesOpened(
+ int render_process_id,
+ int render_view_id,
+ const content::MediaStreamDevices& devices) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK(!devices.empty());
+
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&MediaStreamCaptureIndicator::DoDevicesOpenedOnUIThread,
+ this, render_process_id, render_view_id, devices));
+}
+
+void MediaStreamCaptureIndicator::CaptureDevicesClosed(
+ int render_process_id,
+ int render_view_id,
+ const content::MediaStreamDevices& devices) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK(!devices.empty());
+
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&MediaStreamCaptureIndicator::DoDevicesClosedOnUIThread,
+ this, render_process_id, render_view_id, devices));
+}
+
+void MediaStreamCaptureIndicator::DoDevicesOpenedOnUIThread(
+ int render_process_id,
+ int render_view_id,
+ 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;
+
+ AddCaptureDeviceTab(render_process_id, render_view_id, devices);
+
+ ShowBalloon(render_process_id, render_view_id, devices);
+}
+
+void MediaStreamCaptureIndicator::DoDevicesClosedOnUIThread(
+ int render_process_id,
+ int render_view_id,
+ const content::MediaStreamDevices& devices) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (!status_icon_)
+ return;
+
+ DCHECK(!tabs_.empty());
+ RemoveCaptureDeviceTab(render_process_id, render_view_id, devices);
+
+ if (tabs_.empty())
+ Hide();
+}
+
+void MediaStreamCaptureIndicator::CreateStatusTray() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (status_icon_)
+ 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::GetStringFUTF16(
+ IDS_MEDIA_STREAM_STATUS_TRAY_TOOLTIP,
+ l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)));
+
+ EnsureStatusTrayIcon();
+ DCHECK(!icon_image_.empty());
+
+ status_icon_->SetImage(icon_image_);
+}
+
+void MediaStreamCaptureIndicator::EnsureStatusTrayIcon() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (icon_image_.empty()) {
+ icon_image_ = *ResourceBundle::GetSharedInstance().GetBitmapNamed(
+ IDR_MEDIA_STREAM_CAPTURE_LED);
+ }
+}
+
+void MediaStreamCaptureIndicator::ShowBalloon(
+ int render_process_id,
+ int render_view_id,
+ const content::MediaStreamDevices& devices) const {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ string16 title = l10n_util::GetStringFUTF16(
+ IDS_MEDIA_STREAM_STATUS_TRAY_BALLOON_TITLE,
+ l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
+
+ int message_id = IDS_MEDIA_STREAM_STATUS_TRAY_BALLOON_BODY_AUDIO_AND_VIDEO;
+ if (devices.size() == 1) {
+ if (devices.front().type == content::MEDIA_STREAM_DEVICE_TYPE_AUDIO_CAPTURE)
+ message_id = IDS_MEDIA_STREAM_STATUS_TRAY_BALLOON_BODY_AUDIO_ONLY;
+ else
+ message_id = IDS_MEDIA_STREAM_STATUS_TRAY_BALLOON_BODY_VIDEO_ONLY;
+ }
+
+ string16 message = l10n_util::GetStringFUTF16(
+ message_id, GetTitle(render_process_id, render_view_id));
+
+ status_icon_->DisplayBalloon(icon_image_, title, message);
+}
+
+void MediaStreamCaptureIndicator::Hide() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (!status_icon_)
+ 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() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ scoped_ptr<ui::SimpleMenuModel> menu(new ui::SimpleMenuModel(this));
+
+ for (CaptureDeviceTabList::iterator iter = tabs_.begin();
+ iter != tabs_.end(); ++iter) {
+ // Search backward to see if the tab has been added.
+ CaptureDeviceTabList::iterator iter_backward = std::find_if(
+ tabs_.begin(), iter, TabEquals(iter->render_process_id,
+ iter->render_view_id));
+ // Do nothing if the tab has been added to the menu.
+ if (iter_backward != iter)
+ continue;
+
+ string16 tab_title = GetTitle(iter->render_process_id,
+ iter->render_view_id);
+ // The tab has gone away.
+ if (tab_title.empty())
+ continue;
+
+ string16 message = l10n_util::GetStringFUTF16(
+ IDS_MEDIA_STREAM_STATUS_TRAY_MENU_ITEM, tab_title);
+ menu->AddItem(IDC_MEDIA_CONTEXT_MEDIA_STREAM_CAPTURE_LIST_FIRST, message);
+ menu->AddSeparator();
+ }
+
+ // The icon will take the ownership of the passed context menu.
+ status_icon_->SetContextMenu(menu.release());
+}
+
+void MediaStreamCaptureIndicator::AddCaptureDeviceTab(
+ int render_process_id,
+ int render_view_id,
+ const content::MediaStreamDevices& devices) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ content::MediaStreamDevices::const_iterator dev = devices.begin();
+ for (; dev != devices.end(); ++dev) {
+ DCHECK(dev->type == content::MEDIA_STREAM_DEVICE_TYPE_AUDIO_CAPTURE ||
+ dev->type == content::MEDIA_STREAM_DEVICE_TYPE_VIDEO_CAPTURE);
+ tabs_.push_back(CaptureDeviceTab(render_process_id,
+ render_view_id,
+ dev->type));
+ }
+
+ UpdateStatusTrayIconContextMenu();
+}
+
+void MediaStreamCaptureIndicator::RemoveCaptureDeviceTab(
+ int render_process_id,
+ int render_view_id,
+ const content::MediaStreamDevices& devices) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ content::MediaStreamDevices::const_iterator dev = devices.begin();
+ for (; dev != devices.end(); ++dev) {
+ CaptureDeviceTabList::iterator iter = std::find_if(
+ tabs_.begin(), tabs_.end(), TabEquals(render_process_id,
+ render_view_id,
+ dev->type));
+ if (iter != tabs_.end()) {
+ tabs_.erase(iter);
+ } else {
+ DLOG(ERROR) << "Failed to find MediaStream host "
+ << GetTitle(render_process_id, render_view_id)
+ << " for device " << dev->name
+ << " for type " << dev->type;
+ }
+ }
+
+ if (!tabs_.empty())
+ UpdateStatusTrayIconContextMenu();
+}
+
+string16 MediaStreamCaptureIndicator::GetTitle(int render_process_id,
+ int render_view_id) const {
+ WebContents* tab_content = tab_util::GetWebContentsByID(
+ render_process_id, render_view_id);
+ if (!tab_content)
+ return NULL;
+
+ string16 tab_title = tab_content->GetTitle();
+ if (tab_title.empty()) {
+ GURL url = tab_content->GetURL();
+ tab_title = UTF8ToUTF16(url.spec());
+ // Force URL to be LTR.
+ tab_title = base::i18n::GetDisplayStringInLTRDirectionality(tab_title);
+ } else {
+ // Sets the title explicitly as LTR format. Please look at the comments in
+ // TaskManagerTabContentsResource::GetTitle() for the reasons of doing this.
+ base::i18n::AdjustStringForLocaleDirection(&tab_title);
+ }
+
+ return tab_title;
+}
« 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