Commit c8740df3 authored by Becca Hughes's avatar Becca Hughes Committed by Commit Bot

[Media Notification] Add a custom view

Add a custom view to use when showing a media
notification. At the moment this will just show
and hide the control buttons on hover.

BUG=897836

Change-Id: Ie6335b3fbff55e1f9d588cfbe3e95678fb0b8e1a
Reviewed-on: https://chromium-review.googlesource.com/c/1297246
Commit-Queue: Becca Hughes <beccahughes@chromium.org>
Reviewed-by: default avatarJames Cook <jamescook@chromium.org>
Reviewed-by: default avatarEvan Stade <estade@chromium.org>
Cr-Commit-Position: refs/heads/master@{#603684}
parent 413468f8
......@@ -487,8 +487,12 @@ component("ash") {
"magnifier/magnifier_scale_utils.h",
"magnifier/partial_magnification_controller.cc",
"magnifier/partial_magnification_controller.h",
"media/media_notification_constants.cc",
"media/media_notification_constants.h",
"media/media_notification_controller.cc",
"media/media_notification_controller.h",
"media/media_notification_view.cc",
"media/media_notification_view.h",
"media_controller.cc",
"media_controller.h",
"metrics/demo_session_metrics_recorder.cc",
......@@ -1773,6 +1777,7 @@ test("ash_unittests") {
"magnifier/magnifier_test_utils.h",
"magnifier/partial_magnification_controller_unittest.cc",
"media/media_notification_controller_unittest.cc",
"media/media_notification_view_unittest.cc",
"metrics/demo_session_metrics_recorder_unittest.cc",
"metrics/desktop_task_switch_metric_recorder_unittest.cc",
"metrics/login_metrics_recorder_unittest.cc",
......
// Copyright 2018 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/media/media_notification_constants.h"
namespace ash {
const char kMediaSessionNotificationId[] = "media-session";
const char kMediaSessionNotificationCustomViewType[] = "media-session";
const char kMediaSessionNotifierId[] = "media-session";
} // namespace ash
// Copyright 2018 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_MEDIA_MEDIA_NOTIFICATION_CONSTANTS_H_
#define ASH_MEDIA_MEDIA_NOTIFICATION_CONSTANTS_H_
#include "ash/ash_export.h"
namespace ash {
// The notification ID for the media session notification.
ASH_EXPORT extern const char kMediaSessionNotificationId[];
// The custom view type that should be set on media session notifications.
ASH_EXPORT extern const char kMediaSessionNotificationCustomViewType[];
// The notifier ID associated with the media session service.
ASH_EXPORT extern const char kMediaSessionNotifierId[];
} // namespace ash
#endif // ASH_MEDIA_MEDIA_NOTIFICATION_CONSTANTS_H_
......@@ -4,6 +4,8 @@
#include "ash/media/media_notification_controller.h"
#include "ash/media/media_notification_constants.h"
#include "ash/media/media_notification_view.h"
#include "base/strings/string16.h"
#include "services/media_session/public/mojom/constants.mojom.h"
#include "services/service_manager/public/cpp/connector.h"
......@@ -11,17 +13,19 @@
#include "ui/message_center/public/cpp/notification.h"
#include "ui/message_center/public/cpp/notification_delegate.h"
#include "ui/message_center/public/cpp/notifier_id.h"
#include "ui/message_center/views/message_view_factory.h"
#include "url/gurl.h"
namespace ash {
namespace {
// The ID associated with the media session notification.
const char kMediaSessionNotificationId[] = "media-session";
// The notifier ID associated with the media session service.
const char kMediaSessionNotifierId[] = "media-session";
std::unique_ptr<message_center::MessageView> CreateCustomMediaNotificationView(
const message_center::Notification& notification) {
DCHECK_EQ(kMediaSessionNotificationCustomViewType,
notification.custom_view_type());
return std::make_unique<MediaNotificationView>(notification);
}
bool IsMediaSessionNotificationVisible() {
return message_center::MessageCenter::Get()->FindVisibleNotificationById(
......@@ -32,6 +36,13 @@ bool IsMediaSessionNotificationVisible() {
MediaNotificationController::MediaNotificationController(
service_manager::Connector* connector) {
if (!message_center::MessageViewFactory::HasCustomNotificationViewFactory(
kMediaSessionNotificationCustomViewType)) {
message_center::MessageViewFactory::SetCustomNotificationViewFactory(
kMediaSessionNotificationCustomViewType,
base::BindRepeating(&CreateCustomMediaNotificationView));
}
// |connector| can be null in tests.
if (!connector)
return;
......@@ -55,7 +66,7 @@ void MediaNotificationController::OnFocusGained(
std::unique_ptr<message_center::Notification> notification =
message_center::Notification::CreateSystemNotification(
message_center::NotificationType::NOTIFICATION_TYPE_SIMPLE,
message_center::NotificationType::NOTIFICATION_TYPE_CUSTOM,
kMediaSessionNotificationId, base::string16(), base::string16(),
base::string16(), GURL(),
message_center::NotifierId(
......@@ -69,12 +80,12 @@ void MediaNotificationController::OnFocusGained(
gfx::VectorIcon(),
message_center::SystemNotificationWarningLevel::NORMAL);
notification->set_pinned(true);
// Set the priority to low to prevent the notification showing as a popup and
// keep it at the bottom of the list.
notification->set_priority(message_center::LOW_PRIORITY);
notification->set_custom_view_type(kMediaSessionNotificationCustomViewType);
message_center::MessageCenter::Get()->AddNotification(
std::move(notification));
}
......
......@@ -6,6 +6,7 @@
#include <memory>
#include "ash/media/media_notification_constants.h"
#include "ash/public/cpp/ash_features.h"
#include "ash/shell.h"
#include "ash/test/ash_test_base.h"
......@@ -23,7 +24,7 @@ namespace {
bool IsMediaNotificationShown() {
return message_center::MessageCenter::Get()->FindVisibleNotificationById(
"media-session");
kMediaSessionNotificationId);
}
int GetVisibleNotificationCount() {
......@@ -87,4 +88,18 @@ TEST_F(MediaNotificationControllerTest, OnFocusLost_Noop) {
EXPECT_FALSE(IsMediaNotificationShown());
}
TEST_F(MediaNotificationControllerTest, NotificationHasCustomViewType) {
EXPECT_FALSE(IsMediaNotificationShown());
Shell::Get()->media_notification_controller()->OnFocusGained(
MediaSessionInfo::New(), AudioFocusType::kGain);
message_center::Notification* notification =
message_center::MessageCenter::Get()->FindVisibleNotificationById(
kMediaSessionNotificationId);
EXPECT_TRUE(notification);
EXPECT_EQ(kMediaSessionNotificationCustomViewType,
notification->custom_view_type());
}
} // namespace ash
// Copyright 2018 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/media/media_notification_view.h"
#include "ui/message_center/message_center.h"
#include "ui/message_center/public/cpp/message_center_constants.h"
#include "ui/message_center/views/notification_control_buttons_view.h"
#include "ui/message_center/views/notification_header_view.h"
#include "ui/views/layout/box_layout.h"
namespace ash {
MediaNotificationView::MediaNotificationView(
const message_center::Notification& notification)
: message_center::MessageView(notification) {
SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::kVertical, gfx::Insets(), 0));
// |controls_button_view_| has the common notification control buttons.
control_buttons_view_ =
std::make_unique<message_center::NotificationControlButtonsView>(this);
control_buttons_view_->set_owned_by_client();
// |header_row_| contains app_icon, app_name, control buttons, etc...
header_row_ = new message_center::NotificationHeaderView(
control_buttons_view_.get(), this);
header_row_->SetExpandButtonEnabled(false);
header_row_->SetAppName(
message_center::MessageCenter::Get()->GetSystemNotificationAppName());
AddChildView(header_row_);
// TODO(beccahughes): Add remaining UI for notification.
UpdateControlButtonsVisibilityWithNotification(notification);
UpdateCornerRadius(message_center::kNotificationCornerRadius,
message_center::kNotificationCornerRadius);
}
MediaNotificationView::~MediaNotificationView() = default;
void MediaNotificationView::UpdateWithNotification(
const message_center::Notification& notification) {
MessageView::UpdateWithNotification(notification);
UpdateControlButtonsVisibilityWithNotification(notification);
Layout();
SchedulePaint();
}
message_center::NotificationControlButtonsView*
MediaNotificationView::GetControlButtonsView() const {
return control_buttons_view_.get();
}
void MediaNotificationView::UpdateControlButtonsVisibility() {
const bool target_visibility =
(IsMouseHovered() || control_buttons_view_->IsCloseButtonFocused() ||
control_buttons_view_->IsSettingsButtonFocused()) &&
(GetMode() != Mode::SETTING);
control_buttons_view_->SetVisible(target_visibility);
}
void MediaNotificationView::OnMouseEvent(ui::MouseEvent* event) {
switch (event->type()) {
case ui::ET_MOUSE_ENTERED:
case ui::ET_MOUSE_EXITED:
UpdateControlButtonsVisibility();
break;
default:
break;
}
View::OnMouseEvent(event);
}
void MediaNotificationView::ButtonPressed(views::Button* sender,
const ui::Event& event) {
NOTIMPLEMENTED();
}
void MediaNotificationView::UpdateControlButtonsVisibilityWithNotification(
const message_center::Notification& notification) {
// Media notifications do not use the settings and snooze buttons.
DCHECK(!notification.should_show_settings_button());
DCHECK(!notification.should_show_snooze_button());
control_buttons_view_->ShowCloseButton(!notification.pinned());
UpdateControlButtonsVisibility();
}
} // namespace ash
// Copyright 2018 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_MEDIA_MEDIA_NOTIFICATION_VIEW_H_
#define ASH_MEDIA_MEDIA_NOTIFICATION_VIEW_H_
#include "ash/ash_export.h"
#include "ui/message_center/views/message_view.h"
#include "ui/views/controls/button/button.h"
namespace message_center {
class NotificationHeaderView;
} // namespace message_center
namespace ash {
// MediaNotificationView will show up as a custom notification. It will show the
// currently playing media and provide playback controls. There will also be
// control buttons (e.g. close) in the top right corner that will hide and show
// if the notification is hovered.
class ASH_EXPORT MediaNotificationView : public message_center::MessageView,
public views::ButtonListener {
public:
explicit MediaNotificationView(
const message_center::Notification& notification);
~MediaNotificationView() override;
// message_center::MessageView:
void UpdateWithNotification(
const message_center::Notification& notification) override;
message_center::NotificationControlButtonsView* GetControlButtonsView()
const override;
void UpdateControlButtonsVisibility() override;
// views::View:
void OnMouseEvent(ui::MouseEvent* event) override;
// views::ButtonListener:
void ButtonPressed(views::Button* sender, const ui::Event& event) override;
private:
void UpdateControlButtonsVisibilityWithNotification(
const message_center::Notification& notification);
// View containing close and settings buttons.
std::unique_ptr<message_center::NotificationControlButtonsView>
control_buttons_view_;
// Container views directly attached to this view.
message_center::NotificationHeaderView* header_row_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(MediaNotificationView);
};
} // namespace ash
#endif // ASH_MEDIA_MEDIA_NOTIFICATION_VIEW_H_
// Copyright 2018 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/media/media_notification_view.h"
#include <memory>
#include "ash/media/media_notification_constants.h"
#include "ash/media/media_notification_controller.h"
#include "ash/public/cpp/ash_features.h"
#include "ash/public/cpp/shell_window_ids.h"
#include "ash/shell.h"
#include "ash/system/message_center/message_center_view.h"
#include "ash/system/status_area_widget.h"
#include "ash/system/status_area_widget_test_helper.h"
#include "ash/system/unified/unified_system_tray.h"
#include "ash/test/ash_test_base.h"
#include "base/macros.h"
#include "base/test/scoped_feature_list.h"
#include "services/media_session/public/mojom/audio_focus.mojom.h"
#include "ui/events/base_event_utils.h"
#include "ui/events/test/event_generator.h"
#include "ui/message_center/message_center.h"
#include "ui/message_center/views/message_view_factory.h"
#include "ui/message_center/views/notification_control_buttons_view.h"
namespace ash {
class MediaNotificationViewTest : public AshTestBase {
public:
MediaNotificationViewTest() = default;
~MediaNotificationViewTest() override = default;
// AshTestBase
void SetUp() override {
scoped_feature_list_.InitAndEnableFeature(
features::kMediaSessionNotification);
AshTestBase::SetUp();
MessageCenterView::disable_animation_for_testing = true;
// Set a custom view factory to create and capture the notification view.
message_center::MessageViewFactory::
ClearCustomNotificationViewFactoryForTest(
kMediaSessionNotificationCustomViewType);
message_center::MessageViewFactory::SetCustomNotificationViewFactory(
kMediaSessionNotificationCustomViewType,
base::BindRepeating(
&MediaNotificationViewTest::CreateAndCaptureCustomView,
base::Unretained(this)));
// Show the notification.
Shell::Get()->media_notification_controller()->OnFocusGained(
media_session::mojom::MediaSessionInfo::New(),
media_session::mojom::AudioFocusType::kGain);
message_center::Notification* notification =
message_center::MessageCenter::Get()->FindVisibleNotificationById(
kMediaSessionNotificationId);
ASSERT_TRUE(notification);
// Open the system tray. This will trigger the view to be created.
auto* unified_system_tray =
StatusAreaWidgetTestHelper::GetStatusAreaWidget()
->unified_system_tray();
unified_system_tray->ShowBubble(false /* show_by_click */);
unified_system_tray->ActivateBubble();
// Check that the view was captured.
ASSERT_TRUE(view_);
view_->set_notify_enter_exit_on_child(true);
}
void TearDown() override {
MessageCenterView::disable_animation_for_testing = false;
view_ = nullptr;
message_center::MessageViewFactory::
ClearCustomNotificationViewFactoryForTest(
kMediaSessionNotificationCustomViewType);
AshTestBase::TearDown();
}
bool IsControlButtonsViewVisible() const {
return view()->GetControlButtonsView()->layer()->opacity() > 0;
}
MediaNotificationView* view() const { return view_; }
private:
std::unique_ptr<message_center::MessageView> CreateAndCaptureCustomView(
const message_center::Notification& notification) {
auto view = std::make_unique<MediaNotificationView>(notification);
view_ = view.get();
return view;
}
base::test::ScopedFeatureList scoped_feature_list_;
std::unique_ptr<views::Widget> widget_;
MediaNotificationView* view_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(MediaNotificationViewTest);
};
TEST_F(MediaNotificationViewTest, ShowControlsOnHover) {
EXPECT_FALSE(IsControlButtonsViewVisible());
{
gfx::Point cursor_location(1, 1);
views::View::ConvertPointToScreen(view(), &cursor_location);
GetEventGenerator()->MoveMouseTo(cursor_location);
GetEventGenerator()->SendMouseEnter();
}
EXPECT_TRUE(IsControlButtonsViewVisible());
{
gfx::Point cursor_location(-1, -1);
views::View::ConvertPointToScreen(view(), &cursor_location);
GetEventGenerator()->MoveMouseTo(cursor_location.x(), cursor_location.y());
GetEventGenerator()->SendMouseExit();
}
EXPECT_FALSE(IsControlButtonsViewVisible());
}
} // namespace ash
......@@ -103,6 +103,7 @@ class ASH_EXPORT MessageCenterView
private:
friend class ArcNotificationContentViewTest;
friend class MediaNotificationViewTest;
friend class MessageCenterViewTest;
// NOTIFICATIONS: Normal notification list (MessageListView) is shown.
......
......@@ -6,6 +6,7 @@
#define UI_MESSAGE_CENTER_VIEWS_NOTIFICATION_HEADER_VIEW_H_
#include "base/macros.h"
#include "ui/message_center/message_center_export.h"
#include "ui/message_center/public/cpp/message_center_constants.h"
#include "ui/views/controls/button/button.h"
......@@ -18,7 +19,7 @@ namespace message_center {
class NotificationControlButtonsView;
class NotificationHeaderView : public views::Button {
class MESSAGE_CENTER_EXPORT NotificationHeaderView : public views::Button {
public:
NotificationHeaderView(NotificationControlButtonsView* control_buttons_view,
views::ButtonListener* listener);
......
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