Commit 0dda0e3d authored by Jazz Xu's avatar Jazz Xu Committed by Commit Bot

CrOS GMC: Show media controls in quick setting.

This CL adds a media controls view in UnifiedSystemTrayView along with a
controller in UnifiedSystemTrayController.

Mocks, screenshot and screen record are linked in the bug.

Bug: 1128883

Change-Id: I0294bacce95c102c6056cb14332412283c10e4b6
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2406388
Commit-Queue: Jazz Xu <jazzhsu@chromium.org>
Reviewed-by: default avatarTim Song <tengs@chromium.org>
Reviewed-by: default avatarTommy Steimel <steimel@chromium.org>
Reviewed-by: default avatarTetsui Ohkubo <tetsui@chromium.org>
Cr-Commit-Position: refs/heads/master@{#809101}
parent 26c3c1a2
...@@ -966,6 +966,12 @@ component("ash") { ...@@ -966,6 +966,12 @@ component("ash") {
"system/machine_learning/user_settings_event_logger.h", "system/machine_learning/user_settings_event_logger.h",
"system/media/media_tray.cc", "system/media/media_tray.cc",
"system/media/media_tray.h", "system/media/media_tray.h",
"system/media/unified_media_controls_container.cc",
"system/media/unified_media_controls_container.h",
"system/media/unified_media_controls_controller.cc",
"system/media/unified_media_controls_controller.h",
"system/media/unified_media_controls_view.cc",
"system/media/unified_media_controls_view.h",
"system/message_center/arc_notification_manager_delegate_impl.cc", "system/message_center/arc_notification_manager_delegate_impl.cc",
"system/message_center/arc_notification_manager_delegate_impl.h", "system/message_center/arc_notification_manager_delegate_impl.h",
"system/message_center/ash_message_center_lock_screen_controller.cc", "system/message_center/ash_message_center_lock_screen_controller.cc",
...@@ -2067,6 +2073,7 @@ test("ash_unittests") { ...@@ -2067,6 +2073,7 @@ test("ash_unittests") {
"system/locale/locale_feature_pod_controller_unittest.cc", "system/locale/locale_feature_pod_controller_unittest.cc",
"system/machine_learning/user_settings_event_logger_unittest.cc", "system/machine_learning/user_settings_event_logger_unittest.cc",
"system/media/media_tray_unittest.cc", "system/media/media_tray_unittest.cc",
"system/media/unified_media_controls_controller_unittest.cc",
"system/message_center/ash_message_popup_collection_unittest.cc", "system/message_center/ash_message_popup_collection_unittest.cc",
"system/message_center/inactive_user_notification_blocker_unittest.cc", "system/message_center/inactive_user_notification_blocker_unittest.cc",
"system/message_center/message_center_ui_controller_unittest.cc", "system/message_center/message_center_ui_controller_unittest.cc",
......
...@@ -62,8 +62,8 @@ class GlobalMediaControlsTitleView : public views::View { ...@@ -62,8 +62,8 @@ class GlobalMediaControlsTitleView : public views::View {
} // namespace } // namespace
MediaTray::MediaTray(Shelf* shelf) : TrayBackgroundView(shelf) { MediaTray::MediaTray(Shelf* shelf) : TrayBackgroundView(shelf) {
DCHECK(MediaNotificationProvider::Get()); if (MediaNotificationProvider::Get())
MediaNotificationProvider::Get()->AddObserver(this); MediaNotificationProvider::Get()->AddObserver(this);
auto icon = std::make_unique<views::ImageView>(); auto icon = std::make_unique<views::ImageView>();
icon->SetTooltipText(l10n_util::GetStringUTF16( icon->SetTooltipText(l10n_util::GetStringUTF16(
......
// Copyright 2020 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/media/unified_media_controls_container.h"
#include "ash/system/tray/tray_constants.h"
#include "ui/views/border.h"
namespace ash {
namespace {
constexpr int kContainerHeight = 80;
constexpr gfx::Insets kContainerInsets = gfx::Insets(0, 16, 16, 16);
} // namespace
UnifiedMediaControlsContainer::UnifiedMediaControlsContainer()
: expanded_amount_(0.0f), should_show_media_controls_(false) {
SetBorder(views::CreateEmptyBorder(kContainerInsets));
}
void UnifiedMediaControlsContainer::SetShouldShowMediaControls(
bool should_show) {
should_show_media_controls_ = should_show;
SetVisible(expanded_amount_ > 0 && should_show_media_controls_);
InvalidateLayout();
}
void UnifiedMediaControlsContainer::SetExpandedAmount(double expanded_amount) {
SetVisible(expanded_amount > 0 && should_show_media_controls_);
expanded_amount_ = expanded_amount;
for (auto* child : children())
child->layer()->SetOpacity(expanded_amount);
InvalidateLayout();
}
int UnifiedMediaControlsContainer::GetExpandedHeight() const {
return should_show_media_controls_ ? kContainerHeight : 0;
}
void UnifiedMediaControlsContainer::Layout() {
for (auto* child : children())
child->SetBoundsRect(GetContentsBounds());
views::View::Layout();
}
gfx::Size UnifiedMediaControlsContainer::CalculatePreferredSize() const {
return gfx::Size(kTrayMenuWidth, GetExpandedHeight() * expanded_amount_);
}
} // namespace ash
// Copyright 2020 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_MEDIA_UNIFIED_MEDIA_CONTROLS_CONTAINER_H_
#define ASH_SYSTEM_MEDIA_UNIFIED_MEDIA_CONTROLS_CONTAINER_H_
#include "ui/views/view.h"
namespace ash {
// Container view of UnifiedMediaControlsView. This manages the
// visibility and expanded amount of the entire media controls view.
class UnifiedMediaControlsContainer : public views::View {
public:
UnifiedMediaControlsContainer();
~UnifiedMediaControlsContainer() override = default;
void SetShouldShowMediaControls(bool should_show);
void SetExpandedAmount(double expanded_amount);
int GetExpandedHeight() const;
// views::View
void Layout() override;
gfx::Size CalculatePreferredSize() const override;
private:
double expanded_amount_;
bool should_show_media_controls_;
};
} // namespace ash
#endif // ASH_SYSTEM_MEDIA_UNIFIED_MEDIA_CONTROLS_CONTAINER_H_
// Copyright 2020 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/media/unified_media_controls_controller.h"
#include "ash/shell.h"
#include "ash/shell_delegate.h"
#include "ash/system/media/unified_media_controls_view.h"
#include "services/media_session/public/cpp/util.h"
#include "services/media_session/public/mojom/media_session.mojom.h"
#include "services/media_session/public/mojom/media_session_service.mojom.h"
#include "ui/views/view.h"
namespace ash {
namespace {
constexpr int kMinimumArtworkSize = 30;
constexpr int kDisiredArtworkSize = 48;
// Time to wait for new media session.
constexpr base::TimeDelta kHideControlsDelay =
base::TimeDelta::FromMilliseconds(2000);
} // namespace
UnifiedMediaControlsController::UnifiedMediaControlsController(
Delegate* delegate)
: delegate_(delegate) {
media_session::mojom::MediaSessionService* service =
Shell::Get()->shell_delegate()->GetMediaSessionService();
// Happens in test.
if (!service)
return;
mojo::Remote<media_session::mojom::MediaControllerManager>
controller_manager_remote;
service->BindMediaControllerManager(
controller_manager_remote.BindNewPipeAndPassReceiver());
controller_manager_remote->CreateActiveMediaController(
media_controller_remote_.BindNewPipeAndPassReceiver());
media_controller_remote_->AddObserver(
observer_receiver_.BindNewPipeAndPassRemote());
media_controller_remote_->ObserveImages(
media_session::mojom::MediaSessionImageType::kArtwork,
kMinimumArtworkSize, kDisiredArtworkSize,
artwork_observer_receiver_.BindNewPipeAndPassRemote());
}
UnifiedMediaControlsController::~UnifiedMediaControlsController() = default;
views::View* UnifiedMediaControlsController::CreateView() {
media_controls_ = new UnifiedMediaControlsView(this);
return media_controls_;
}
void UnifiedMediaControlsController::MediaSessionInfoChanged(
media_session::mojom::MediaSessionInfoPtr session_info) {
if (hide_controls_timer_->IsRunning())
return;
if (!session_info)
return;
media_controls_->SetIsPlaying(
session_info->playback_state ==
media_session::mojom::MediaPlaybackState::kPlaying);
media_controls_->UpdateActionButtonAvailability(enabled_actions_);
}
void UnifiedMediaControlsController::MediaSessionMetadataChanged(
const base::Optional<media_session::MediaMetadata>& metadata) {
if (hide_controls_timer_->IsRunning())
return;
media_session::MediaMetadata session_metadata =
metadata.value_or(media_session::MediaMetadata());
media_controls_->SetTitle(session_metadata.title);
media_controls_->SetArtist(session_metadata.artist);
}
void UnifiedMediaControlsController::MediaSessionActionsChanged(
const std::vector<media_session::mojom::MediaSessionAction>& actions) {
if (hide_controls_timer_->IsRunning())
return;
enabled_actions_ = base::flat_set<media_session::mojom::MediaSessionAction>(
actions.begin(), actions.end());
media_controls_->UpdateActionButtonAvailability(enabled_actions_);
}
void UnifiedMediaControlsController::MediaSessionChanged(
const base::Optional<base::UnguessableToken>& request_id) {
// Stop the timer if we receive a new active sessoin.
if (hide_controls_timer_->IsRunning() && request_id.has_value())
hide_controls_timer_->Stop();
if (request_id == media_session_id_)
return;
// Start hide controls timer if there is no active session, wait to
// see if we will receive a new session.
if (!request_id.has_value()) {
hide_controls_timer_->Start(
FROM_HERE, kHideControlsDelay,
base::BindOnce(&UnifiedMediaControlsController::HideControls,
base::Unretained(this)));
return;
}
if (!media_session_id_.has_value())
delegate_->ShowMediaControls();
media_session_id_ = request_id;
}
void UnifiedMediaControlsController::MediaControllerImageChanged(
media_session::mojom::MediaSessionImageType type,
const SkBitmap& bitmap) {
if (hide_controls_timer_->IsRunning())
return;
if (type != media_session::mojom::MediaSessionImageType::kArtwork)
return;
// Convert the bitmap to kN32_SkColorType if necessary.
SkBitmap converted_bitmap;
if (bitmap.colorType() == kN32_SkColorType) {
converted_bitmap = bitmap;
} else {
SkImageInfo info = bitmap.info().makeColorType(kN32_SkColorType);
if (converted_bitmap.tryAllocPixels(info)) {
bitmap.readPixels(info, converted_bitmap.getPixels(),
converted_bitmap.rowBytes(), 0, 0);
}
}
base::Optional<gfx::ImageSkia> session_artwork;
if (!converted_bitmap.empty())
session_artwork = gfx::ImageSkia::CreateFrom1xBitmap(converted_bitmap);
media_controls_->SetArtwork(session_artwork);
}
void UnifiedMediaControlsController::PerformAction(
media_session::mojom::MediaSessionAction action) {
media_session::PerformMediaSessionAction(action, media_controller_remote_);
}
void UnifiedMediaControlsController::HideControls() {
media_session_id_ = base::nullopt;
delegate_->HideMediaControls();
}
void UnifiedMediaControlsController::FlushForTesting() {
media_controller_remote_.FlushForTesting(); // IN-TEST
}
} // namespace ash
// Copyright 2020 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_MEDIA_UNIFIED_MEDIA_CONTROLS_CONTROLLER_H_
#define ASH_SYSTEM_MEDIA_UNIFIED_MEDIA_CONTROLS_CONTROLLER_H_
#include "ash/ash_export.h"
#include "base/containers/flat_set.h"
#include "base/timer/timer.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/media_session/public/mojom/media_controller.mojom.h"
namespace views {
class View;
} // namespace views
namespace ash {
class UnifiedMediaControlsView;
// Controller class of UnifiedMediaControlsView. Handles events of the view
// and updates the view when receives media session updates.
class ASH_EXPORT UnifiedMediaControlsController
: public media_session::mojom::MediaControllerObserver,
public media_session::mojom::MediaControllerImageObserver {
public:
class Delegate {
public:
virtual ~Delegate() = default;
virtual void ShowMediaControls() = 0;
virtual void HideMediaControls() = 0;
};
explicit UnifiedMediaControlsController(Delegate* deleate);
~UnifiedMediaControlsController() override;
// media_session::mojom::MediaControllerObserver implementations.
void MediaSessionInfoChanged(
media_session::mojom::MediaSessionInfoPtr session_info) override;
void MediaSessionMetadataChanged(
const base::Optional<media_session::MediaMetadata>& metadata) override;
void MediaSessionActionsChanged(
const std::vector<media_session::mojom::MediaSessionAction>& actions)
override;
void MediaSessionChanged(
const base::Optional<base::UnguessableToken>& request_id) override;
void MediaSessionPositionChanged(
const base::Optional<media_session::MediaPosition>& position) override {}
// media_session::mojom::MediaControllerImageObserver implementations.
void MediaControllerImageChanged(
media_session::mojom::MediaSessionImageType type,
const SkBitmap& bitmap) override;
views::View* CreateView();
// Called from view when media buttons are pressed.
void PerformAction(media_session::mojom::MediaSessionAction action);
void FlushForTesting();
void set_media_controller_for_testing(
mojo::Remote<media_session::mojom::MediaController> controller) {
media_controller_remote_ = std::move(controller);
}
private:
void HideControls();
// Weak ptr, owned by view hierarchy.
UnifiedMediaControlsView* media_controls_ = nullptr;
// Delegate for show/hide media controls.
Delegate* const delegate_ = nullptr;
mojo::Remote<media_session::mojom::MediaController> media_controller_remote_;
mojo::Receiver<media_session::mojom::MediaControllerObserver>
observer_receiver_{this};
mojo::Receiver<media_session::mojom::MediaControllerImageObserver>
artwork_observer_receiver_{this};
std::unique_ptr<base::OneShotTimer> hide_controls_timer_ =
std::make_unique<base::OneShotTimer>();
base::Optional<base::UnguessableToken> media_session_id_;
base::flat_set<media_session::mojom::MediaSessionAction> enabled_actions_;
};
} // namespace ash
#endif // ASH_SYSTEM_MEDIA_UNIFIED_MEDIA_CONTROLS_CONTROLLER_H_
This diff is collapsed.
// Copyright 2020 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/media/unified_media_controls_view.h"
#include "ash/strings/grit/ash_strings.h"
#include "ash/style/ash_color_provider.h"
#include "ash/system/media/unified_media_controls_controller.h"
#include "ash/system/tray/tray_constants.h"
#include "components/media_message_center/media_notification_util.h"
#include "components/vector_icons/vector_icons.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/paint_vector_icon.h"
#include "ui/views/background.h"
#include "ui/views/border.h"
#include "ui/views/controls/image_view.h"
#include "ui/views/controls/label.h"
#include "ui/views/layout/box_layout.h"
namespace ash {
using media_session::mojom::MediaSessionAction;
namespace {
constexpr int kMediaControlsCornerRadius = 8;
constexpr int kMediaControlsViewPadding = 8;
constexpr int kMediaButtonsPadding = 4;
constexpr int kMediaButtonIconSize = 18;
constexpr int kArtworkCornerRadius = 4;
constexpr gfx::Insets kTrackColumnInsets = gfx::Insets(0, 8, 0, 0);
constexpr gfx::Insets kMediaControlsViewInsets = gfx::Insets(8, 8, 8, 8);
constexpr gfx::Size kArtworkSize = gfx::Size(48, 48);
constexpr gfx::Size kMediaButtonSize = gfx::Size(36, 36);
gfx::Size ScaleSizeToFitView(const gfx::Size& size,
const gfx::Size& view_size) {
// If |size| is too big in either dimension or two small in both
// dimensions, scale it appropriately.
if ((size.width() > view_size.width() ||
size.height() > view_size.height()) ||
(size.width() < view_size.width() &&
size.height() < view_size.height())) {
const float scale =
std::min(view_size.width() / static_cast<float>(size.width()),
view_size.height() / static_cast<float>(size.height()));
return gfx::ScaleToFlooredSize(size, scale);
}
return size;
}
const gfx::VectorIcon& GetVectorIconForMediaAction(MediaSessionAction action) {
switch (action) {
case MediaSessionAction::kPreviousTrack:
return vector_icons::kMediaPreviousTrackIcon;
case MediaSessionAction::kPause:
return vector_icons::kPauseIcon;
case MediaSessionAction::kNextTrack:
return vector_icons::kMediaNextTrackIcon;
case MediaSessionAction::kPlay:
return vector_icons::kPlayArrowIcon;
// Actions that are not supported.
case MediaSessionAction::kSeekBackward:
case MediaSessionAction::kSeekForward:
case MediaSessionAction::kStop:
case MediaSessionAction::kSkipAd:
case MediaSessionAction::kSeekTo:
case MediaSessionAction::kScrubTo:
case MediaSessionAction::kEnterPictureInPicture:
case MediaSessionAction::kExitPictureInPicture:
case MediaSessionAction::kSwitchAudioDevice:
NOTREACHED();
break;
}
NOTREACHED();
return gfx::kNoneIcon;
}
} // namespace
UnifiedMediaControlsView::MediaActionButton::MediaActionButton(
views::ButtonListener* listener,
MediaSessionAction action,
const base::string16& accessible_name)
: views::ImageButton(listener) {
SetImageHorizontalAlignment(views::ImageButton::ALIGN_CENTER);
SetImageVerticalAlignment(views::ImageButton::ALIGN_MIDDLE);
SetPreferredSize(kMediaButtonSize);
SetAction(action, accessible_name);
}
void UnifiedMediaControlsView::MediaActionButton::SetAction(
MediaSessionAction action,
const base::string16& accessible_name) {
set_tag(static_cast<int>(action));
SetTooltipText(accessible_name);
SetImage(views::Button::STATE_NORMAL,
CreateVectorIcon(
GetVectorIconForMediaAction(action), kMediaButtonIconSize,
AshColorProvider::Get()->GetContentLayerColor(
AshColorProvider::ContentLayerType::kIconColorPrimary)));
SetImage(views::Button::STATE_DISABLED,
CreateVectorIcon(
GetVectorIconForMediaAction(action), kMediaButtonIconSize,
AshColorProvider::Get()->GetContentLayerColor(
AshColorProvider::ContentLayerType::kIconColorSecondary)));
}
UnifiedMediaControlsView::UnifiedMediaControlsView(
UnifiedMediaControlsController* controller)
: controller_(controller) {
SetBackground(views::CreateRoundedRectBackground(
AshColorProvider::Get()->GetControlsLayerColor(
AshColorProvider::ControlsLayerType::kControlBackgroundColorInactive),
kMediaControlsCornerRadius));
auto* box_layout = SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kHorizontal, kMediaControlsViewInsets,
kMediaControlsViewPadding));
box_layout->set_cross_axis_alignment(
views::BoxLayout::CrossAxisAlignment::kCenter);
auto artwork_view = std::make_unique<views::ImageView>();
artwork_view->SetPreferredSize(kArtworkSize);
artwork_view_ = AddChildView(std::move(artwork_view));
artwork_view_->SetVisible(false);
auto track_column = std::make_unique<views::View>();
track_column->SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kVertical, kTrackColumnInsets));
auto config_label = [](views::Label* label) {
label->SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_LEFT);
label->SetAutoColorReadabilityEnabled(false);
label->SetSubpixelRenderingEnabled(false);
};
auto title_label = std::make_unique<views::Label>();
config_label(title_label.get());
title_label->SetEnabledColor(AshColorProvider::Get()->GetContentLayerColor(
AshColorProvider::ContentLayerType::kTextColorPrimary));
title_label_ = track_column->AddChildView(std::move(title_label));
auto artist_label = std::make_unique<views::Label>();
config_label(artist_label.get());
artist_label->SetEnabledColor(AshColorProvider::Get()->GetContentLayerColor(
AshColorProvider::ContentLayerType::kTextColorSecondary));
artist_label_ = track_column->AddChildView(std::move(artist_label));
box_layout->SetFlexForView(AddChildView(std::move(track_column)), 1);
auto button_row = std::make_unique<views::View>();
button_row->SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kHorizontal, gfx::Insets(),
kMediaButtonsPadding));
button_row->AddChildView(std::make_unique<MediaActionButton>(
this, MediaSessionAction::kPreviousTrack,
l10n_util::GetStringUTF16(
IDS_ASH_MEDIA_NOTIFICATION_ACTION_PREVIOUS_TRACK)));
play_pause_button_ =
button_row->AddChildView(std::make_unique<MediaActionButton>(
this, MediaSessionAction::kPause,
l10n_util::GetStringUTF16(IDS_ASH_MEDIA_NOTIFICATION_ACTION_PAUSE)));
button_row->AddChildView(std::make_unique<MediaActionButton>(
this, MediaSessionAction::kNextTrack,
l10n_util::GetStringUTF16(IDS_ASH_MEDIA_NOTIFICATION_ACTION_NEXT_TRACK)));
button_row_ = AddChildView(std::move(button_row));
}
void UnifiedMediaControlsView::ButtonPressed(views::Button* sender,
const ui::Event& event) {
controller_->PerformAction(
media_message_center::GetActionFromButtonTag(*sender));
}
void UnifiedMediaControlsView::SetIsPlaying(bool playing) {
if (playing) {
play_pause_button_->SetAction(
MediaSessionAction::kPause,
l10n_util::GetStringUTF16(IDS_ASH_MEDIA_NOTIFICATION_ACTION_PAUSE));
} else {
play_pause_button_->SetAction(
MediaSessionAction::kPlay,
l10n_util::GetStringUTF16(IDS_ASH_MEDIA_NOTIFICATION_ACTION_PLAY));
}
}
void UnifiedMediaControlsView::SetArtwork(
base::Optional<gfx::ImageSkia> artwork) {
if (!artwork.has_value()) {
artwork_view_->SetImage(nullptr);
artwork_view_->SetVisible(false);
artwork_view_->InvalidateLayout();
return;
}
artwork_view_->SetVisible(true);
gfx::Size image_size = ScaleSizeToFitView(artwork->size(), kArtworkSize);
artwork_view_->SetImageSize(image_size);
artwork_view_->SetImage(*artwork);
Layout();
artwork_view_->SetClipPath(GetArtworkClipPath());
}
void UnifiedMediaControlsView::SetTitle(const base::string16& title) {
title_label_->SetText(title);
}
void UnifiedMediaControlsView::SetArtist(const base::string16& artist) {
artist_label_->SetText(artist);
}
void UnifiedMediaControlsView::UpdateActionButtonAvailability(
const base::flat_set<MediaSessionAction>& enabled_actions) {
for (views::View* child : button_row_->children()) {
views::Button* button = static_cast<views::Button*>(child);
button->SetEnabled(
base::Contains(enabled_actions,
media_message_center::GetActionFromButtonTag(*button)));
}
}
SkPath UnifiedMediaControlsView::GetArtworkClipPath() {
// Calculate image bounds since we might need to draw this when image is
// not visible (i.e. when quick setting bubble is collapsed).
gfx::Size image_size = artwork_view_->GetImageBounds().size();
int x = (kArtworkSize.width() - image_size.width()) / 2;
int y = (kArtworkSize.height() - image_size.height()) / 2;
SkPath path;
path.addRoundRect(gfx::RectToSkRect(gfx::Rect(x, y, image_size.width(),
image_size.height())),
kArtworkCornerRadius, kArtworkCornerRadius);
return path;
}
} // namespace ash
// Copyright 2020 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_MEDIA_UNIFIED_MEDIA_CONTROLS_VIEW_H_
#define ASH_SYSTEM_MEDIA_UNIFIED_MEDIA_CONTROLS_VIEW_H_
#include "ash/ash_export.h"
#include "base/containers/flat_set.h"
#include "base/optional.h"
#include "services/media_session/public/mojom/media_session.mojom.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/controls/button/image_button.h"
#include "ui/views/view.h"
namespace gfx {
class ImageSkia;
} // namespace gfx
namespace views {
class ImageView;
class Label;
} // namespace views
namespace ash {
class UnifiedMediaControlsController;
// Media controls view displayed in quick settings.
class ASH_EXPORT UnifiedMediaControlsView : public views::View,
public views::ButtonListener {
public:
explicit UnifiedMediaControlsView(UnifiedMediaControlsController* controller);
~UnifiedMediaControlsView() override = default;
// ButtonListener implementation.
void ButtonPressed(views::Button* sender, const ui::Event& event) override;
void SetIsPlaying(bool playing);
void SetArtwork(base::Optional<gfx::ImageSkia> artwork);
void SetTitle(const base::string16& title);
void SetArtist(const base::string16& artist);
void UpdateActionButtonAvailability(
const base::flat_set<media_session::mojom::MediaSessionAction>&
enabled_actions);
private:
friend class UnifiedMediaControlsControllerTest;
class MediaActionButton : public views::ImageButton {
public:
MediaActionButton(views::ButtonListener* listener,
media_session::mojom::MediaSessionAction action,
const base::string16& accessible_name);
~MediaActionButton() override = default;
void SetAction(media_session::mojom::MediaSessionAction action,
const base::string16& accessible_name);
};
SkPath GetArtworkClipPath();
UnifiedMediaControlsController* const controller_ = nullptr;
views::ImageView* artwork_view_ = nullptr;
views::Label* title_label_ = nullptr;
views::Label* artist_label_ = nullptr;
MediaActionButton* play_pause_button_ = nullptr;
views::View* button_row_ = nullptr;
};
} // namespace ash
#endif // ASH_SYSTEM_MEDIA_UNIFIED_MEDIA_CONTROLS_VIEW_H_
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include "ash/system/ime/unified_ime_detailed_view_controller.h" #include "ash/system/ime/unified_ime_detailed_view_controller.h"
#include "ash/system/locale/locale_feature_pod_controller.h" #include "ash/system/locale/locale_feature_pod_controller.h"
#include "ash/system/locale/unified_locale_detailed_view_controller.h" #include "ash/system/locale/unified_locale_detailed_view_controller.h"
#include "ash/system/media/unified_media_controls_controller.h"
#include "ash/system/model/clock_model.h" #include "ash/system/model/clock_model.h"
#include "ash/system/model/system_tray_model.h" #include "ash/system/model/system_tray_model.h"
#include "ash/system/network/network_feature_pod_controller.h" #include "ash/system/network/network_feature_pod_controller.h"
...@@ -53,6 +54,7 @@ ...@@ -53,6 +54,7 @@
#include "base/metrics/histogram_macros.h" #include "base/metrics/histogram_macros.h"
#include "base/metrics/user_metrics.h" #include "base/metrics/user_metrics.h"
#include "base/numerics/ranges.h" #include "base/numerics/ranges.h"
#include "media/base/media_switches.h"
#include "ui/accessibility/ax_enums.mojom.h" #include "ui/accessibility/ax_enums.mojom.h"
#include "ui/compositor/animation_metrics_reporter.h" #include "ui/compositor/animation_metrics_reporter.h"
#include "ui/gfx/animation/slide_animation.h" #include "ui/gfx/animation/slide_animation.h"
...@@ -130,6 +132,13 @@ UnifiedSystemTrayView* UnifiedSystemTrayController::CreateView() { ...@@ -130,6 +132,13 @@ UnifiedSystemTrayView* UnifiedSystemTrayController::CreateView() {
unified_view_ = new UnifiedSystemTrayView(this, model_->IsExpandedOnOpen()); unified_view_ = new UnifiedSystemTrayView(this, model_->IsExpandedOnOpen());
InitFeaturePods(); InitFeaturePods();
if (base::FeatureList::IsEnabled(media::kGlobalMediaControlsForChromeOS)) {
media_controls_controller_ =
std::make_unique<UnifiedMediaControlsController>(this);
unified_view_->AddMediaControlsView(
media_controls_controller_->CreateView());
}
volume_slider_controller_ = volume_slider_controller_ =
std::make_unique<UnifiedVolumeSliderController>(this); std::make_unique<UnifiedVolumeSliderController>(this);
unified_view_->AddSliderView(volume_slider_controller_->CreateView()); unified_view_->AddSliderView(volume_slider_controller_->CreateView());
...@@ -407,6 +416,14 @@ void UnifiedSystemTrayController::OnAudioSettingsButtonClicked() { ...@@ -407,6 +416,14 @@ void UnifiedSystemTrayController::OnAudioSettingsButtonClicked() {
ShowAudioDetailedView(); ShowAudioDetailedView();
} }
void UnifiedSystemTrayController::ShowMediaControls() {
unified_view_->ShowMediaControls();
}
void UnifiedSystemTrayController::HideMediaControls() {
unified_view_->HideMediaControls();
}
void UnifiedSystemTrayController::InitFeaturePods() { void UnifiedSystemTrayController::InitFeaturePods() {
AddFeaturePodItem(std::make_unique<NetworkFeaturePodController>(this)); AddFeaturePodItem(std::make_unique<NetworkFeaturePodController>(this));
AddFeaturePodItem(std::make_unique<BluetoothFeaturePodController>(this)); AddFeaturePodItem(std::make_unique<BluetoothFeaturePodController>(this));
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "ash/ash_export.h" #include "ash/ash_export.h"
#include "ash/system/audio/unified_volume_slider_controller.h" #include "ash/system/audio/unified_volume_slider_controller.h"
#include "ash/system/media/unified_media_controls_controller.h"
#include "ash/system/unified/unified_system_tray_model.h" #include "ash/system/unified/unified_system_tray_model.h"
#include "base/macros.h" #include "base/macros.h"
#include "ui/gfx/geometry/point.h" #include "ui/gfx/geometry/point.h"
...@@ -24,6 +25,7 @@ namespace ash { ...@@ -24,6 +25,7 @@ namespace ash {
class DetailedViewController; class DetailedViewController;
class FeaturePodControllerBase; class FeaturePodControllerBase;
class PaginationController; class PaginationController;
class UnifiedMediaControlsController;
class UnifiedBrightnessSliderController; class UnifiedBrightnessSliderController;
class UnifiedVolumeSliderController; class UnifiedVolumeSliderController;
class UnifiedSystemTrayBubble; class UnifiedSystemTrayBubble;
...@@ -33,7 +35,8 @@ class UnifiedSystemTrayView; ...@@ -33,7 +35,8 @@ class UnifiedSystemTrayView;
// Controller class of UnifiedSystemTrayView. Handles events of the view. // Controller class of UnifiedSystemTrayView. Handles events of the view.
class ASH_EXPORT UnifiedSystemTrayController class ASH_EXPORT UnifiedSystemTrayController
: public views::AnimationDelegateViews, : public views::AnimationDelegateViews,
public UnifiedVolumeSliderController::Delegate { public UnifiedVolumeSliderController::Delegate,
public UnifiedMediaControlsController::Delegate {
public: public:
UnifiedSystemTrayController(UnifiedSystemTrayModel* model, UnifiedSystemTrayController(UnifiedSystemTrayModel* model,
UnifiedSystemTrayBubble* bubble = nullptr, UnifiedSystemTrayBubble* bubble = nullptr,
...@@ -127,6 +130,10 @@ class ASH_EXPORT UnifiedSystemTrayController ...@@ -127,6 +130,10 @@ class ASH_EXPORT UnifiedSystemTrayController
// UnifiedVolumeSliderController::Delegate: // UnifiedVolumeSliderController::Delegate:
void OnAudioSettingsButtonClicked() override; void OnAudioSettingsButtonClicked() override;
// UnifedMediaControlsController::Delegate;
void ShowMediaControls() override;
void HideMediaControls() override;
UnifiedSystemTrayModel* model() { return model_; } UnifiedSystemTrayModel* model() { return model_; }
PaginationController* pagination_controller() { PaginationController* pagination_controller() {
...@@ -212,6 +219,8 @@ class ASH_EXPORT UnifiedSystemTrayController ...@@ -212,6 +219,8 @@ class ASH_EXPORT UnifiedSystemTrayController
std::unique_ptr<PaginationController> pagination_controller_; std::unique_ptr<PaginationController> pagination_controller_;
std::unique_ptr<UnifiedMediaControlsController> media_controls_controller_;
// Controller of volume slider. Owned. // Controller of volume slider. Owned.
std::unique_ptr<UnifiedVolumeSliderController> volume_slider_controller_; std::unique_ptr<UnifiedVolumeSliderController> volume_slider_controller_;
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "ash/shelf/shelf_widget.h" #include "ash/shelf/shelf_widget.h"
#include "ash/shell.h" #include "ash/shell.h"
#include "ash/style/ash_color_provider.h" #include "ash/style/ash_color_provider.h"
#include "ash/system/media/unified_media_controls_container.h"
#include "ash/system/message_center/ash_message_center_lock_screen_controller.h" #include "ash/system/message_center/ash_message_center_lock_screen_controller.h"
#include "ash/system/message_center/unified_message_center_view.h" #include "ash/system/message_center/unified_message_center_view.h"
#include "ash/system/tray/interacted_by_tap_recorder.h" #include "ash/system/tray/interacted_by_tap_recorder.h"
...@@ -27,6 +28,7 @@ ...@@ -27,6 +28,7 @@
#include "ash/system/unified/unified_system_tray_controller.h" #include "ash/system/unified/unified_system_tray_controller.h"
#include "ash/system/unified/unified_system_tray_model.h" #include "ash/system/unified/unified_system_tray_model.h"
#include "ash/wm/tablet_mode/tablet_mode_controller.h" #include "ash/wm/tablet_mode/tablet_mode_controller.h"
#include "media/base/media_switches.h"
#include "ui/accessibility/ax_enums.mojom.h" #include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_node_data.h" #include "ui/accessibility/ax_node_data.h"
#include "ui/gfx/canvas.h" #include "ui/gfx/canvas.h"
...@@ -238,6 +240,13 @@ UnifiedSystemTrayView::UnifiedSystemTrayView( ...@@ -238,6 +240,13 @@ UnifiedSystemTrayView::UnifiedSystemTrayView(
add_layered_child(system_tray_container_, top_shortcuts_view_); add_layered_child(system_tray_container_, top_shortcuts_view_);
system_tray_container_->AddChildView(feature_pods_container_); system_tray_container_->AddChildView(feature_pods_container_);
system_tray_container_->AddChildView(page_indicator_view_); system_tray_container_->AddChildView(page_indicator_view_);
if (base::FeatureList::IsEnabled(media::kGlobalMediaControlsForChromeOS)) {
media_controls_container_ = new UnifiedMediaControlsContainer();
system_tray_container_->AddChildView(media_controls_container_);
media_controls_container_->SetExpandedAmount(expanded_amount_);
}
system_tray_container_->AddChildView(sliders_container_); system_tray_container_->AddChildView(sliders_container_);
if (features::IsManagedDeviceUIRedesignEnabled()) { if (features::IsManagedDeviceUIRedesignEnabled()) {
...@@ -267,12 +276,17 @@ void UnifiedSystemTrayView::SetMaxHeight(int max_height) { ...@@ -267,12 +276,17 @@ void UnifiedSystemTrayView::SetMaxHeight(int max_height) {
managed_device_view_ ? managed_device_view_->GetPreferredSize().height() managed_device_view_ ? managed_device_view_->GetPreferredSize().height()
: 0; : 0;
int media_controls_container_height =
media_controls_container_ ? media_controls_container_->GetExpandedHeight()
: 0;
// FeaturePodsContainer can adjust it's height by reducing the number of rows // FeaturePodsContainer can adjust it's height by reducing the number of rows
// it uses. It will calculate how many rows to use based on the max height // it uses. It will calculate how many rows to use based on the max height
// passed here. // passed here.
feature_pods_container_->SetMaxHeight( feature_pods_container_->SetMaxHeight(
max_height - top_shortcuts_view_->GetPreferredSize().height() - max_height - top_shortcuts_view_->GetPreferredSize().height() -
page_indicator_view_->GetPreferredSize().height() - page_indicator_view_->GetPreferredSize().height() -
media_controls_container_height -
sliders_container_->GetExpandedHeight() - sliders_container_->GetExpandedHeight() -
system_info_view_->GetPreferredSize().height() - system_info_view_->GetPreferredSize().height() -
managed_device_view_height); managed_device_view_height);
...@@ -288,6 +302,25 @@ void UnifiedSystemTrayView::AddSliderView(views::View* slider_view) { ...@@ -288,6 +302,25 @@ void UnifiedSystemTrayView::AddSliderView(views::View* slider_view) {
sliders_container_->AddChildView(slider_view); sliders_container_->AddChildView(slider_view);
} }
void UnifiedSystemTrayView::AddMediaControlsView(views::View* media_controls) {
DCHECK(media_controls);
DCHECK(media_controls_container_);
media_controls->SetPaintToLayer();
media_controls->layer()->SetFillsBoundsOpaquely(false);
media_controls_container_->AddChildView(media_controls);
}
void UnifiedSystemTrayView::ShowMediaControls() {
media_controls_container_->SetShouldShowMediaControls(true);
PreferredSizeChanged();
}
void UnifiedSystemTrayView::HideMediaControls() {
media_controls_container_->SetShouldShowMediaControls(false);
PreferredSizeChanged();
}
void UnifiedSystemTrayView::SetDetailedView(views::View* detailed_view) { void UnifiedSystemTrayView::SetDetailedView(views::View* detailed_view) {
auto system_tray_size = system_tray_container_->GetPreferredSize(); auto system_tray_size = system_tray_container_->GetPreferredSize();
system_tray_container_->SetVisible(false); system_tray_container_->SetVisible(false);
...@@ -329,6 +362,8 @@ void UnifiedSystemTrayView::SetExpandedAmount(double expanded_amount) { ...@@ -329,6 +362,8 @@ void UnifiedSystemTrayView::SetExpandedAmount(double expanded_amount) {
top_shortcuts_view_->SetExpandedAmount(expanded_amount); top_shortcuts_view_->SetExpandedAmount(expanded_amount);
feature_pods_container_->SetExpandedAmount(expanded_amount); feature_pods_container_->SetExpandedAmount(expanded_amount);
page_indicator_view_->SetExpandedAmount(expanded_amount); page_indicator_view_->SetExpandedAmount(expanded_amount);
if (media_controls_container_)
media_controls_container_->SetExpandedAmount(expanded_amount);
sliders_container_->SetExpandedAmount(expanded_amount); sliders_container_->SetExpandedAmount(expanded_amount);
PreferredSizeChanged(); PreferredSizeChanged();
...@@ -341,6 +376,9 @@ int UnifiedSystemTrayView::GetExpandedSystemTrayHeight() const { ...@@ -341,6 +376,9 @@ int UnifiedSystemTrayView::GetExpandedSystemTrayHeight() const {
int managed_device_view_height = int managed_device_view_height =
managed_device_view_ ? managed_device_view_->GetPreferredSize().height() managed_device_view_ ? managed_device_view_->GetPreferredSize().height()
: 0; : 0;
int media_controls_container_height =
media_controls_container_ ? media_controls_container_->GetExpandedHeight()
: 0;
return (notification_hidden_view_->GetVisible() return (notification_hidden_view_->GetVisible()
? notification_hidden_view_->GetPreferredSize().height() ? notification_hidden_view_->GetPreferredSize().height()
: 0) + : 0) +
...@@ -348,6 +386,7 @@ int UnifiedSystemTrayView::GetExpandedSystemTrayHeight() const { ...@@ -348,6 +386,7 @@ int UnifiedSystemTrayView::GetExpandedSystemTrayHeight() const {
feature_pods_container_->GetExpandedHeight() + feature_pods_container_->GetExpandedHeight() +
page_indicator_view_->GetExpandedHeight() + page_indicator_view_->GetExpandedHeight() +
sliders_container_->GetExpandedHeight() + sliders_container_->GetExpandedHeight() +
media_controls_container_height +
system_info_view_->GetPreferredSize().height() + system_info_view_->GetPreferredSize().height() +
managed_device_view_height; managed_device_view_height;
} }
......
...@@ -18,6 +18,7 @@ namespace ash { ...@@ -18,6 +18,7 @@ namespace ash {
class FeaturePodButton; class FeaturePodButton;
class FeaturePodsContainerView; class FeaturePodsContainerView;
class TopShortcutsView; class TopShortcutsView;
class UnifiedMediaControlsContainer;
class NotificationHiddenView; class NotificationHiddenView;
class PageIndicatorView; class PageIndicatorView;
class UnifiedManagedDeviceView; class UnifiedManagedDeviceView;
...@@ -86,6 +87,9 @@ class ASH_EXPORT UnifiedSystemTrayView : public views::View, ...@@ -86,6 +87,9 @@ class ASH_EXPORT UnifiedSystemTrayView : public views::View,
// Add slider view. // Add slider view.
void AddSliderView(views::View* slider_view); void AddSliderView(views::View* slider_view);
// Add media controls view to |media_controls_container_|;
void AddMediaControlsView(views::View* media_controls);
// Hide the main view and show the given |detailed_view|. // Hide the main view and show the given |detailed_view|.
void SetDetailedView(views::View* detailed_view); void SetDetailedView(views::View* detailed_view);
...@@ -132,6 +136,10 @@ class ASH_EXPORT UnifiedSystemTrayView : public views::View, ...@@ -132,6 +136,10 @@ class ASH_EXPORT UnifiedSystemTrayView : public views::View,
// Settings). // Settings).
bool IsDetailedViewShown() const; bool IsDetailedViewShown() const;
// Show and hide media controls view.
void ShowMediaControls();
void HideMediaControls();
// views::View: // views::View:
gfx::Size CalculatePreferredSize() const override; gfx::Size CalculatePreferredSize() const override;
void OnGestureEvent(ui::GestureEvent* event) override; void OnGestureEvent(ui::GestureEvent* event) override;
...@@ -190,6 +198,9 @@ class ASH_EXPORT UnifiedSystemTrayView : public views::View, ...@@ -190,6 +198,9 @@ class ASH_EXPORT UnifiedSystemTrayView : public views::View,
SystemTrayContainer* const system_tray_container_; SystemTrayContainer* const system_tray_container_;
views::View* const detailed_view_container_; views::View* const detailed_view_container_;
// Null if media::kGlobalMediaControlsForChromeOS is disabled.
UnifiedMediaControlsContainer* media_controls_container_ = nullptr;
// Null if kManagedDeviceUIRedesign is disabled. // Null if kManagedDeviceUIRedesign is disabled.
UnifiedManagedDeviceView* managed_device_view_ = nullptr; UnifiedManagedDeviceView* managed_device_view_ = nullptr;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment