diff options
-rw-r--r-- | chrome/app/generated_resources.grd | 16 | ||||
-rw-r--r-- | chrome/browser/chrome_content_browser_client.cc | 41 | ||||
-rw-r--r-- | chrome/browser/infobars/infobar_delegate.cc | 4 | ||||
-rw-r--r-- | chrome/browser/infobars/infobar_delegate.h | 2 | ||||
-rw-r--r-- | chrome/browser/media/media_stream_devices_menu_model.cc | 87 | ||||
-rw-r--r-- | chrome/browser/media/media_stream_devices_menu_model.h | 58 | ||||
-rw-r--r-- | chrome/browser/ui/media_stream_infobar_delegate.cc | 140 | ||||
-rw-r--r-- | chrome/browser/ui/media_stream_infobar_delegate.h | 82 | ||||
-rw-r--r-- | chrome/browser/ui/views/infobars/media_stream_infobar.cc | 129 | ||||
-rw-r--r-- | chrome/browser/ui/views/infobars/media_stream_infobar.h | 57 | ||||
-rw-r--r-- | chrome/chrome_browser.gypi | 6 | ||||
-rw-r--r-- | content/browser/renderer_host/media/media_stream_device_settings.cc | 6 | ||||
-rw-r--r-- | content/browser/renderer_host/media/media_stream_device_settings.h | 2 | ||||
-rw-r--r-- | content/public/browser/content_browser_client.h | 2 | ||||
-rw-r--r-- | content/public/common/media_stream_request.h | 4 |
15 files changed, 616 insertions, 20 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 32fef50..a900770 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd @@ -15368,20 +15368,20 @@ Battery full <message name="IDS_MEDIA_CAPTURE_VIDEO_ONLY" desc="Question asked on the info bar whenever a web page requests access to the computer's camera."> <ph name="HOST">$1<ex>html5rocks.com</ex></ph> wants to use your camera. </message> - <message name="IDS_MEDIA_CAPTURE_MIC" desc="Label for a microphone list drop-down."> - Microphone: + <message name="IDS_MEDIA_CAPTURE_MIC" desc="Label for a microphone element in a device list."> + Microphone: <ph name="DEVICE_NAME">$1<ex>default microphone</ex></ph> </message> - <message name="IDS_MEDIA_CAPTURE_VIDEO" desc="Label for a camera list drop-down."> - Camera: + <message name="IDS_MEDIA_CAPTURE_VIDEO" desc="Label for a camera element in a device list."> + Camera: <ph name="DEVICE_NAME">$1<ex>Built-in camera</ex></ph> </message> - <message name="IDS_MEDIA_CAPTURE_ALLOW" desc="Label for a button that grants access to a web page, so they can use a camera and/or a microphone."> + <message name="IDS_MEDIA_CAPTURE_ALLOW" desc="Label for a button that grants access to a web page, so they can use a camera and/or a microphone."> Allow </message> - <message name="IDS_MEDIA_CAPTURE_DENY" desc="Label for a button that denies access to a web page, so they can use a camera and/or a microphone."> + <message name="IDS_MEDIA_CAPTURE_DENY" desc="Label for a button that denies access to a web page, so they can use a camera and/or a microphone."> Deny </message> - <message name="IDS_MEDIA_CAPTURE_NO_DEVICES" desc="Label for a drop-down button, used if there are no available devices (e.g. camera, microphone) available on the computer."> - (no devices) + <message name="IDS_MEDIA_CAPTURE_DEVICES_MENU_TITLE" desc="Label for a drop-down menu button that will, when clicked, list the available and selected camera and/or microphone devices."> + Devices </message> <!-- Quota messages --> diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index 5a898a9..32a58c3 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc @@ -35,6 +35,7 @@ #include "chrome/browser/extensions/extension_webkit_preferences.h" #include "chrome/browser/geolocation/chrome_access_token_store.h" #include "chrome/browser/google/google_util.h" +#include "chrome/browser/infobars/infobar_tab_helper.h" #include "chrome/browser/net/chrome_net_log.h" #include "chrome/browser/notifications/desktop_notification_service.h" #include "chrome/browser/notifications/desktop_notification_service_factory.h" @@ -58,6 +59,7 @@ #include "chrome/browser/ssl/ssl_blocking_page.h" #include "chrome/browser/tab_contents/tab_contents_ssl_helper.h" #include "chrome/browser/tab_contents/tab_util.h" +#include "chrome/browser/ui/media_stream_infobar_delegate.h" #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" #include "chrome/browser/ui/webui/chrome_web_ui_controller_factory.h" #include "chrome/browser/user_style_sheet_watcher.h" @@ -1063,17 +1065,46 @@ void ChromeContentBrowserClient::RequestMediaAccessPermission( const content::MediaResponseCallback& callback) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - content::MediaStreamDeviceArray devices; + WebContents* contents = tab_util::GetWebContentsByID( + request->render_process_id, request->render_view_id); + if (!contents) { + // Abort, if the tab was closed after the request was made but before we + // got to this point. + callback.Run(content::MediaStreamDevices()); + return; + } + + TabContentsWrapper* tab = + TabContentsWrapper::GetCurrentWrapperForContents(contents); + DCHECK(tab); + + InfoBarTabHelper* infobar_helper = tab->infobar_tab_helper(); + InfoBarDelegate* old_infobar = NULL; + for (size_t i = 0; i < infobar_helper->infobar_count() && !old_infobar; ++i) { + old_infobar = + infobar_helper->GetInfoBarDelegateAt(i)->AsMediaStreamInfobarDelegate(); + } + +#if defined(TOOLKIT_VIEWS) + InfoBarDelegate* infobar = new MediaStreamInfoBarDelegate(infobar_helper, + request, + callback); + if (old_infobar) + infobar_helper->ReplaceInfoBar(old_infobar, infobar); + else + infobar_helper->AddInfoBar(infobar); +#elif defined(OS_LINUX) || defined(OS_MACOSX) + // TODO(macourteau): UI is not implemented yet for Linux and OS X. Fallback to + // the default behaviour and allow access to the first device of each + // requested type. + content::MediaStreamDevices devices; for (content::MediaStreamDeviceMap::const_iterator it = request->devices.begin(); it != request->devices.end(); ++it) { devices.push_back(*it->second.begin()); } - // TODO(macourteau): This is temporary. The base::Callback object will be - // passed to the Infobar, which will Run it with the request's label and the - // list of accepted devices (if any), or an empty list of devices if the user - // has denied the request. callback.Run(devices); +#endif // TOOLKIT_VIEWS } void ChromeContentBrowserClient::RequestDesktopNotificationPermission( diff --git a/chrome/browser/infobars/infobar_delegate.cc b/chrome/browser/infobars/infobar_delegate.cc index bcaf344..25a65ce 100644 --- a/chrome/browser/infobars/infobar_delegate.cc +++ b/chrome/browser/infobars/infobar_delegate.cc @@ -63,6 +63,10 @@ LinkInfoBarDelegate* InfoBarDelegate::AsLinkInfoBarDelegate() { return NULL; } +MediaStreamInfoBarDelegate* InfoBarDelegate::AsMediaStreamInfobarDelegate() { + return NULL; +} + RegisterProtocolHandlerInfoBarDelegate* InfoBarDelegate::AsRegisterProtocolHandlerInfoBarDelegate() { return NULL; diff --git a/chrome/browser/infobars/infobar_delegate.h b/chrome/browser/infobars/infobar_delegate.h index 785f67b..3dcda68 100644 --- a/chrome/browser/infobars/infobar_delegate.h +++ b/chrome/browser/infobars/infobar_delegate.h @@ -16,6 +16,7 @@ class InfoBar; class InfoBarTabHelper; class InsecureContentInfoBarDelegate; class LinkInfoBarDelegate; +class MediaStreamInfoBarDelegate; class PluginInstallerInfoBarDelegate; class RegisterProtocolHandlerInfoBarDelegate; class ThemeInstalledInfoBarDelegate; @@ -88,6 +89,7 @@ class InfoBarDelegate { virtual ExtensionInfoBarDelegate* AsExtensionInfoBarDelegate(); virtual InsecureContentInfoBarDelegate* AsInsecureContentInfoBarDelegate(); virtual LinkInfoBarDelegate* AsLinkInfoBarDelegate(); + virtual MediaStreamInfoBarDelegate* AsMediaStreamInfobarDelegate(); virtual RegisterProtocolHandlerInfoBarDelegate* AsRegisterProtocolHandlerInfoBarDelegate(); virtual ThemeInstalledInfoBarDelegate* AsThemePreviewInfobarDelegate(); diff --git a/chrome/browser/media/media_stream_devices_menu_model.cc b/chrome/browser/media/media_stream_devices_menu_model.cc new file mode 100644 index 0000000..119d424 --- /dev/null +++ b/chrome/browser/media/media_stream_devices_menu_model.cc @@ -0,0 +1,87 @@ +// 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_devices_menu_model.h" + +#include <utility> + +#include "base/utf_string_conversions.h" +#include "chrome/browser/ui/media_stream_infobar_delegate.h" +#include "content/public/common/media_stream_request.h" +#include "grit/generated_resources.h" +#include "ui/base/l10n/l10n_util.h" + +MediaStreamDevicesMenuModel::MediaStreamDevicesMenuModel( + const MediaStreamInfoBarDelegate* delegate) + : ALLOW_THIS_IN_INITIALIZER_LIST(ui::SimpleMenuModel(this)), + selected_command_id_audio_(-1), + selected_command_id_video_(-1) { + const bool nonempty_audio_section = + delegate->has_audio() && !delegate->GetAudioDevices().empty(); + if (delegate->has_video() && !delegate->GetVideoDevices().empty()) { + // The default command ID is the first element that will be inserted. + selected_command_id_video_ = commands_.size(); + AddDevices(delegate->GetVideoDevices()); + if (nonempty_audio_section) + AddSeparator(); + } + if (nonempty_audio_section) { + // The default command ID is the first element that will be inserted. + selected_command_id_audio_ = commands_.size(); + AddDevices(delegate->GetAudioDevices()); + } +} + +MediaStreamDevicesMenuModel::~MediaStreamDevicesMenuModel() { +} + +void MediaStreamDevicesMenuModel::AddDevices( + const content::MediaStreamDevices& devices) { + for (size_t i = 0; i < devices.size(); ++i) { + int command_id = commands_.size(); + commands_.insert(std::make_pair(command_id, devices[i])); + int message_id = (devices[i].type == + content::MEDIA_STREAM_DEVICE_TYPE_AUDIO_CAPTURE) ? + IDS_MEDIA_CAPTURE_MIC : IDS_MEDIA_CAPTURE_VIDEO; + AddCheckItem(command_id, + l10n_util::GetStringFUTF16(message_id, + UTF8ToUTF16(devices[i].name))); + } +} + +bool MediaStreamDevicesMenuModel::GetSelectedDeviceId( + content::MediaStreamDeviceType type, + std::string* device_id) const { + int command_id = (type == content::MEDIA_STREAM_DEVICE_TYPE_AUDIO_CAPTURE) ? + selected_command_id_audio_ : selected_command_id_video_; + CommandMap::const_iterator it = commands_.find(command_id); + if (it != commands_.end()) + *device_id = it->second.device_id; + return (it != commands_.end()); +} + +bool MediaStreamDevicesMenuModel::IsCommandIdChecked(int command_id) const { + return (selected_command_id_audio_ == command_id || + selected_command_id_video_ == command_id); +} + +bool MediaStreamDevicesMenuModel::IsCommandIdEnabled(int command_id) const { + return true; +} + +bool MediaStreamDevicesMenuModel::GetAcceleratorForCommandId( + int command_id, + ui::Accelerator* accelerator) { + return false; +} + +void MediaStreamDevicesMenuModel::ExecuteCommand(int command_id) { + CommandMap::iterator it = commands_.find(command_id); + DCHECK(it != commands_.end()); + + if (it->second.type == content::MEDIA_STREAM_DEVICE_TYPE_AUDIO_CAPTURE) + selected_command_id_audio_ = command_id; + else + selected_command_id_video_ = command_id; +} diff --git a/chrome/browser/media/media_stream_devices_menu_model.h b/chrome/browser/media/media_stream_devices_menu_model.h new file mode 100644 index 0000000..fa22ae0 --- /dev/null +++ b/chrome/browser/media/media_stream_devices_menu_model.h @@ -0,0 +1,58 @@ +// 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. + +#ifndef CHROME_BROWSER_MEDIA_MEDIA_STREAM_DEVICES_MENU_MODEL_H_ +#define CHROME_BROWSER_MEDIA_MEDIA_STREAM_DEVICES_MENU_MODEL_H_ +#pragma once + +#include <map> +#include <string> + +#include "content/public/common/media_stream_request.h" +#include "ui/base/models/simple_menu_model.h" + +class MediaStreamInfoBarDelegate; + +// A menu model that builds the contents of the devices menu in the media stream +// infobar. This menu has only one level (no submenus). +class MediaStreamDevicesMenuModel : public ui::SimpleMenuModel, + public ui::SimpleMenuModel::Delegate { + public: + explicit MediaStreamDevicesMenuModel( + const MediaStreamInfoBarDelegate* delegate); + virtual ~MediaStreamDevicesMenuModel(); + + // Returns the |device_id| for the selected device of type |type|. Returns + // true if a selected device of the requested |type| was found, and false if + // none was found, in which case |device_id| remains untouched. + bool GetSelectedDeviceId( + content::MediaStreamDeviceType type, + std::string* device_id) const; + + private: + typedef std::map<int, content::MediaStreamDevice> CommandMap; + + // Internal method to add the |devices| to the current menu. + void AddDevices(const content::MediaStreamDevices& devices); + + // ui::SimpleMenuModel::Delegate implementation: + virtual bool IsCommandIdChecked(int command_id) const OVERRIDE; + virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE; + virtual bool GetAcceleratorForCommandId( + int command_id, + ui::Accelerator* accelerator) OVERRIDE; + virtual void ExecuteCommand(int command_id) OVERRIDE; + + // Map of command IDs to devices. + CommandMap commands_; + + // These are the command IDs (key of above |commands_| map) of the selected + // devices entries in the menu, or -1 if there is no selected ID. + int selected_command_id_audio_; + int selected_command_id_video_; + + DISALLOW_COPY_AND_ASSIGN(MediaStreamDevicesMenuModel); +}; + +#endif // CHROME_BROWSER_MEDIA_MEDIA_STREAM_DEVICES_MENU_MODEL_H_ diff --git a/chrome/browser/ui/media_stream_infobar_delegate.cc b/chrome/browser/ui/media_stream_infobar_delegate.cc new file mode 100644 index 0000000..ef7bab4 --- /dev/null +++ b/chrome/browser/ui/media_stream_infobar_delegate.cc @@ -0,0 +1,140 @@ +// 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 <algorithm> +#include <functional> + +#include "base/logging.h" +#include "chrome/browser/ui/media_stream_infobar_delegate.h" +#include "content/public/common/media_stream_request.h" +#include "grit/theme_resources_standard.h" +#include "ui/base/resource/resource_bundle.h" + +namespace { + +// A predicate that checks if a StreamDeviceInfo object has the same ID as the +// device ID specified at construction. +class DeviceIdEquals { + public: + explicit DeviceIdEquals(const std::string& device_id) + : device_id_(device_id) { + } + + bool operator() (const content::MediaStreamDevice& device) { + return device.device_id == device_id_; + } + + private: + std::string device_id_; +}; + +} // namespace + +MediaStreamInfoBarDelegate::MediaStreamInfoBarDelegate( + InfoBarTabHelper* tab_helper, + const content::MediaStreamRequest* request, + const content::MediaResponseCallback& callback) + : InfoBarDelegate(tab_helper), + request_(request), + callback_(callback) { + DCHECK(request_); + has_audio_ = request_->devices.count( + content::MEDIA_STREAM_DEVICE_TYPE_AUDIO_CAPTURE) != 0; + has_video_ = request_->devices.count( + content::MEDIA_STREAM_DEVICE_TYPE_VIDEO_CAPTURE) != 0; +} + +MediaStreamInfoBarDelegate::~MediaStreamInfoBarDelegate() { +} + +content::MediaStreamDevices + MediaStreamInfoBarDelegate::GetAudioDevices() const { + if (!has_audio_) + return content::MediaStreamDevices(); + content::MediaStreamDeviceMap::const_iterator it = + request_->devices.find(content::MEDIA_STREAM_DEVICE_TYPE_AUDIO_CAPTURE); + DCHECK(it != request_->devices.end()); + return it->second; +} + +content::MediaStreamDevices + MediaStreamInfoBarDelegate::GetVideoDevices() const { + if (!has_video_) + return content::MediaStreamDevices(); + content::MediaStreamDeviceMap::const_iterator it = + request_->devices.find(content::MEDIA_STREAM_DEVICE_TYPE_VIDEO_CAPTURE); + DCHECK(it != request_->devices.end()); + return it->second; +} + +const std::string& MediaStreamInfoBarDelegate::GetSecurityOrigin() const { + return request_->security_origin; +} + +void MediaStreamInfoBarDelegate::Accept(const std::string& audio_id, + const std::string& video_id) { + content::MediaStreamDevices devices; + + if (has_audio_) { + AddDeviceWithId(content::MEDIA_STREAM_DEVICE_TYPE_AUDIO_CAPTURE, + audio_id, &devices); + } + if (has_video_) { + AddDeviceWithId(content::MEDIA_STREAM_DEVICE_TYPE_VIDEO_CAPTURE, + video_id, &devices); + } + + callback_.Run(devices); +} + +void MediaStreamInfoBarDelegate::Deny() { + callback_.Run(content::MediaStreamDevices()); +} + +void MediaStreamInfoBarDelegate::AddDeviceWithId( + content::MediaStreamDeviceType type, + const std::string& id, + content::MediaStreamDevices* devices) { + DCHECK(devices); + content::MediaStreamDeviceMap::const_iterator device_it = + request_->devices.find(type); + if (device_it != request_->devices.end()) { + content::MediaStreamDevices::const_iterator it = std::find_if( + device_it->second.begin(), device_it->second.end(), DeviceIdEquals(id)); + if (it != device_it->second.end()) + devices->push_back(*it); + } +} + +// MediaStreamInfoBarDelegate::CreateInfoBar is implemented in platform-specific +// files. + +#if !defined(TOOLKIT_VIEWS) +// TODO(macourteau): This section is temporary, until the InfoBar is implemented +// on other platforms, to make sure everything compiles and links. +InfoBar* MediaStreamInfoBarDelegate::CreateInfoBar(InfoBarTabHelper* owner) { + DCHECK(owner); + return NULL; +} +#endif // !TOOLKIT_VIEWS + +void MediaStreamInfoBarDelegate::InfoBarDismissed() { + // Deny the request if the infobar was closed with the 'x' button, since + // we don't want WebRTC to be waiting for an answer that will never come. + Deny(); +} + +gfx::Image* MediaStreamInfoBarDelegate::GetIcon() const { + return &ResourceBundle::GetSharedInstance().GetNativeImageNamed(has_video_ ? + IDR_INFOBAR_MEDIA_STREAM_CAMERA : IDR_INFOBAR_MEDIA_STREAM_MIC); +} + +InfoBarDelegate::Type MediaStreamInfoBarDelegate::GetInfoBarType() const { + return PAGE_ACTION_TYPE; +} + +MediaStreamInfoBarDelegate* + MediaStreamInfoBarDelegate::AsMediaStreamInfobarDelegate() { + return this; +} diff --git a/chrome/browser/ui/media_stream_infobar_delegate.h b/chrome/browser/ui/media_stream_infobar_delegate.h new file mode 100644 index 0000000..925e00d --- /dev/null +++ b/chrome/browser/ui/media_stream_infobar_delegate.h @@ -0,0 +1,82 @@ +// 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. + +#ifndef CHROME_BROWSER_UI_MEDIA_STREAM_INFOBAR_DELEGATE_H_ +#define CHROME_BROWSER_UI_MEDIA_STREAM_INFOBAR_DELEGATE_H_ + +#include <string> + +#include "base/callback.h" +#include "base/compiler_specific.h" +#include "chrome/browser/infobars/infobar_delegate.h" +#include "content/public/browser/content_browser_client.h" +#include "content/public/common/media_stream_request.h" + +class MessageLoop; +class TabContents; +class TabContentsWrapper; + +// This class configures an infobar shown when a page requests access to a +// user's microphone and/or video camera. The user is shown a message asking +// which audio and/or video devices he wishes to use with the current page, and +// buttons to give access to the selected devices to the page, or to deny access +// to them. +class MediaStreamInfoBarDelegate : public InfoBarDelegate { + public: + MediaStreamInfoBarDelegate( + InfoBarTabHelper* tab_helper, + const content::MediaStreamRequest* request, + const content::MediaResponseCallback& callback); + + virtual ~MediaStreamInfoBarDelegate(); + + // These tell whether the user has to select audio and/or video devices. + bool has_audio() const { return has_audio_; } + bool has_video() const { return has_video_; } + + // Returns lists of audio and/or video devices from which the user will have + // to choose. + content::MediaStreamDevices GetAudioDevices() const; + content::MediaStreamDevices GetVideoDevices() const; + + // Returns the security origin (e.g. "www.html5rocks.com") at the origin + // of this request. + const std::string& GetSecurityOrigin() const; + + // Callbacks to handle accepting devices or denying the request. |audio_id| + // and |video_id| are the device IDs of the accepted audio and video devices. + // The |audio_id| or |video_id| values are ignored if the request did not ask + // for audio or video devices respectively. + void Accept(const std::string& audio_id, const std::string& video_id); + void Deny(); + + private: + // Finds a device in the current request with the specified |id| and |type|, + // and adds it to the |devices| array. + void AddDeviceWithId(content::MediaStreamDeviceType type, + const std::string& id, + content::MediaStreamDevices* devices); + + // InfoBarDelegate: + virtual InfoBar* CreateInfoBar(InfoBarTabHelper* owner) OVERRIDE; + virtual void InfoBarDismissed() OVERRIDE; + virtual gfx::Image* GetIcon() const OVERRIDE; + virtual Type GetInfoBarType() const OVERRIDE; + virtual MediaStreamInfoBarDelegate* AsMediaStreamInfobarDelegate() OVERRIDE; + + // The original request for access to devices. + const content::MediaStreamRequest* request_; + + // The callback that needs to be Run to notify WebRTC of whether access to + // audio/video devices was granted or not. + content::MediaResponseCallback callback_; + + // Whether the request is for audio and/or video devices. + bool has_audio_; + bool has_video_; + + DISALLOW_COPY_AND_ASSIGN(MediaStreamInfoBarDelegate); +}; + +#endif // CHROME_BROWSER_UI_MEDIA_STREAM_INFOBAR_DELEGATE_H_ diff --git a/chrome/browser/ui/views/infobars/media_stream_infobar.cc b/chrome/browser/ui/views/infobars/media_stream_infobar.cc new file mode 100644 index 0000000..3bd6054 --- /dev/null +++ b/chrome/browser/ui/views/infobars/media_stream_infobar.cc @@ -0,0 +1,129 @@ +// 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 <algorithm> +#include <string> + +#include "base/utf_string_conversions.h" +#include "chrome/browser/infobars/infobar_tab_helper.h" +#include "chrome/browser/ui/media_stream_infobar_delegate.h" +#include "chrome/browser/ui/views/infobars/media_stream_infobar.h" +#include "grit/generated_resources.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/views/controls/button/menu_button.h" +#include "ui/views/controls/label.h" + +InfoBar* MediaStreamInfoBarDelegate::CreateInfoBar(InfoBarTabHelper* owner) { + DCHECK(owner); + return new MediaStreamInfoBar(owner, this); +} + +MediaStreamInfoBar::MediaStreamInfoBar( + InfoBarTabHelper* owner, + MediaStreamInfoBarDelegate* delegate) + : InfoBarView(owner, delegate), + delegate_(delegate), + label_(NULL), + allow_button_(NULL), + deny_button_(NULL), + devices_menu_button_(NULL), + devices_menu_model_(delegate) { +} + +MediaStreamInfoBar::~MediaStreamInfoBar() { +} + +void MediaStreamInfoBar::Layout() { + InfoBarView::Layout(); + + int available_width = std::max(0, EndX() - StartX() - ContentMinimumWidth()); + gfx::Size label_size = label_->GetPreferredSize(); + label_->SetBounds(StartX(), OffsetY(label_size), + std::min(label_size.width(), available_width), label_size.height()); + available_width = std::max(0, available_width - label_size.width()); + + gfx::Size allow_button_size = allow_button_->GetPreferredSize(); + allow_button_->SetBounds(label_->bounds().right() + kEndOfLabelSpacing, + OffsetY(allow_button_size), allow_button_size.width(), + allow_button_size.height()); + + gfx::Size deny_button_size = deny_button_->GetPreferredSize(); + deny_button_->SetBounds( + allow_button_->bounds().right() + kButtonButtonSpacing, + OffsetY(deny_button_size), deny_button_size.width(), + deny_button_size.height()); + + gfx::Size devices_size = devices_menu_button_->GetPreferredSize(); + devices_menu_button_->SetBounds(EndX() - devices_size.width(), + OffsetY(devices_size), devices_size.width(), devices_size.height()); +} + +void MediaStreamInfoBar::ViewHierarchyChanged(bool is_add, + View* parent, + View* child) { + if (is_add && child == this && (label_ == NULL)) { + int message_id = IDS_MEDIA_CAPTURE_MIC_AND_VIDEO; + DCHECK(delegate_->has_audio() || delegate_->has_video()); + if (!delegate_->has_audio()) + message_id = IDS_MEDIA_CAPTURE_VIDEO_ONLY; + else if (!delegate_->has_video()) + message_id = IDS_MEDIA_CAPTURE_MIC_ONLY; + + label_ = CreateLabel(l10n_util::GetStringFUTF16(message_id, + UTF8ToUTF16(delegate_->GetSecurityOrigin()))); + AddChildView(label_); + + allow_button_ = CreateTextButton(this, + l10n_util::GetStringUTF16(IDS_MEDIA_CAPTURE_ALLOW), false); + AddChildView(allow_button_); + + deny_button_ = CreateTextButton(this, + l10n_util::GetStringUTF16(IDS_MEDIA_CAPTURE_DENY), false); + AddChildView(deny_button_); + + devices_menu_button_ = CreateMenuButton( + l10n_util::GetStringUTF16(IDS_MEDIA_CAPTURE_DEVICES_MENU_TITLE), this); + AddChildView(devices_menu_button_); + } + + // This must happen after adding all other children so InfoBarView can ensure + // the close button is the last child. + InfoBarView::ViewHierarchyChanged(is_add, parent, child); +} + +void MediaStreamInfoBar::ButtonPressed(views::Button* sender, + const views::Event& event) { + if (!owned()) + return; // We're closing; don't call anything, it might access the owner. + if (sender == allow_button_) { + std::string audio_id, video_id; + devices_menu_model_.GetSelectedDeviceId( + content::MEDIA_STREAM_DEVICE_TYPE_AUDIO_CAPTURE, &audio_id); + devices_menu_model_.GetSelectedDeviceId( + content::MEDIA_STREAM_DEVICE_TYPE_VIDEO_CAPTURE, &video_id); + delegate_->Accept(audio_id, video_id); + RemoveSelf(); + } else if (sender == deny_button_) { + delegate_->Deny(); + RemoveSelf(); + } else { + InfoBarView::ButtonPressed(sender, event); + } +} + +int MediaStreamInfoBar::ContentMinimumWidth() const { + return + kEndOfLabelSpacing + + (allow_button_->GetPreferredSize().width() + kButtonButtonSpacing + + deny_button_->GetPreferredSize().width()) + + (kButtonButtonSpacing + devices_menu_button_->GetPreferredSize().width()); +} + +void MediaStreamInfoBar::RunMenu(View* source, const gfx::Point& pt) { + if (!owned()) + return; // We're closing; don't call anything, it might access the owner. + DCHECK_EQ(devices_menu_button_, source); + RunMenuAt(&devices_menu_model_, devices_menu_button_, + views::MenuItemView::TOPRIGHT); +} diff --git a/chrome/browser/ui/views/infobars/media_stream_infobar.h b/chrome/browser/ui/views/infobars/media_stream_infobar.h new file mode 100644 index 0000000..a5a913e --- /dev/null +++ b/chrome/browser/ui/views/infobars/media_stream_infobar.h @@ -0,0 +1,57 @@ +// 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. + +#ifndef CHROME_BROWSER_UI_VIEWS_INFOBARS_MEDIA_STREAM_INFOBAR_H_ +#define CHROME_BROWSER_UI_VIEWS_INFOBARS_MEDIA_STREAM_INFOBAR_H_ +#pragma once + +#include "chrome/browser/infobars/infobar_delegate.h" +#include "chrome/browser/media/media_stream_devices_menu_model.h" +#include "chrome/browser/ui/views/infobars/infobar_background.h" +#include "chrome/browser/ui/views/infobars/infobar_view.h" +#include "ui/views/controls/menu/view_menu_delegate.h" + +class MediaStreamInfoBarDelegate; + +namespace views { +class MenuButton; +} + +// Views implementation of the Media Stream InfoBar, which asks the user whether +// he wants to grant access to his camera/microphone to the current webpage. It +// also provides a way for the user to select which device(s) will be used by +// the page. +class MediaStreamInfoBar : public InfoBarView, public views::ViewMenuDelegate { + public: + MediaStreamInfoBar(InfoBarTabHelper* contents, + MediaStreamInfoBarDelegate* delegate); + + private: + virtual ~MediaStreamInfoBar(); + + // InfoBarView: + virtual void Layout() OVERRIDE; + virtual void ViewHierarchyChanged(bool is_add, + View* parent, + View* child) OVERRIDE; + virtual void ButtonPressed(views::Button* sender, + const views::Event& event) OVERRIDE; + virtual int ContentMinimumWidth() const OVERRIDE; + + // views::ViewMenuDelegate: + virtual void RunMenu(View* source, const gfx::Point& pt) OVERRIDE; + + MediaStreamInfoBarDelegate* delegate_; + + views::Label* label_; + views::TextButton* allow_button_; + views::TextButton* deny_button_; + views::MenuButton* devices_menu_button_; + + MediaStreamDevicesMenuModel devices_menu_model_; + + DISALLOW_COPY_AND_ASSIGN(MediaStreamInfoBar); +}; + +#endif // CHROME_BROWSER_UI_VIEWS_INFOBARS_MEDIA_STREAM_INFOBAR_H_ diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index a446acd..1b29ea5 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -1688,6 +1688,8 @@ 'browser/mac/scoped_launch_data.h', 'browser/media/media_internals.cc', 'browser/media/media_internals.h', + 'browser/media/media_stream_devices_menu_model.cc', + 'browser/media/media_stream_devices_menu_model.h', 'browser/memory_details.cc', 'browser/memory_details.h', 'browser/memory_details_android.cc', @@ -3375,6 +3377,8 @@ 'browser/ui/login/login_prompt_mac.mm', 'browser/ui/login/login_prompt_ui.cc', 'browser/ui/login/login_prompt_win.cc', + 'browser/ui/media_stream_infobar_delegate.cc', + 'browser/ui/media_stream_infobar_delegate.cc', 'browser/ui/omnibox/location_bar.h', 'browser/ui/omnibox/location_bar_util.cc', 'browser/ui/omnibox/location_bar_util.h', @@ -3726,6 +3730,8 @@ 'browser/ui/views/infobars/infobar_view.h', 'browser/ui/views/infobars/link_infobar.cc', 'browser/ui/views/infobars/link_infobar.h', + 'browser/ui/views/infobars/media_stream_infobar.cc', + 'browser/ui/views/infobars/media_stream_infobar.h', 'browser/ui/views/infobars/translate_infobar_base.cc', 'browser/ui/views/infobars/translate_infobar_base.h', 'browser/ui/views/infobars/translate_message_infobar.cc', diff --git a/content/browser/renderer_host/media/media_stream_device_settings.cc b/content/browser/renderer_host/media/media_stream_device_settings.cc index 3347480..0f473bd 100644 --- a/content/browser/renderer_host/media/media_stream_device_settings.cc +++ b/content/browser/renderer_host/media/media_stream_device_settings.cc @@ -39,7 +39,7 @@ class ResponseCallbackHelper } void PostResponse(const std::string& label, - const content::MediaStreamDeviceArray& devices) { + const content::MediaStreamDevices& devices) { if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, @@ -214,7 +214,7 @@ void MediaStreamDeviceSettings::AvailableDevices( void MediaStreamDeviceSettings::PostResponse( const std::string& label, - const content::MediaStreamDeviceArray& devices) { + const content::MediaStreamDevices& devices) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); SettingsRequests::iterator req = requests_.find(label); @@ -224,7 +224,7 @@ void MediaStreamDeviceSettings::PostResponse( if (devices.size() > 0) { // Build a list of "full" device objects for the accepted devices. StreamDeviceInfoArray deviceList; - for (content::MediaStreamDeviceArray::const_iterator dev = devices.begin(); + for (content::MediaStreamDevices::const_iterator dev = devices.begin(); dev != devices.end(); ++dev) { DeviceMap::iterator subList = req->second->devices_full.find(dev->type); DCHECK(subList != req->second->devices_full.end()); diff --git a/content/browser/renderer_host/media/media_stream_device_settings.h b/content/browser/renderer_host/media/media_stream_device_settings.h index 55b6d44..0a83cda 100644 --- a/content/browser/renderer_host/media/media_stream_device_settings.h +++ b/content/browser/renderer_host/media/media_stream_device_settings.h @@ -64,7 +64,7 @@ class CONTENT_EXPORT MediaStreamDeviceSettings // the requester. An empty list of devices means that access has been denied. // This method must be called on the IO thread. void PostResponse(const std::string& label, - const content::MediaStreamDeviceArray& devices); + const content::MediaStreamDevices& devices); // Used for testing only. This function is called to use faked UI, which is // needed for server based tests. The first non-opened device(s) will be diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h index a6adede..d848406 100644 --- a/content/public/browser/content_browser_client.h +++ b/content/public/browser/content_browser_client.h @@ -66,7 +66,7 @@ class BrowserContext; class ResourceContext; class WebUIControllerFactory; -typedef base::Callback< void(const content::MediaStreamDeviceArray&) > +typedef base::Callback< void(const content::MediaStreamDevices&) > MediaResponseCallback; // Embedder API (or SPI) for participating in browser logic, to be implemented diff --git a/content/public/common/media_stream_request.h b/content/public/common/media_stream_request.h index 7a5eceb..df9ce4e 100644 --- a/content/public/common/media_stream_request.h +++ b/content/public/common/media_stream_request.h @@ -39,9 +39,9 @@ struct CONTENT_EXPORT MediaStreamDevice { std::string name; }; -typedef std::vector<MediaStreamDevice> MediaStreamDeviceArray; +typedef std::vector<MediaStreamDevice> MediaStreamDevices; -typedef std::map<MediaStreamDeviceType, MediaStreamDeviceArray> +typedef std::map<MediaStreamDeviceType, MediaStreamDevices> MediaStreamDeviceMap; // Represents a request for media streams (audio/video). |