diff options
25 files changed, 767 insertions, 258 deletions
diff --git a/ash/ash.gyp b/ash/ash.gyp index 8c9cfdf..eedf7a7 100644 --- a/ash/ash.gyp +++ b/ash/ash.gyp @@ -325,21 +325,21 @@ 'system/chromeos/audio/tray_audio_chromeos.h', 'system/chromeos/audio/tray_audio_delegate_chromeos.cc', 'system/chromeos/audio/tray_audio_delegate_chromeos.h', - 'system/chromeos/enterprise/enterprise_domain_observer.h', 'system/chromeos/bluetooth/bluetooth_notification_controller.cc', 'system/chromeos/bluetooth/bluetooth_notification_controller.h', 'system/chromeos/brightness/brightness_controller_chromeos.cc', 'system/chromeos/brightness/brightness_controller_chromeos.h', 'system/chromeos/brightness/tray_brightness.cc', 'system/chromeos/brightness/tray_brightness.h', - 'system/chromeos/enterprise/tray_enterprise.h', + 'system/chromeos/enterprise/enterprise_domain_observer.h', 'system/chromeos/enterprise/tray_enterprise.cc', + 'system/chromeos/enterprise/tray_enterprise.h', 'system/chromeos/keyboard_brightness_controller.cc', 'system/chromeos/keyboard_brightness_controller.h', - 'system/chromeos/label_tray_view.h', 'system/chromeos/label_tray_view.cc', - 'system/chromeos/managed/tray_locally_managed_user.h', + 'system/chromeos/label_tray_view.h', 'system/chromeos/managed/tray_locally_managed_user.cc', + 'system/chromeos/managed/tray_locally_managed_user.h', 'system/chromeos/network/network_connect.cc', 'system/chromeos/network/network_connect.h', 'system/chromeos/network/network_detailed_view.h', @@ -441,6 +441,9 @@ 'system/tray/fixed_sized_scroll_view.h', 'system/tray/hover_highlight_view.cc', 'system/tray/hover_highlight_view.h', + 'system/tray/media_security/media_capture_observer.h', + 'system/tray/media_security/multi_profile_media_tray_item.cc', + 'system/tray/media_security/multi_profile_media_tray_item.h', 'system/tray/special_popup_row.cc', 'system/tray/special_popup_row.h', 'system/tray/system_tray.cc', @@ -729,6 +732,9 @@ ['exclude', 'display/display_configurator_animation.h'], ['exclude', 'display/resolution_notification_controller.cc'], ['exclude', 'display/resolution_notification_controller.h'], + ['exclude', 'system/tray/media_security/media_capture_observer.h'], + ['exclude', 'system/tray/media_security/multi_profile_media_tray_item.cc'], + ['exclude', 'system/tray/media_security/multi_profile_media_tray_item.h'], ], }], ], @@ -966,6 +972,7 @@ 'system/chromeos/tray_display_unittest.cc', 'system/date/date_view_unittest.cc', 'system/overview/overview_button_tray_unittest.cc', + 'system/tray/media_security/multi_profile_media_tray_item_unittest.cc', 'system/tray/system_tray_unittest.cc', 'system/tray/tray_details_view_unittest.cc', 'system/user/tray_user_unittest.cc', @@ -1031,6 +1038,7 @@ ['exclude', 'wm/workspace/workspace_window_resizer_unittest.cc'], ['exclude', 'sticky_keys/sticky_keys_overlay_unittest.cc'], ['exclude', 'sticky_keys/sticky_keys_unittest.cc'], + ['exclude', 'system/tray/media_security/multi_profile_media_tray_item_unittest.cc'], ['exclude', 'autoclick/autoclick_unittest.cc'], ], 'sources': [ @@ -1117,8 +1125,6 @@ 'sources': [ '../content/app/startup_helper_win.cc', '../ui/views/test/test_views_delegate.cc', - 'session/session_state_delegate_stub.cc', - 'session/session_state_delegate_stub.h', 'shell/app_list.cc', 'shell/bubble.cc', 'shell/content_client/shell_browser_main_parts.cc', diff --git a/ash/ash_chromeos_strings.grdp b/ash/ash_chromeos_strings.grdp index b0333ec..15a0fb7 100644 --- a/ash/ash_chromeos_strings.grdp +++ b/ash/ash_chromeos_strings.grdp @@ -305,6 +305,17 @@ Server message: <ph name="server_msg">$3<ex>Incorrect password</ex></ph> Stop </message> + <!-- Status tray media recording state strings. --> + <message name="IDS_ASH_STATUS_TRAY_MEDIA_RECORDING_AUDIO" desc="label used to indicate that the microphone is used by a background user"> + Micropohne is in use. + </message> + <message name="IDS_ASH_STATUS_TRAY_MEDIA_RECORDING_VIDEO" desc="label used to indicate that the camera is used by a background user"> + Camera is in use. + </message> + <message name="IDS_ASH_STATUS_TRAY_MEDIA_RECORDING_AUDIO_VIDEO" desc="label used to indicate that the camera and microphone are used by a background user"> + Camera and microphone are in use. + </message> + <!-- Status tray screen share strings. --> <message name="IDS_ASH_STATUS_TRAY_SCREEN_SHARE_STOP" desc="label used for screen sharing stop button"> Stop diff --git a/ash/ash_view_ids.h b/ash/ash_view_ids.h new file mode 100644 index 0000000..61bf3cf --- /dev/null +++ b/ash/ash_view_ids.h @@ -0,0 +1,18 @@ +// Copyright 2014 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 ASH_ASH_VIEW_IDS_H_ +#define ASH_ASH_VIEW_IDS_H_ + +namespace ash { + +enum ViewID { + VIEW_ID_NONE = 10000, + VIEW_ID_MEDIA_TRAY_VIEW, + VIEW_ID_USER_VIEW_MEDIA_INDICATOR, +}; + +} // namespace ash + +#endif // ASH_ASH_VIEW_IDS_H_ diff --git a/ash/media_delegate.h b/ash/media_delegate.h index 1dac059..4ea9a17 100644 --- a/ash/media_delegate.h +++ b/ash/media_delegate.h @@ -5,8 +5,19 @@ #ifndef ASH_MEDIA_DELEGATE_H_ #define ASH_MEDIA_DELEGATE_H_ +namespace content { +class BrowserContext; +} + namespace ash { +enum MediaCaptureState { + MEDIA_CAPTURE_NONE = 0, + MEDIA_CAPTURE_AUDIO = 1 << 0, + MEDIA_CAPTURE_VIDEO = 1 << 1, + MEDIA_CAPTURE_AUDIO_VIDEO = MEDIA_CAPTURE_AUDIO | MEDIA_CAPTURE_VIDEO, +}; + // A delegate class to control media playback. class MediaDelegate { public: @@ -20,6 +31,11 @@ class MediaDelegate { // Handles the Previous Track Media shortcut key. virtual void HandleMediaPrevTrack() = 0; + + // Returns the current media recording state of web contents + // that belongs to the |context|. + virtual MediaCaptureState GetMediaCaptureState( + content::BrowserContext* context) = 0; }; } // namespace ash diff --git a/ash/resources/ash_resources.grd b/ash/resources/ash_resources.grd index 1201745..aabbc18 100644 --- a/ash/resources/ash_resources.grd +++ b/ash/resources/ash_resources.grd @@ -77,6 +77,7 @@ <structure type="chrome_scaled_image" name="IDR_AURA_WARNING_ICON" file="common/alert_small.png" /> + <!-- TODO(oshima): Make following resources cros only --> <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_ACCESSIBILITY" file="cros/status/status_accessibility_mode.png" /> <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_ACCESSIBILITY_DARK" file="cros/status/status_accessibility_dark.png" /> <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_BLUETOOTH" file="cros/status/status_bluetooth.png" /> @@ -187,6 +188,8 @@ <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_NETWORK_VPN" file="cros/network/statusbar_vpn_dark.png" /> <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_NETWORK_VPN_BADGE" file="cros/network/statusbar_network_vpn_badge.png" /> <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_NETWORK_WIRED" file="cros/network/statusbar_wired.png" /> + <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_RECORDING" file="cros/status/status_recording.png" /> + <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_RECORDING_RED" file="cros/status/status_recording_red.png" /> <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_VIRTUAL_KEYBOARD" file="cros/status/status_virtual_keyboard.png" /> </if> diff --git a/ash/session/session_state_delegate_stub.cc b/ash/session/session_state_delegate_stub.cc deleted file mode 100644 index 05bca13..0000000 --- a/ash/session/session_state_delegate_stub.cc +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright (c) 2013 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 "ash/session/session_state_delegate_stub.h" - -#include "ash/session/user_info.h" -#include "ash/shell.h" -#include "ash/shell/example_factory.h" -#include "ash/shell_delegate.h" -#include "base/strings/string16.h" -#include "base/strings/utf_string_conversions.h" -#include "ui/gfx/image/image_skia.h" - -namespace ash { -namespace { - -class UserInfoStub : public UserInfo { - public: - UserInfoStub() {} - virtual ~UserInfoStub() {} - - // UserInfo: - virtual base::string16 GetDisplayName() const OVERRIDE { - return base::UTF8ToUTF16("stub-user"); - } - virtual base::string16 GetGivenName() const OVERRIDE { - return base::UTF8ToUTF16("Stub"); - } - virtual std::string GetEmail() const OVERRIDE { - return "stub-user@domain.com"; - } - virtual std::string GetUserID() const OVERRIDE { return GetEmail(); } - virtual const gfx::ImageSkia& GetImage() const OVERRIDE { - return user_image_; - } - - private: - gfx::ImageSkia user_image_; - - DISALLOW_COPY_AND_ASSIGN(UserInfoStub); -}; - -} // namespace - -SessionStateDelegateStub::SessionStateDelegateStub() - : screen_locked_(false), user_info_(new UserInfoStub()) { -} - -SessionStateDelegateStub::~SessionStateDelegateStub() { -} - -content::BrowserContext* SessionStateDelegateStub::GetBrowserContextByIndex( - MultiProfileIndex index) { - return Shell::GetInstance()->delegate()->GetActiveBrowserContext(); -} - -content::BrowserContext* SessionStateDelegateStub::GetBrowserContextForWindow( - aura::Window* window) { - return Shell::GetInstance()->delegate()->GetActiveBrowserContext(); -} - -int SessionStateDelegateStub::GetMaximumNumberOfLoggedInUsers() const { - return 3; -} - -int SessionStateDelegateStub::NumberOfLoggedInUsers() const { - return 1; -} - -bool SessionStateDelegateStub::IsActiveUserSessionStarted() const { - return true; -} - -bool SessionStateDelegateStub::CanLockScreen() const { - return true; -} - -bool SessionStateDelegateStub::IsScreenLocked() const { - return screen_locked_; -} - -bool SessionStateDelegateStub::ShouldLockScreenBeforeSuspending() const { - return false; -} - -void SessionStateDelegateStub::LockScreen() { - shell::CreateLockScreen(); - screen_locked_ = true; - Shell::GetInstance()->UpdateShelfVisibility(); -} - -void SessionStateDelegateStub::UnlockScreen() { - screen_locked_ = false; - Shell::GetInstance()->UpdateShelfVisibility(); -} - -bool SessionStateDelegateStub::IsUserSessionBlocked() const { - return !IsActiveUserSessionStarted() || IsScreenLocked(); -} - -SessionStateDelegate::SessionState SessionStateDelegateStub::GetSessionState() - const { - // Assume that if session is not active we're at login. - return IsActiveUserSessionStarted() ? SESSION_STATE_ACTIVE - : SESSION_STATE_LOGIN_PRIMARY; -} - -const UserInfo* SessionStateDelegateStub::GetUserInfo( - MultiProfileIndex index) const { - return user_info_.get(); -} - -const UserInfo* SessionStateDelegateStub::GetUserInfo( - content::BrowserContext* context) const { - return user_info_.get(); -} - -bool SessionStateDelegateStub::ShouldShowAvatar(aura::Window* window) const { - return !user_info_->GetImage().isNull(); -} - -void SessionStateDelegateStub::SwitchActiveUser(const std::string& user_id) { -} - -void SessionStateDelegateStub::CycleActiveUser(CycleUser cycle_user) { -} - -void SessionStateDelegateStub::AddSessionStateObserver( - ash::SessionStateObserver* observer) { -} - -void SessionStateDelegateStub::RemoveSessionStateObserver( - ash::SessionStateObserver* observer) { -} - -} // namespace ash diff --git a/ash/session/session_state_delegate_stub.h b/ash/session/session_state_delegate_stub.h deleted file mode 100644 index 5ce9cf3..0000000 --- a/ash/session/session_state_delegate_stub.h +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) 2013 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 ASH_SESSION_SESSION_STATE_DELEGATE_STUB_H_ -#define ASH_SESSION_SESSION_STATE_DELEGATE_STUB_H_ - -#include "ash/session/session_state_delegate.h" -#include "base/basictypes.h" -#include "base/compiler_specific.h" -#include "base/memory/scoped_ptr.h" - -namespace ash { - -// Stub implementation of SessionStateDelegate for testing. -class SessionStateDelegateStub : public SessionStateDelegate { - public: - SessionStateDelegateStub(); - virtual ~SessionStateDelegateStub(); - - // SessionStateDelegate: - virtual content::BrowserContext* GetBrowserContextByIndex( - MultiProfileIndex index) OVERRIDE; - virtual content::BrowserContext* GetBrowserContextForWindow( - aura::Window* window) OVERRIDE; - virtual int GetMaximumNumberOfLoggedInUsers() const OVERRIDE; - virtual int NumberOfLoggedInUsers() const OVERRIDE; - virtual bool IsActiveUserSessionStarted() const OVERRIDE; - virtual bool CanLockScreen() const OVERRIDE; - virtual bool IsScreenLocked() const OVERRIDE; - virtual bool ShouldLockScreenBeforeSuspending() const OVERRIDE; - virtual void LockScreen() OVERRIDE; - virtual void UnlockScreen() OVERRIDE; - virtual bool IsUserSessionBlocked() const OVERRIDE; - virtual SessionState GetSessionState() const OVERRIDE; - virtual const UserInfo* GetUserInfo(MultiProfileIndex index) const OVERRIDE; - virtual const UserInfo* GetUserInfo( - content::BrowserContext* context) const OVERRIDE; - virtual bool ShouldShowAvatar(aura::Window* window) const OVERRIDE; - virtual void SwitchActiveUser(const std::string& user_id) OVERRIDE; - virtual void CycleActiveUser(CycleUser cycle_user) OVERRIDE; - virtual void AddSessionStateObserver( - ash::SessionStateObserver* observer) OVERRIDE; - virtual void RemoveSessionStateObserver( - ash::SessionStateObserver* observer) OVERRIDE; - - private: - bool screen_locked_; - - // A pseudo user info. - scoped_ptr<UserInfo> user_info_; - - DISALLOW_COPY_AND_ASSIGN(SessionStateDelegateStub); -}; - -} // namespace ash - -#endif // ASH_SESSION_SESSION_STATE_DELEGATE_STUB_H_ diff --git a/ash/shell/shell_delegate_impl.cc b/ash/shell/shell_delegate_impl.cc index 2bf14e8..289d769 100644 --- a/ash/shell/shell_delegate_impl.cc +++ b/ash/shell/shell_delegate_impl.cc @@ -11,7 +11,7 @@ #include "ash/media_delegate.h" #include "ash/new_window_delegate.h" #include "ash/session/session_state_delegate.h" -#include "ash/session/session_state_delegate_stub.h" +#include "ash/session/user_info.h" #include "ash/shell/context_menu.h" #include "ash/shell/example_factory.h" #include "ash/shell/keyboard_controller_proxy_stub.h" @@ -21,6 +21,7 @@ #include "ash/system/tray/default_system_tray_delegate.h" #include "ash/wm/window_state.h" #include "base/message_loop/message_loop.h" +#include "base/strings/utf_string_conversions.h" #include "ui/aura/window.h" #include "ui/wm/core/input_method_event_filter.h" @@ -33,6 +34,7 @@ class NewWindowDelegateImpl : public NewWindowDelegate { NewWindowDelegateImpl() {} virtual ~NewWindowDelegateImpl() {} + // NewWindowDelegate: virtual void NewTab() OVERRIDE {} virtual void NewWindow(bool incognito) OVERRIDE { ash::shell::ToplevelWindow::CreateParams create_params; @@ -56,14 +58,115 @@ class MediaDelegateImpl : public MediaDelegate { MediaDelegateImpl() {} virtual ~MediaDelegateImpl() {} + // MediaDelegate: virtual void HandleMediaNextTrack() OVERRIDE {} virtual void HandleMediaPlayPause() OVERRIDE {} virtual void HandleMediaPrevTrack() OVERRIDE {} + virtual MediaCaptureState GetMediaCaptureState( + content::BrowserContext* context) OVERRIDE { + return MEDIA_CAPTURE_VIDEO; + } private: DISALLOW_COPY_AND_ASSIGN(MediaDelegateImpl); }; +class UserInfoImpl : public UserInfo { + public: + UserInfoImpl() {} + virtual ~UserInfoImpl() {} + + // UserInfo: + virtual base::string16 GetDisplayName() const OVERRIDE { + return base::UTF8ToUTF16("stub-user"); + } + virtual base::string16 GetGivenName() const OVERRIDE { + return base::UTF8ToUTF16("Stub"); + } + virtual std::string GetEmail() const OVERRIDE { + return "stub-user@domain.com"; + } + virtual std::string GetUserID() const OVERRIDE { return GetEmail(); } + virtual const gfx::ImageSkia& GetImage() const OVERRIDE { + return user_image_; + } + + private: + gfx::ImageSkia user_image_; + + DISALLOW_COPY_AND_ASSIGN(UserInfoImpl); +}; + +class SessionStateDelegateImpl : public SessionStateDelegate { + public: + SessionStateDelegateImpl() + : screen_locked_(false), user_info_(new UserInfoImpl()) {} + + virtual ~SessionStateDelegateImpl() {} + + // SessionStateDelegate: + virtual content::BrowserContext* GetBrowserContextByIndex( + MultiProfileIndex index) OVERRIDE { + return Shell::GetInstance()->delegate()->GetActiveBrowserContext(); + } + virtual content::BrowserContext* GetBrowserContextForWindow( + aura::Window* window) OVERRIDE { + return Shell::GetInstance()->delegate()->GetActiveBrowserContext(); + } + virtual int GetMaximumNumberOfLoggedInUsers() const OVERRIDE { return 3; } + virtual int NumberOfLoggedInUsers() const OVERRIDE { + // ash_shell has 2 users. + return 2; + } + virtual bool IsActiveUserSessionStarted() const OVERRIDE { return true; } + virtual bool CanLockScreen() const OVERRIDE { return true; } + virtual bool IsScreenLocked() const OVERRIDE { return screen_locked_; } + virtual bool ShouldLockScreenBeforeSuspending() const OVERRIDE { + return false; + } + virtual void LockScreen() OVERRIDE { + shell::CreateLockScreen(); + screen_locked_ = true; + Shell::GetInstance()->UpdateShelfVisibility(); + } + virtual void UnlockScreen() OVERRIDE { + screen_locked_ = false; + Shell::GetInstance()->UpdateShelfVisibility(); + } + virtual bool IsUserSessionBlocked() const OVERRIDE { + return !IsActiveUserSessionStarted() || IsScreenLocked(); + } + virtual SessionState GetSessionState() const OVERRIDE { + // Assume that if session is not active we're at login. + return IsActiveUserSessionStarted() ? SESSION_STATE_ACTIVE + : SESSION_STATE_LOGIN_PRIMARY; + } + virtual const UserInfo* GetUserInfo(MultiProfileIndex index) const OVERRIDE { + return user_info_.get(); + } + virtual const UserInfo* GetUserInfo( + content::BrowserContext* context) const OVERRIDE { + return user_info_.get(); + } + virtual bool ShouldShowAvatar(aura::Window* window) const OVERRIDE { + return !user_info_->GetImage().isNull(); + } + virtual void SwitchActiveUser(const std::string& user_id) OVERRIDE {} + virtual void CycleActiveUser(CycleUser cycle_user) OVERRIDE {} + virtual void AddSessionStateObserver( + ash::SessionStateObserver* observer) OVERRIDE {} + virtual void RemoveSessionStateObserver( + ash::SessionStateObserver* observer) OVERRIDE {} + + private: + bool screen_locked_; + + // A pseudo user info. + scoped_ptr<UserInfo> user_info_; + + DISALLOW_COPY_AND_ASSIGN(SessionStateDelegateImpl); +}; + } // namespace ShellDelegateImpl::ShellDelegateImpl() @@ -149,7 +252,7 @@ ash::UserWallpaperDelegate* ShellDelegateImpl::CreateUserWallpaperDelegate() { } ash::SessionStateDelegate* ShellDelegateImpl::CreateSessionStateDelegate() { - return new SessionStateDelegateStub; + return new SessionStateDelegateImpl; } ash::AccessibilityDelegate* ShellDelegateImpl::CreateAccessibilityDelegate() { diff --git a/ash/system/tray/media_security/media_capture_observer.h b/ash/system/tray/media_security/media_capture_observer.h new file mode 100644 index 0000000..9a217b2 --- /dev/null +++ b/ash/system/tray/media_security/media_capture_observer.h @@ -0,0 +1,23 @@ +// Copyright 2014 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 ASH_SYSTEM_CHROMEOS_MEDIA_SECURITY_MEDIA_CAPTURE_OBSERVER_H_ +#define ASH_SYSTEM_CHROMEOS_MEDIA_SECURITY_MEDIA_CAPTURE_OBSERVER_H_ + +#include "ash/ash_export.h" + +namespace ash { + +class ASH_EXPORT MediaCaptureObserver { + public: + // Called when media capture state has changed. + virtual void OnMediaCaptureChanged() = 0; + + protected: + virtual ~MediaCaptureObserver() {} +}; + +} // namespace ash + +#endif // ASH_SYSTEM_CHROMEOS_MEDIA_SECURITY_MEDIA_CAPTURE_OBSERVER_H_ diff --git a/ash/system/tray/media_security/multi_profile_media_tray_item.cc b/ash/system/tray/media_security/multi_profile_media_tray_item.cc new file mode 100644 index 0000000..7826fb7 --- /dev/null +++ b/ash/system/tray/media_security/multi_profile_media_tray_item.cc @@ -0,0 +1,85 @@ +// Copyright 2014 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 "ash/system/tray/media_security/multi_profile_media_tray_item.h" + +#include "ash/ash_view_ids.h" +#include "ash/media_delegate.h" +#include "ash/session/session_state_delegate.h" +#include "ash/shell.h" +#include "ash/system/tray/media_security/media_capture_observer.h" +#include "ash/system/tray/system_tray_notifier.h" +#include "ash/system/tray/tray_item_view.h" +#include "grit/ash_resources.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/views/controls/image_view.h" +#include "ui/views/layout/fill_layout.h" + +namespace ash { +namespace tray { + +class MultiProfileMediaTrayView : public TrayItemView, + public MediaCaptureObserver { + public: + explicit MultiProfileMediaTrayView(SystemTrayItem* system_tray_item) + : TrayItemView(system_tray_item) { + SetLayoutManager(new views::FillLayout); + views::ImageView* icon = new views::ImageView; + ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); + icon->SetImage( + bundle.GetImageNamed(IDR_AURA_UBER_TRAY_RECORDING).ToImageSkia()); + AddChildView(icon); + OnMediaCaptureChanged(); + Shell::GetInstance()->system_tray_notifier()->AddMediaCaptureObserver(this); + set_id(VIEW_ID_MEDIA_TRAY_VIEW); + } + + virtual ~MultiProfileMediaTrayView() { + Shell::GetInstance()->system_tray_notifier()->RemoveMediaCaptureObserver( + this); + } + + // MediaCaptureObserver: + virtual void OnMediaCaptureChanged() OVERRIDE { + MediaDelegate* media_delegate = Shell::GetInstance()->media_delegate(); + SessionStateDelegate* session_state_delegate = + Shell::GetInstance()->session_state_delegate(); + // The user at 0 is the current desktop user. + for (MultiProfileIndex index = 1; + index < session_state_delegate->NumberOfLoggedInUsers(); + ++index) { + content::BrowserContext* context = + session_state_delegate->GetBrowserContextByIndex(index); + if (media_delegate->GetMediaCaptureState(context) != MEDIA_CAPTURE_NONE) { + SetVisible(true); + return; + } + } + SetVisible(false); + } + + private: + DISALLOW_COPY_AND_ASSIGN(MultiProfileMediaTrayView); +}; + +} // namespace tray + +MultiProfileMediaTrayItem::MultiProfileMediaTrayItem(SystemTray* system_tray) + : SystemTrayItem(system_tray), tray_view_(NULL) { +} + +MultiProfileMediaTrayItem::~MultiProfileMediaTrayItem() { +} + +views::View* MultiProfileMediaTrayItem::CreateTrayView( + user::LoginStatus status) { + tray_view_ = new tray::MultiProfileMediaTrayView(this); + return tray_view_; +} + +void MultiProfileMediaTrayItem::DestroyTrayView() { + tray_view_ = NULL; +} + +} // namespace ash diff --git a/ash/system/tray/media_security/multi_profile_media_tray_item.h b/ash/system/tray/media_security/multi_profile_media_tray_item.h new file mode 100644 index 0000000..038bf8d --- /dev/null +++ b/ash/system/tray/media_security/multi_profile_media_tray_item.h @@ -0,0 +1,35 @@ +// Copyright 2014 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 ASH_SYSTEM_CHROMEOS_MULTI_PROFILE_MEDIA_TRAY_ITEM_H_ +#define ASH_SYSTEM_CHROMEOS_MULTI_PROFILE_MEDIA_TRAY_ITEM_H_ + +#include "ash/system/tray/system_tray_item.h" +#include "ui/message_center/notification_delegate.h" +#include "ui/views/view.h" + +namespace ash { +namespace tray { +class MultiProfileMediaTrayView; +} + +// The tray item for media recording. +class ASH_EXPORT MultiProfileMediaTrayItem : public SystemTrayItem { + public: + explicit MultiProfileMediaTrayItem(SystemTray* system_tray); + virtual ~MultiProfileMediaTrayItem(); + + // SystemTrayItem: + virtual views::View* CreateTrayView(user::LoginStatus status) OVERRIDE; + virtual void DestroyTrayView() OVERRIDE; + + private: + tray::MultiProfileMediaTrayView* tray_view_; + + DISALLOW_COPY_AND_ASSIGN(MultiProfileMediaTrayItem); +}; + +} // namespace ash + +#endif // ASH_SYSTEM_CHROMEOS_MULTI_PROFILE_MEDIA_TRAY_ITEM_H_ diff --git a/ash/system/tray/media_security/multi_profile_media_tray_item_unittest.cc b/ash/system/tray/media_security/multi_profile_media_tray_item_unittest.cc new file mode 100644 index 0000000..1dcfeaa --- /dev/null +++ b/ash/system/tray/media_security/multi_profile_media_tray_item_unittest.cc @@ -0,0 +1,58 @@ +// Copyright 2014 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 "ash/system/tray/media_security/multi_profile_media_tray_item.h" + +#include "ash/ash_view_ids.h" +#include "ash/shell.h" +#include "ash/system/status_area_widget.h" +#include "ash/system/tray/system_tray.h" +#include "ash/system/tray/system_tray_bubble.h" +#include "ash/system/tray/tray_item_view.h" +#include "ash/test/ash_test_base.h" +#include "ash/test/test_session_state_delegate.h" +#include "ash/test/test_shell_delegate.h" +#include "ui/views/bubble/tray_bubble_view.h" + +namespace ash { + +typedef test::AshTestBase MultiProfileMediaTrayItemTest; + +TEST_F(MultiProfileMediaTrayItemTest, NotifyMediaCaptureChange) { + TrayItemView::DisableAnimationsForTest(); + test::TestShellDelegate* shell_delegate = + static_cast<test::TestShellDelegate*>(Shell::GetInstance()->delegate()); + test::TestSessionStateDelegate* session_state_delegate = + static_cast<test::TestSessionStateDelegate*>( + Shell::GetInstance()->session_state_delegate()); + session_state_delegate->set_logged_in_users(2); + + SystemTray* system_tray = Shell::GetInstance()->GetPrimarySystemTray(); + system_tray->ShowDefaultView(BUBBLE_CREATE_NEW); + views::View* in_user_view = + system_tray->GetSystemBubble()->bubble_view()->GetViewByID( + VIEW_ID_USER_VIEW_MEDIA_INDICATOR); + + StatusAreaWidget* widget = system_tray->status_area_widget(); + EXPECT_TRUE(widget->GetRootView()->visible()); + views::View* tray_view = + widget->GetRootView()->GetViewByID(VIEW_ID_MEDIA_TRAY_VIEW); + + EXPECT_FALSE(tray_view->visible()); + EXPECT_FALSE(in_user_view->visible()); + + shell_delegate->SetMediaCaptureState(MEDIA_CAPTURE_AUDIO); + EXPECT_TRUE(tray_view->visible()); + EXPECT_TRUE(in_user_view->visible()); + + shell_delegate->SetMediaCaptureState(MEDIA_CAPTURE_AUDIO_VIDEO); + EXPECT_TRUE(tray_view->visible()); + EXPECT_TRUE(in_user_view->visible()); + + shell_delegate->SetMediaCaptureState(MEDIA_CAPTURE_NONE); + EXPECT_FALSE(tray_view->visible()); + EXPECT_FALSE(in_user_view->visible()); +} + +} // namespace ash diff --git a/ash/system/tray/system_tray.cc b/ash/system/tray/system_tray.cc index 726bbf3..d8ac9a5 100644 --- a/ash/system/tray/system_tray.cc +++ b/ash/system/tray/system_tray.cc @@ -61,6 +61,7 @@ #include "ash/system/chromeos/tray_caps_lock.h" #include "ash/system/chromeos/tray_display.h" #include "ash/system/chromeos/tray_tracing.h" +#include "ash/system/tray/media_security/multi_profile_media_tray_item.h" #include "ui/message_center/message_center.h" #elif defined(OS_WIN) #include "ash/system/win/audio/tray_audio_win.h" @@ -188,6 +189,7 @@ void SystemTray::CreateItems(SystemTrayDelegate* delegate) { AddTrayItem(new TrayDisplay(this)); AddTrayItem(new ScreenCaptureTrayItem(this)); AddTrayItem(new ScreenShareTrayItem(this)); + AddTrayItem(new MultiProfileMediaTrayItem(this)); AddTrayItem(new TrayAudioChromeOs(this)); AddTrayItem(new TrayBrightness(this)); AddTrayItem(new TrayCapsLock(this)); diff --git a/ash/system/tray/system_tray_notifier.cc b/ash/system/tray/system_tray_notifier.cc index ed858c3..5801ce6 100644 --- a/ash/system/tray/system_tray_notifier.cc +++ b/ash/system/tray/system_tray_notifier.cc @@ -151,6 +151,16 @@ void SystemTrayNotifier::RemoveEnterpriseDomainObserver( enterprise_domain_observers_.RemoveObserver(observer); } +void SystemTrayNotifier::AddMediaCaptureObserver( + MediaCaptureObserver* observer) { + media_capture_observers_.AddObserver(observer); +} + +void SystemTrayNotifier::RemoveMediaCaptureObserver( + MediaCaptureObserver* observer) { + media_capture_observers_.RemoveObserver(observer); +} + void SystemTrayNotifier::AddScreenCaptureObserver( ScreenCaptureObserver* observer) { screen_capture_observers_.AddObserver(observer); @@ -354,6 +364,11 @@ void SystemTrayNotifier::NotifyEnterpriseDomainChanged() { OnEnterpriseDomainChanged()); } +void SystemTrayNotifier::NotifyMediaCaptureChanged() { + FOR_EACH_OBSERVER( + MediaCaptureObserver, media_capture_observers_, OnMediaCaptureChanged()); +} + void SystemTrayNotifier::NotifyScreenCaptureStart( const base::Closure& stop_callback, const base::string16& sharing_app_name) { diff --git a/ash/system/tray/system_tray_notifier.h b/ash/system/tray/system_tray_notifier.h index 29cd9d2..6e6b03f 100644 --- a/ash/system/tray/system_tray_notifier.h +++ b/ash/system/tray/system_tray_notifier.h @@ -30,6 +30,7 @@ #include "ash/system/chromeos/session/last_window_closed_observer.h" #include "ash/system/chromeos/session/logout_button_observer.h" #include "ash/system/chromeos/session/session_length_limit_observer.h" +#include "ash/system/tray/media_security/media_capture_observer.h" #include "base/time/time.h" #endif @@ -92,6 +93,9 @@ class ASH_EXPORT SystemTrayNotifier { void AddEnterpriseDomainObserver(EnterpriseDomainObserver* observer); void RemoveEnterpriseDomainObserver(EnterpriseDomainObserver* observer); + void AddMediaCaptureObserver(MediaCaptureObserver* observer); + void RemoveMediaCaptureObserver(MediaCaptureObserver* observer); + void AddScreenCaptureObserver(ScreenCaptureObserver* observer); void RemoveScreenCaptureObserver(ScreenCaptureObserver* observer); @@ -133,6 +137,7 @@ class ASH_EXPORT SystemTrayNotifier { void NotifyRequestToggleWifi(); void NotifyOnCaptivePortalDetected(const std::string& service_path); void NotifyEnterpriseDomainChanged(); + void NotifyMediaCaptureChanged(); void NotifyScreenCaptureStart(const base::Closure& stop_callback, const base::string16& sharing_app_name); void NotifyScreenCaptureStop(); @@ -164,6 +169,7 @@ class ASH_EXPORT SystemTrayNotifier { ObserverList<NetworkPortalDetectorObserver> network_portal_detector_observers_; ObserverList<EnterpriseDomainObserver> enterprise_domain_observers_; + ObserverList<MediaCaptureObserver> media_capture_observers_; ObserverList<ScreenCaptureObserver> screen_capture_observers_; ObserverList<ScreenShareObserver> screen_share_observers_; ObserverList<LastWindowClosedObserver> last_window_closed_observers_; diff --git a/ash/system/user/user_card_view.cc b/ash/system/user/user_card_view.cc index af568ae..c1bdd15 100644 --- a/ash/system/user/user_card_view.cc +++ b/ash/system/user/user_card_view.cc @@ -11,6 +11,7 @@ #include "ash/session/user_info.h" #include "ash/shell.h" #include "ash/system/tray/system_tray_delegate.h" +#include "ash/system/tray/system_tray_notifier.h" #include "ash/system/tray/tray_constants.h" #include "ash/system/user/config.h" #include "ash/system/user/rounded_image_view.h" @@ -35,6 +36,14 @@ #include "ui/views/controls/link_listener.h" #include "ui/views/layout/box_layout.h" +#if defined(OS_CHROMEOS) +#include "ash/ash_view_ids.h" +#include "ash/media_delegate.h" +#include "ash/system/tray/media_security/media_capture_observer.h" +#include "ui/views/controls/image_view.h" +#include "ui/views/layout/fill_layout.h" +#endif + namespace ash { namespace tray { @@ -46,6 +55,70 @@ const int kUserDetailsVerticalPadding = 5; // and end of the user's display name in the public account user card's text. const base::char16 kDisplayNameMark[] = {0x2060, 0}; +#if defined(OS_CHROMEOS) +class MediaIndicator : public views::View, public MediaCaptureObserver { + public: + explicit MediaIndicator(MultiProfileIndex index) + : index_(index), label_(new views::Label) { + SetLayoutManager(new views::FillLayout); + views::ImageView* icon = new views::ImageView; + icon->SetImage(ui::ResourceBundle::GetSharedInstance() + .GetImageNamed(IDR_AURA_UBER_TRAY_RECORDING_RED) + .ToImageSkia()); + AddChildView(icon); + label_->SetHorizontalAlignment(gfx::ALIGN_LEFT); + label_->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList( + ui::ResourceBundle::SmallFont)); + OnMediaCaptureChanged(); + Shell::GetInstance()->system_tray_notifier()->AddMediaCaptureObserver(this); + set_id(VIEW_ID_USER_VIEW_MEDIA_INDICATOR); + } + + virtual ~MediaIndicator() { + Shell::GetInstance()->system_tray_notifier()->RemoveMediaCaptureObserver( + this); + } + + // MediaCaptureObserver: + virtual void OnMediaCaptureChanged() OVERRIDE { + Shell* shell = Shell::GetInstance(); + content::BrowserContext* context = + shell->session_state_delegate()->GetBrowserContextByIndex(index_); + MediaCaptureState state = + Shell::GetInstance()->media_delegate()->GetMediaCaptureState(context); + int res_id = 0; + switch (state) { + case MEDIA_CAPTURE_AUDIO_VIDEO: + res_id = IDS_ASH_STATUS_TRAY_MEDIA_RECORDING_AUDIO_VIDEO; + break; + case MEDIA_CAPTURE_AUDIO: + res_id = IDS_ASH_STATUS_TRAY_MEDIA_RECORDING_AUDIO; + break; + case MEDIA_CAPTURE_VIDEO: + res_id = IDS_ASH_STATUS_TRAY_MEDIA_RECORDING_VIDEO; + break; + case MEDIA_CAPTURE_NONE: + break; + } + SetMessage(res_id ? l10n_util::GetStringUTF16(res_id) : base::string16()); + } + + views::View* GetMessageView() { return label_; } + + void SetMessage(const base::string16& message) { + SetVisible(!message.empty()); + label_->SetText(message); + label_->SetVisible(!message.empty()); + } + + private: + MultiProfileIndex index_; + views::Label* label_; + + DISALLOW_COPY_AND_ASSIGN(MediaIndicator); +}; +#endif + // The user details shown in public account mode. This is essentially a label // but with custom painting code as the text is styled with multiple colors and // contains a link. @@ -301,7 +374,7 @@ void UserCardView::AddUserContent(user::LoginStatus login_status, int multiprofile_index) { views::View* icon = CreateIcon(login_status, multiprofile_index); AddChildView(icon); - views::Label* username = NULL; + views::Label* user_name = NULL; SessionStateDelegate* delegate = Shell::GetInstance()->session_state_delegate(); if (!multiprofile_index) { @@ -313,12 +386,12 @@ void UserCardView::AddUserContent(user::LoginStatus login_status, user_name_string = base::ASCIIToUTF16( delegate->GetUserInfo(multiprofile_index)->GetEmail()); if (!user_name_string.empty()) { - username = new views::Label(user_name_string); - username->SetHorizontalAlignment(gfx::ALIGN_LEFT); + user_name = new views::Label(user_name_string); + user_name->SetHorizontalAlignment(gfx::ALIGN_LEFT); } } - views::Label* additional = NULL; + views::Label* user_email = NULL; if (login_status != user::LOGGED_IN_GUEST && (multiprofile_index || !IsMultiAccountSupportedAndUserActive())) { base::string16 user_email_string = @@ -328,37 +401,55 @@ void UserCardView::AddUserContent(user::LoginStatus login_status, : base::UTF8ToUTF16( delegate->GetUserInfo(multiprofile_index)->GetEmail()); if (!user_email_string.empty()) { - additional = new views::Label(user_email_string); - additional->SetFontList( + user_email = new views::Label(user_email_string); + user_email->SetFontList( ui::ResourceBundle::GetSharedInstance().GetFontList( ui::ResourceBundle::SmallFont)); - additional->SetHorizontalAlignment(gfx::ALIGN_LEFT); + user_email->SetHorizontalAlignment(gfx::ALIGN_LEFT); } } // Adjust text properties dependent on if it is an active or inactive user. if (multiprofile_index) { // Fade the text of non active users to 50%. - SkColor text_color = additional->enabled_color(); + SkColor text_color = user_email->enabled_color(); text_color = SkColorSetA(text_color, SkColorGetA(text_color) / 2); - if (additional) - additional->SetDisabledColor(text_color); - if (username) - username->SetDisabledColor(text_color); + if (user_email) + user_email->SetDisabledColor(text_color); + if (user_name) + user_name->SetDisabledColor(text_color); } - if (additional && username) { + if (user_email && user_name) { views::View* details = new views::View; details->SetLayoutManager(new views::BoxLayout( views::BoxLayout::kVertical, 0, kUserDetailsVerticalPadding, 0)); - details->AddChildView(username); - details->AddChildView(additional); + details->AddChildView(user_name); + details->AddChildView(user_email); AddChildView(details); } else { - if (username) - AddChildView(username); - if (additional) - AddChildView(additional); + if (user_name) + AddChildView(user_name); + if (user_email) { +#if defined(OS_CHROMEOS) + // Only non active user can have a media indicator. + MediaIndicator* media_indicator = new MediaIndicator(multiprofile_index); + views::View* email_indicator_view = new views::View; + email_indicator_view->SetLayoutManager(new views::BoxLayout( + views::BoxLayout::kHorizontal, 0, 0, kTrayPopupPaddingBetweenItems)); + email_indicator_view->AddChildView(user_email); + email_indicator_view->AddChildView(media_indicator); + + views::View* details = new views::View; + details->SetLayoutManager(new views::BoxLayout( + views::BoxLayout::kVertical, 0, kUserDetailsVerticalPadding, 0)); + details->AddChildView(email_indicator_view); + details->AddChildView(media_indicator->GetMessageView()); + AddChildView(details); +#else + AddChildView(user_email); +#endif + } } } diff --git a/ash/system/user/user_view.cc b/ash/system/user/user_view.cc index f5eb6833..6707686 100644 --- a/ash/system/user/user_view.cc +++ b/ash/system/user/user_view.cc @@ -283,8 +283,8 @@ void UserView::Layout() { int remaining_width = contents_area.width() - logout_area.width(); if (IsMultiProfileSupportedAndUserActive() || IsMultiAccountSupportedAndUserActive()) { - // In multiprofile case |user_card_view_| and |logout_button_| have to - // have the same height. + // In multiprofile/multiaccount case |user_card_view_| and + // |logout_button_| have to have the same height. int y = std::min(user_card_area.y(), logout_area.y()); int height = std::max(user_card_area.height(), logout_area.height()); logout_area.set_y(y); diff --git a/ash/test/test_shell_delegate.cc b/ash/test/test_shell_delegate.cc index 52962ee..2a6597d 100644 --- a/ash/test/test_shell_delegate.cc +++ b/ash/test/test_shell_delegate.cc @@ -27,11 +27,21 @@ #include "ui/app_list/test/app_list_test_view_delegate.h" #include "ui/aura/window.h" +#if defined(OS_CHROMEOS) +#include "ash/system/tray/system_tray_notifier.h" +#endif + namespace ash { namespace test { namespace { class NewWindowDelegateImpl : public NewWindowDelegate { + public: + NewWindowDelegateImpl() {} + virtual ~NewWindowDelegateImpl() {} + + private: + // NewWindowDelegate: virtual void NewTab() OVERRIDE {} virtual void NewWindow(bool incognito) OVERRIDE {} virtual void OpenFileManager() OVERRIDE {} @@ -40,13 +50,30 @@ class NewWindowDelegateImpl : public NewWindowDelegate { virtual void ShowKeyboardOverlay() OVERRIDE {} virtual void ShowTaskManager() OVERRIDE {} virtual void OpenFeedbackPage() OVERRIDE {} + + DISALLOW_COPY_AND_ASSIGN(NewWindowDelegateImpl); }; class MediaDelegateImpl : public MediaDelegate { public: + MediaDelegateImpl() : state_(MEDIA_CAPTURE_NONE) {} + virtual ~MediaDelegateImpl() {} + + void set_media_capture_state(MediaCaptureState state) { state_ = state; } + + private: + // MediaDelegate: virtual void HandleMediaNextTrack() OVERRIDE {} virtual void HandleMediaPlayPause() OVERRIDE {} virtual void HandleMediaPrevTrack() OVERRIDE {} + virtual MediaCaptureState GetMediaCaptureState( + content::BrowserContext* context) OVERRIDE { + return state_; + } + + MediaCaptureState state_; + + DISALLOW_COPY_AND_ASSIGN(MediaDelegateImpl); }; } // namespace @@ -161,8 +188,13 @@ base::string16 TestShellDelegate::GetProductName() const { return base::string16(); } -TestSessionStateDelegate* TestShellDelegate::test_session_state_delegate() { - return test_session_state_delegate_; +void TestShellDelegate::SetMediaCaptureState(MediaCaptureState state) { +#if defined(OS_CHROMEOS) + Shell* shell = Shell::GetInstance(); + static_cast<MediaDelegateImpl*>(shell->media_delegate()) + ->set_media_capture_state(state); + shell->system_tray_notifier()->NotifyMediaCaptureChanged(); +#endif } } // namespace test diff --git a/ash/test/test_shell_delegate.h b/ash/test/test_shell_delegate.h index 1d8da2f..d92f80d 100644 --- a/ash/test/test_shell_delegate.h +++ b/ash/test/test_shell_delegate.h @@ -7,6 +7,7 @@ #include <string> +#include "ash/media_delegate.h" #include "ash/shell_delegate.h" #include "base/compiler_specific.h" #include "base/memory/scoped_ptr.h" @@ -63,7 +64,11 @@ class TestShellDelegate : public ShellDelegate { int num_exit_requests() const { return num_exit_requests_; } - TestSessionStateDelegate* test_session_state_delegate(); + TestSessionStateDelegate* test_session_state_delegate() { + return test_session_state_delegate_; + } + + void SetMediaCaptureState(MediaCaptureState state); private: int num_exit_requests_; diff --git a/chrome/browser/ui/ash/chrome_shell_delegate_chromeos.cc b/chrome/browser/ui/ash/chrome_shell_delegate_chromeos.cc index 3bfe3df..138ad5a 100644 --- a/chrome/browser/ui/ash/chrome_shell_delegate_chromeos.cc +++ b/chrome/browser/ui/ash/chrome_shell_delegate_chromeos.cc @@ -7,7 +7,6 @@ #include "ash/accelerators/magnifier_key_scroller.h" #include "ash/accelerators/spoken_feedback_toggler.h" #include "ash/accessibility_delegate.h" -#include "ash/media_delegate.h" #include "ash/wm/mru_window_tracker.h" #include "ash/wm/window_util.h" #include "base/command_line.h" @@ -20,8 +19,6 @@ #include "chrome/browser/chromeos/background/ash_user_wallpaper_delegate.h" #include "chrome/browser/chromeos/display/display_configuration_observer.h" #include "chrome/browser/chromeos/display/display_preferences.h" -#include "chrome/browser/chromeos/extensions/media_player_api.h" -#include "chrome/browser/chromeos/extensions/media_player_event_router.h" #include "chrome/browser/chromeos/profiles/profile_helper.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_manager.h" @@ -29,6 +26,7 @@ #include "chrome/browser/speech/tts_controller.h" #include "chrome/browser/sync/sync_error_notifier_factory_ash.h" #include "chrome/browser/ui/ash/chrome_new_window_delegate_chromeos.h" +#include "chrome/browser/ui/ash/media_delegate_chromeos.h" #include "chrome/browser/ui/ash/session_state_delegate_chromeos.h" #include "chrome/browser/ui/ash/system_tray_delegate_chromeos.h" #include "chrome/browser/ui/browser.h" @@ -209,33 +207,6 @@ class AccessibilityDelegateImpl : public ash::AccessibilityDelegate { DISALLOW_COPY_AND_ASSIGN(AccessibilityDelegateImpl); }; -class MediaDelegateImpl : public ash::MediaDelegate { - public: - MediaDelegateImpl() {} - virtual ~MediaDelegateImpl() {} - - virtual void HandleMediaNextTrack() OVERRIDE { - extensions::MediaPlayerAPI::Get( - ProfileManager::GetActiveUserProfile())-> - media_player_event_router()->NotifyNextTrack(); - } - - virtual void HandleMediaPlayPause() OVERRIDE { - extensions::MediaPlayerAPI::Get( - ProfileManager::GetActiveUserProfile())-> - media_player_event_router()->NotifyTogglePlayState(); - } - - virtual void HandleMediaPrevTrack() OVERRIDE { - extensions::MediaPlayerAPI::Get( - ProfileManager::GetActiveUserProfile())-> - media_player_event_router()->NotifyPrevTrack(); - } - - private: - DISALLOW_COPY_AND_ASSIGN(MediaDelegateImpl); -}; - } // anonymous namespace bool ChromeShellDelegate::IsFirstRunAfterBoot() const { @@ -268,7 +239,7 @@ ash::NewWindowDelegate* ChromeShellDelegate::CreateNewWindowDelegate() { } ash::MediaDelegate* ChromeShellDelegate::CreateMediaDelegate() { - return new MediaDelegateImpl; + return new MediaDelegateChromeOS; } ash::SystemTrayDelegate* ChromeShellDelegate::CreateSystemTrayDelegate() { diff --git a/chrome/browser/ui/ash/chrome_shell_delegate_views.cc b/chrome/browser/ui/ash/chrome_shell_delegate_views.cc index 1ce1cc0..3522aa5 100644 --- a/chrome/browser/ui/ash/chrome_shell_delegate_views.cc +++ b/chrome/browser/ui/ash/chrome_shell_delegate_views.cc @@ -61,6 +61,10 @@ class MediaDelegateImpl : public ash::MediaDelegate { virtual void HandleMediaNextTrack() OVERRIDE {} virtual void HandleMediaPlayPause() OVERRIDE {} virtual void HandleMediaPrevTrack() OVERRIDE {} + virtual ash::MediaCaptureState GetMediaCaptureState( + content::BrowserContext* context) OVERRIDE { + return ash::MEDIA_CAPTURE_NONE; + } private: DISALLOW_COPY_AND_ASSIGN(MediaDelegateImpl); diff --git a/chrome/browser/ui/ash/media_delegate_chromeos.cc b/chrome/browser/ui/ash/media_delegate_chromeos.cc new file mode 100644 index 0000000..ff92c70 --- /dev/null +++ b/chrome/browser/ui/ash/media_delegate_chromeos.cc @@ -0,0 +1,173 @@ +// Copyright 2014 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/ui/ash/media_delegate_chromeos.h" + +#include "apps/app_window.h" +#include "apps/app_window_registry.h" +#include "ash/shell.h" +#include "ash/system/tray/system_tray_notifier.h" +#include "base/message_loop/message_loop.h" +#include "chrome/browser/chromeos/extensions/media_player_api.h" +#include "chrome/browser/chromeos/extensions/media_player_event_router.h" +#include "chrome/browser/media/media_stream_capture_indicator.h" +#include "chrome/browser/profiles/profile_manager.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_list.h" +#include "chrome/browser/ui/browser_window.h" +#include "chrome/browser/ui/tabs/tab_strip_model.h" +#include "content/public/browser/render_view_host.h" +#include "content/public/browser/web_contents.h" +#include "extensions/browser/extension_system.h" +#include "extensions/browser/process_manager.h" + +namespace { + +void GetMediaCaptureState( + const MediaStreamCaptureIndicator* indicator, + content::WebContents* web_contents, + int* media_state_out) { + if (indicator->IsCapturingVideo(web_contents)) + *media_state_out |= ash::MEDIA_CAPTURE_VIDEO; + if (indicator->IsCapturingAudio(web_contents)) + *media_state_out |= ash::MEDIA_CAPTURE_AUDIO; +} + +void GetBrowserMediaCaptureState( + const MediaStreamCaptureIndicator* indicator, + const content::BrowserContext* context, + int* media_state_out) { + + const BrowserList* desktop_list = + BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH); + + for (BrowserList::BrowserVector::const_iterator iter = desktop_list->begin(); + iter != desktop_list->end(); + ++iter) { + TabStripModel* tab_strip_model = (*iter)->tab_strip_model(); + for (int i = 0; i < tab_strip_model->count(); ++i) { + content::WebContents* web_contents = tab_strip_model->GetWebContentsAt(i); + if (web_contents->GetBrowserContext() != context) + continue; + GetMediaCaptureState(indicator, web_contents, media_state_out); + if (*media_state_out == ash::MEDIA_CAPTURE_AUDIO_VIDEO) + return; + } + } +} + +void GetAppMediaCaptureState( + const MediaStreamCaptureIndicator* indicator, + content::BrowserContext* context, + int* media_state_out) { + const apps::AppWindowRegistry::AppWindowList& apps = + apps::AppWindowRegistry::Get(context)->app_windows(); + for (apps::AppWindowRegistry::AppWindowList::const_iterator iter = + apps.begin(); + iter != apps.end(); + ++iter) { + GetMediaCaptureState(indicator, (*iter)->web_contents(), media_state_out); + if (*media_state_out == ash::MEDIA_CAPTURE_AUDIO_VIDEO) + return; + } +} + +void GetExtensionMediaCaptureState( + const MediaStreamCaptureIndicator* indicator, + content::BrowserContext* context, + int* media_state_out) { + extensions::ProcessManager* process_manager = + extensions::ExtensionSystem::Get(context)->process_manager(); + const extensions::ProcessManager::ViewSet view_set = + process_manager->GetAllViews(); + for (extensions::ProcessManager::ViewSet::const_iterator iter = + view_set.begin(); + iter != view_set.end(); + ++iter) { + content::WebContents* web_contents = + content::WebContents::FromRenderViewHost(*iter); + // RVH may not have web contents. + if (!web_contents) + continue; + GetMediaCaptureState(indicator, web_contents, media_state_out); + if (*media_state_out == ash::MEDIA_CAPTURE_AUDIO_VIDEO) + return; + } +} + +ash::MediaCaptureState GetMediaCaptureStateOfAllWebContents( + content::BrowserContext* context) { + if (!context) + return ash::MEDIA_CAPTURE_NONE; + + scoped_refptr<MediaStreamCaptureIndicator> indicator = + MediaCaptureDevicesDispatcher::GetInstance() + ->GetMediaStreamCaptureIndicator(); + + int media_state = ash::MEDIA_CAPTURE_NONE; + // Browser windows + GetBrowserMediaCaptureState(indicator.get(), context, &media_state); + if (media_state == ash::MEDIA_CAPTURE_AUDIO_VIDEO) + return ash::MEDIA_CAPTURE_AUDIO_VIDEO; + + // App windows + GetAppMediaCaptureState(indicator.get(), context, &media_state); + if (media_state == ash::MEDIA_CAPTURE_AUDIO_VIDEO) + return ash::MEDIA_CAPTURE_AUDIO_VIDEO; + + // Extensions + GetExtensionMediaCaptureState(indicator.get(), context, &media_state); + + return static_cast<ash::MediaCaptureState>(media_state); +} + +} // namespace + +MediaDelegateChromeOS::MediaDelegateChromeOS() : weak_ptr_factory_(this) { + MediaCaptureDevicesDispatcher::GetInstance()->AddObserver(this); +} + +MediaDelegateChromeOS::~MediaDelegateChromeOS() { + MediaCaptureDevicesDispatcher::GetInstance()->RemoveObserver(this); +} + +void MediaDelegateChromeOS::HandleMediaNextTrack() { + extensions::MediaPlayerAPI::Get(ProfileManager::GetActiveUserProfile()) + ->media_player_event_router() + ->NotifyNextTrack(); +} + +void MediaDelegateChromeOS::HandleMediaPlayPause() { + extensions::MediaPlayerAPI::Get(ProfileManager::GetActiveUserProfile()) + ->media_player_event_router() + ->NotifyTogglePlayState(); +} + +void MediaDelegateChromeOS::HandleMediaPrevTrack() { + extensions::MediaPlayerAPI::Get(ProfileManager::GetActiveUserProfile()) + ->media_player_event_router() + ->NotifyPrevTrack(); +} + +ash::MediaCaptureState MediaDelegateChromeOS::GetMediaCaptureState( + content::BrowserContext* context) { + return GetMediaCaptureStateOfAllWebContents(context); +} + +void MediaDelegateChromeOS::OnRequestUpdate( + int render_process_id, + int render_view_id, + const content::MediaStreamDevice& device, + const content::MediaRequestState state) { + base::MessageLoopForUI::current()->PostTask( + FROM_HERE, + base::Bind(&MediaDelegateChromeOS::NotifyMediaCaptureChange, + weak_ptr_factory_.GetWeakPtr())); +} + +void MediaDelegateChromeOS::NotifyMediaCaptureChange() { + ash::Shell::GetInstance() + ->system_tray_notifier() + ->NotifyMediaCaptureChanged(); +} diff --git a/chrome/browser/ui/ash/media_delegate_chromeos.h b/chrome/browser/ui/ash/media_delegate_chromeos.h new file mode 100644 index 0000000..7370432 --- /dev/null +++ b/chrome/browser/ui/ash/media_delegate_chromeos.h @@ -0,0 +1,39 @@ +// Copyright 2014 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_ASH_MEDIA_DELEGATE_CHROMEOS_H_ +#define CHROME_BROWSER_UI_ASH_MEDIA_DELEGATE_CHROMEOS_H_ + +#include "ash/media_delegate.h" +#include "base/memory/weak_ptr.h" +#include "chrome/browser/media/media_capture_devices_dispatcher.h" + +class MediaDelegateChromeOS : public ash::MediaDelegate, + MediaCaptureDevicesDispatcher::Observer { + public: + MediaDelegateChromeOS(); + virtual ~MediaDelegateChromeOS(); + + // ash::MediaDelegate: + virtual void HandleMediaNextTrack() OVERRIDE; + virtual void HandleMediaPlayPause() OVERRIDE; + virtual void HandleMediaPrevTrack() OVERRIDE; + virtual ash::MediaCaptureState GetMediaCaptureState( + content::BrowserContext* context) OVERRIDE; + + // MediaCaptureDevicesDispatcher::Observer: + virtual void OnRequestUpdate(int render_process_id, + int render_view_id, + const content::MediaStreamDevice& device, + const content::MediaRequestState state) OVERRIDE; + + private: + void NotifyMediaCaptureChange(); + + base::WeakPtrFactory<MediaDelegateChromeOS> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(MediaDelegateChromeOS); +}; + +#endif // CHROME_BROWSER_UI_ASH_MEDIA_DELEGATE_CHROMEOS_H_ diff --git a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.cc b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.cc index 22798ca..452eacc 100644 --- a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.cc +++ b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.cc @@ -14,6 +14,7 @@ #include "ash/shell.h" #include "ash/shell_delegate.h" #include "ash/shell_window_ids.h" +#include "ash/system/tray/system_tray_notifier.h" #include "ash/wm/window_state.h" #include "base/auto_reset.h" #include "base/message_loop/message_loop.h" @@ -400,6 +401,11 @@ void MultiUserWindowManagerChromeOS::ActiveUserChanged( animation_.reset( new UserSwichAnimatorChromeOS( this, user_id, GetAdjustedAnimationTimeInMS(kUserFadeTimeMS))); + // Call notifier here instead of observing ActiveUserChanged because + // this must happen after MultiUserWindowManagerChromeOS is notified. + ash::Shell::GetInstance() + ->system_tray_notifier() + ->NotifyMediaCaptureChanged(); } void MultiUserWindowManagerChromeOS::OnWindowDestroyed(aura::Window* window) { diff --git a/chrome/chrome_browser_ui.gypi b/chrome/chrome_browser_ui.gypi index 9f7dd0e..5aa3781 100644 --- a/chrome/chrome_browser_ui.gypi +++ b/chrome/chrome_browser_ui.gypi @@ -333,6 +333,8 @@ 'browser/ui/ash/launcher/multi_profile_app_window_launcher_controller.h', 'browser/ui/ash/launcher/multi_profile_browser_status_monitor.cc', 'browser/ui/ash/launcher/multi_profile_browser_status_monitor.h', + 'browser/ui/ash/media_delegate_chromeos.cc', + 'browser/ui/ash/media_delegate_chromeos.h', 'browser/ui/ash/multi_user/multi_user_context_menu.cc', 'browser/ui/ash/multi_user/multi_user_context_menu.h', 'browser/ui/ash/multi_user/multi_user_context_menu_chromeos.cc', |