| 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
|
| deleted file mode 100644
|
| index d7e79c5b81d8db7a85eacf41e5efee3454505d47..0000000000000000000000000000000000000000
|
| --- a/chrome/browser/media/media_stream_capture_indicator.cc
|
| +++ /dev/null
|
| @@ -1,441 +0,0 @@
|
| -// 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 <stddef.h>
|
| -
|
| -#include <memory>
|
| -#include <string>
|
| -#include <utility>
|
| -
|
| -#include "base/logging.h"
|
| -#include "base/macros.h"
|
| -#include "base/memory/ptr_util.h"
|
| -#include "base/strings/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 "chrome/grit/chromium_strings.h"
|
| -#include "chrome/grit/theme_resources.h"
|
| -#include "components/url_formatter/elide_url.h"
|
| -#include "content/public/browser/browser_thread.h"
|
| -#include "content/public/browser/content_browser_client.h"
|
| -#include "content/public/browser/web_contents.h"
|
| -#include "content/public/browser/web_contents_delegate.h"
|
| -#include "content/public/browser/web_contents_observer.h"
|
| -#include "ui/base/l10n/l10n_util.h"
|
| -#include "ui/base/resource/resource_bundle.h"
|
| -#include "ui/gfx/image/image_skia.h"
|
| -
|
| -#if defined(ENABLE_EXTENSIONS)
|
| -#include "chrome/common/extensions/extension_constants.h"
|
| -#include "extensions/browser/extension_registry.h"
|
| -#include "extensions/common/extension.h"
|
| -#endif
|
| -
|
| -using content::BrowserThread;
|
| -using content::WebContents;
|
| -
|
| -namespace {
|
| -
|
| -#if defined(ENABLE_EXTENSIONS)
|
| -const extensions::Extension* GetExtension(WebContents* web_contents) {
|
| - DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
| -
|
| - if (!web_contents)
|
| - return NULL;
|
| -
|
| - extensions::ExtensionRegistry* registry =
|
| - extensions::ExtensionRegistry::Get(web_contents->GetBrowserContext());
|
| - return registry->enabled_extensions().GetExtensionOrAppByURL(
|
| - web_contents->GetURL());
|
| -}
|
| -
|
| -bool IsWhitelistedExtension(const extensions::Extension* extension) {
|
| - DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
| -
|
| - static const char* const kExtensionWhitelist[] = {
|
| - extension_misc::kHotwordNewExtensionId,
|
| - };
|
| -
|
| - for (size_t i = 0; i < arraysize(kExtensionWhitelist); ++i) {
|
| - if (extension->id() == kExtensionWhitelist[i])
|
| - return true;
|
| - }
|
| -
|
| - return false;
|
| -}
|
| -#endif // defined(ENABLE_EXTENSIONS)
|
| -
|
| -base::string16 GetTitle(WebContents* web_contents) {
|
| - DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
| -
|
| - if (!web_contents)
|
| - return base::string16();
|
| -
|
| -#if defined(ENABLE_EXTENSIONS)
|
| - const extensions::Extension* const extension = GetExtension(web_contents);
|
| - if (extension)
|
| - return base::UTF8ToUTF16(extension->name());
|
| -#endif
|
| -
|
| - return url_formatter::FormatUrlForSecurityDisplay(web_contents->GetURL());
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -// Stores usage counts for all the capture devices associated with a single
|
| -// WebContents instance. Instances of this class are owned by
|
| -// MediaStreamCaptureIndicator. They also observe for the destruction of their
|
| -// corresponding WebContents and trigger their own deletion from their
|
| -// MediaStreamCaptureIndicator.
|
| -class MediaStreamCaptureIndicator::WebContentsDeviceUsage
|
| - : public content::WebContentsObserver {
|
| - public:
|
| - WebContentsDeviceUsage(scoped_refptr<MediaStreamCaptureIndicator> indicator,
|
| - WebContents* web_contents)
|
| - : WebContentsObserver(web_contents),
|
| - indicator_(indicator),
|
| - audio_ref_count_(0),
|
| - video_ref_count_(0),
|
| - mirroring_ref_count_(0),
|
| - weak_factory_(this) {
|
| - }
|
| -
|
| - bool IsCapturingAudio() const { return audio_ref_count_ > 0; }
|
| - bool IsCapturingVideo() const { return video_ref_count_ > 0; }
|
| - bool IsMirroring() const { return mirroring_ref_count_ > 0; }
|
| -
|
| - std::unique_ptr<content::MediaStreamUI> RegisterMediaStream(
|
| - const content::MediaStreamDevices& devices);
|
| -
|
| - // Increment ref-counts up based on the type of each device provided.
|
| - void AddDevices(const content::MediaStreamDevices& devices);
|
| -
|
| - // Decrement ref-counts up based on the type of each device provided.
|
| - void RemoveDevices(const content::MediaStreamDevices& devices);
|
| -
|
| - private:
|
| - // content::WebContentsObserver overrides.
|
| - void WebContentsDestroyed() override {
|
| - indicator_->UnregisterWebContents(web_contents());
|
| - }
|
| -
|
| - scoped_refptr<MediaStreamCaptureIndicator> indicator_;
|
| - int audio_ref_count_;
|
| - int video_ref_count_;
|
| - int mirroring_ref_count_;
|
| -
|
| - base::WeakPtrFactory<WebContentsDeviceUsage> weak_factory_;
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(WebContentsDeviceUsage);
|
| -};
|
| -
|
| -// Implements MediaStreamUI interface. Instances of this class are created for
|
| -// each MediaStream and their ownership is passed to MediaStream implementation
|
| -// in the content layer. Each UIDelegate keeps a weak pointer to the
|
| -// corresponding WebContentsDeviceUsage object to deliver updates about state of
|
| -// the stream.
|
| -class MediaStreamCaptureIndicator::UIDelegate : public content::MediaStreamUI {
|
| - public:
|
| - UIDelegate(base::WeakPtr<WebContentsDeviceUsage> device_usage,
|
| - const content::MediaStreamDevices& devices)
|
| - : device_usage_(device_usage),
|
| - devices_(devices),
|
| - started_(false) {
|
| - DCHECK(!devices_.empty());
|
| - }
|
| -
|
| - ~UIDelegate() override {
|
| - if (started_ && device_usage_.get())
|
| - device_usage_->RemoveDevices(devices_);
|
| - }
|
| -
|
| - private:
|
| - // content::MediaStreamUI interface.
|
| - gfx::NativeViewId OnStarted(const base::Closure& close_callback) override {
|
| - DCHECK(!started_);
|
| - started_ = true;
|
| - if (device_usage_.get())
|
| - device_usage_->AddDevices(devices_);
|
| - return 0;
|
| - }
|
| -
|
| - base::WeakPtr<WebContentsDeviceUsage> device_usage_;
|
| - content::MediaStreamDevices devices_;
|
| - bool started_;
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(UIDelegate);
|
| -};
|
| -
|
| -std::unique_ptr<content::MediaStreamUI>
|
| -MediaStreamCaptureIndicator::WebContentsDeviceUsage::RegisterMediaStream(
|
| - const content::MediaStreamDevices& devices) {
|
| - return base::WrapUnique(new UIDelegate(weak_factory_.GetWeakPtr(), devices));
|
| -}
|
| -
|
| -void MediaStreamCaptureIndicator::WebContentsDeviceUsage::AddDevices(
|
| - const content::MediaStreamDevices& devices) {
|
| - for (content::MediaStreamDevices::const_iterator it = devices.begin();
|
| - it != devices.end(); ++it) {
|
| - if (it->type == content::MEDIA_TAB_AUDIO_CAPTURE ||
|
| - it->type == content::MEDIA_TAB_VIDEO_CAPTURE) {
|
| - ++mirroring_ref_count_;
|
| - } else if (content::IsAudioInputMediaType(it->type)) {
|
| - ++audio_ref_count_;
|
| - } else if (content::IsVideoMediaType(it->type)) {
|
| - ++video_ref_count_;
|
| - } else {
|
| - NOTIMPLEMENTED();
|
| - }
|
| - }
|
| -
|
| - if (web_contents())
|
| - web_contents()->NotifyNavigationStateChanged(content::INVALIDATE_TYPE_TAB);
|
| -
|
| - indicator_->UpdateNotificationUserInterface();
|
| -}
|
| -
|
| -void MediaStreamCaptureIndicator::WebContentsDeviceUsage::RemoveDevices(
|
| - const content::MediaStreamDevices& devices) {
|
| - for (content::MediaStreamDevices::const_iterator it = devices.begin();
|
| - it != devices.end(); ++it) {
|
| - if (it->type == content::MEDIA_TAB_AUDIO_CAPTURE ||
|
| - it->type == content::MEDIA_TAB_VIDEO_CAPTURE) {
|
| - --mirroring_ref_count_;
|
| - } else if (content::IsAudioInputMediaType(it->type)) {
|
| - --audio_ref_count_;
|
| - } else if (content::IsVideoMediaType(it->type)) {
|
| - --video_ref_count_;
|
| - } else {
|
| - NOTIMPLEMENTED();
|
| - }
|
| - }
|
| -
|
| - DCHECK_GE(audio_ref_count_, 0);
|
| - DCHECK_GE(video_ref_count_, 0);
|
| - DCHECK_GE(mirroring_ref_count_, 0);
|
| -
|
| - web_contents()->NotifyNavigationStateChanged(content::INVALIDATE_TYPE_TAB);
|
| - indicator_->UpdateNotificationUserInterface();
|
| -}
|
| -
|
| -MediaStreamCaptureIndicator::MediaStreamCaptureIndicator()
|
| - : status_icon_(NULL),
|
| - mic_image_(NULL),
|
| - camera_image_(NULL) {
|
| -}
|
| -
|
| -MediaStreamCaptureIndicator::~MediaStreamCaptureIndicator() {
|
| - // The user is responsible for cleaning up by reporting the closure of any
|
| - // opened devices. However, there exists a race condition at shutdown: The UI
|
| - // thread may be stopped before CaptureDevicesClosed() posts the task to
|
| - // invoke DoDevicesClosedOnUIThread(). In this case, usage_map_ won't be
|
| - // empty like it should.
|
| - DCHECK(usage_map_.empty() ||
|
| - !BrowserThread::IsMessageLoopValid(BrowserThread::UI));
|
| -}
|
| -
|
| -std::unique_ptr<content::MediaStreamUI>
|
| -MediaStreamCaptureIndicator::RegisterMediaStream(
|
| - content::WebContents* web_contents,
|
| - const content::MediaStreamDevices& devices) {
|
| - WebContentsDeviceUsage* usage = usage_map_.get(web_contents);
|
| - if (!usage) {
|
| - usage = new WebContentsDeviceUsage(this, web_contents);
|
| - usage_map_.add(web_contents, base::WrapUnique(usage));
|
| - }
|
| - return usage->RegisterMediaStream(devices);
|
| -}
|
| -
|
| -void MediaStreamCaptureIndicator::ExecuteCommand(int command_id,
|
| - int event_flags) {
|
| - DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
| -
|
| - const int index =
|
| - command_id - IDC_MEDIA_CONTEXT_MEDIA_STREAM_CAPTURE_LIST_FIRST;
|
| - DCHECK_LE(0, index);
|
| - DCHECK_GT(static_cast<int>(command_targets_.size()), index);
|
| - WebContents* web_contents = command_targets_[index];
|
| - if (ContainsKey(usage_map_, web_contents))
|
| - web_contents->GetDelegate()->ActivateContents(web_contents);
|
| -}
|
| -
|
| -bool MediaStreamCaptureIndicator::IsCapturingUserMedia(
|
| - content::WebContents* web_contents) const {
|
| - DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
| -
|
| - WebContentsDeviceUsage* usage = usage_map_.get(web_contents);
|
| - return usage && (usage->IsCapturingAudio() || usage->IsCapturingVideo());
|
| -}
|
| -
|
| -bool MediaStreamCaptureIndicator::IsCapturingVideo(
|
| - content::WebContents* web_contents) const {
|
| - DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
| -
|
| - WebContentsDeviceUsage* usage = usage_map_.get(web_contents);
|
| - return usage && usage->IsCapturingVideo();
|
| -}
|
| -
|
| -bool MediaStreamCaptureIndicator::IsCapturingAudio(
|
| - content::WebContents* web_contents) const {
|
| - DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
| -
|
| - WebContentsDeviceUsage* usage = usage_map_.get(web_contents);
|
| - return usage && usage->IsCapturingAudio();
|
| -}
|
| -
|
| -bool MediaStreamCaptureIndicator::IsBeingMirrored(
|
| - content::WebContents* web_contents) const {
|
| - DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
| -
|
| - WebContentsDeviceUsage* usage = usage_map_.get(web_contents);
|
| - return usage && usage->IsMirroring();
|
| -}
|
| -
|
| -void MediaStreamCaptureIndicator::UnregisterWebContents(
|
| - WebContents* web_contents) {
|
| - usage_map_.erase(web_contents);
|
| - UpdateNotificationUserInterface();
|
| -}
|
| -
|
| -void MediaStreamCaptureIndicator::MaybeCreateStatusTrayIcon(bool audio,
|
| - bool video) {
|
| - DCHECK_CURRENTLY_ON(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;
|
| -
|
| - EnsureStatusTrayIconResources();
|
| -
|
| - gfx::ImageSkia image;
|
| - base::string16 tool_tip;
|
| - GetStatusTrayIconInfo(audio, video, &image, &tool_tip);
|
| - DCHECK(!image.isNull());
|
| - DCHECK(!tool_tip.empty());
|
| -
|
| - status_icon_ = status_tray->CreateStatusIcon(
|
| - StatusTray::MEDIA_STREAM_CAPTURE_ICON, image, tool_tip);
|
| -}
|
| -
|
| -void MediaStreamCaptureIndicator::EnsureStatusTrayIconResources() {
|
| - DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
| -
|
| - if (!mic_image_) {
|
| - mic_image_ = ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
|
| - IDR_INFOBAR_MEDIA_STREAM_MIC);
|
| - }
|
| - if (!camera_image_) {
|
| - camera_image_ = ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
|
| - IDR_INFOBAR_MEDIA_STREAM_CAMERA);
|
| - }
|
| - DCHECK(mic_image_);
|
| - DCHECK(camera_image_);
|
| -}
|
| -
|
| -void MediaStreamCaptureIndicator::MaybeDestroyStatusTrayIcon() {
|
| - DCHECK_CURRENTLY_ON(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::UpdateNotificationUserInterface() {
|
| - DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
| -
|
| - std::unique_ptr<StatusIconMenuModel> menu(new StatusIconMenuModel(this));
|
| - bool audio = false;
|
| - bool video = false;
|
| - int command_id = IDC_MEDIA_CONTEXT_MEDIA_STREAM_CAPTURE_LIST_FIRST;
|
| - command_targets_.clear();
|
| -
|
| - for (const auto& it : usage_map_) {
|
| - // Check if any audio and video devices have been used.
|
| - const WebContentsDeviceUsage& usage = *it.second;
|
| - if (!usage.IsCapturingAudio() && !usage.IsCapturingVideo())
|
| - continue;
|
| -
|
| - WebContents* const web_contents = it.first;
|
| -
|
| - // The audio/video icon is shown only for non-whitelisted extensions or on
|
| - // Android. For regular tabs on desktop, we show an indicator in the tab
|
| - // icon.
|
| -#if defined(ENABLE_EXTENSIONS)
|
| - const extensions::Extension* extension = GetExtension(web_contents);
|
| - if (!extension || IsWhitelistedExtension(extension))
|
| - continue;
|
| -#endif
|
| -
|
| - audio = audio || usage.IsCapturingAudio();
|
| - video = video || usage.IsCapturingVideo();
|
| -
|
| - command_targets_.push_back(web_contents);
|
| - menu->AddItem(command_id, GetTitle(web_contents));
|
| -
|
| - // If the menu item is not a label, enable it.
|
| - menu->SetCommandIdEnabled(command_id, command_id != IDC_MinimumLabelValue);
|
| -
|
| - // If reaching the maximum number, no more item will be added to the menu.
|
| - if (command_id == IDC_MEDIA_CONTEXT_MEDIA_STREAM_CAPTURE_LIST_LAST)
|
| - break;
|
| - ++command_id;
|
| - }
|
| -
|
| - if (command_targets_.empty()) {
|
| - MaybeDestroyStatusTrayIcon();
|
| - return;
|
| - }
|
| -
|
| - // The icon will take the ownership of the passed context menu.
|
| - MaybeCreateStatusTrayIcon(audio, video);
|
| - if (status_icon_) {
|
| - status_icon_->SetContextMenu(std::move(menu));
|
| - }
|
| -}
|
| -
|
| -void MediaStreamCaptureIndicator::GetStatusTrayIconInfo(
|
| - bool audio,
|
| - bool video,
|
| - gfx::ImageSkia* image,
|
| - base::string16* tool_tip) {
|
| - DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
| - DCHECK(audio || video);
|
| - DCHECK(image);
|
| - DCHECK(tool_tip);
|
| -
|
| - int message_id = 0;
|
| - if (audio && video) {
|
| - message_id = IDS_MEDIA_STREAM_STATUS_TRAY_TEXT_AUDIO_AND_VIDEO;
|
| - *image = *camera_image_;
|
| - } else if (audio && !video) {
|
| - message_id = IDS_MEDIA_STREAM_STATUS_TRAY_TEXT_AUDIO_ONLY;
|
| - *image = *mic_image_;
|
| - } else if (!audio && video) {
|
| - message_id = IDS_MEDIA_STREAM_STATUS_TRAY_TEXT_VIDEO_ONLY;
|
| - *image = *camera_image_;
|
| - }
|
| -
|
| - *tool_tip = l10n_util::GetStringUTF16(message_id);
|
| -}
|
|
|