Commit 875de1d4 authored by Tommy Steimel's avatar Tommy Steimel Committed by Commit Bot

GMC: Make MediaNotificationItem independent of Ash

This CL updates the relationship between MediaNotificationItem and
MediaNotificationController (now MediaNotificationControllerImpl) such
that MediaNotificationItem is only responsible for deciding when to
show or hide a media notification, and isn't responsible for how that
media notification is displayed. This is done by creating a
MediaNotificationController interface that
MediaNotificationControllerImpl implements.

This CL also updates the relationship of MediaNotificationItem and
MediaNotificationView so that MediaNotificationView calls methods on
MediaNotificationItem directly instead of calling them through the
MediaNotificationController or the message_center::MessageCenter.

This is part of a refactoring of the media notification to make it
reusable outside of ash/media.

Bug: 959478
Change-Id: I77d3f0329f0e8ee32d4cbb79829a0fdf50ac8113
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1615497Reviewed-by: default avatarScott Violet <sky@chromium.org>
Reviewed-by: default avatarBecca Hughes <beccahughes@chromium.org>
Commit-Queue: Tommy Steimel <steimel@chromium.org>
Cr-Commit-Position: refs/heads/master@{#660873}
parent 06c18e5a
...@@ -453,8 +453,9 @@ component("ash") { ...@@ -453,8 +453,9 @@ component("ash") {
"media/media_notification_background.h", "media/media_notification_background.h",
"media/media_notification_constants.cc", "media/media_notification_constants.cc",
"media/media_notification_constants.h", "media/media_notification_constants.h",
"media/media_notification_controller.cc",
"media/media_notification_controller.h", "media/media_notification_controller.h",
"media/media_notification_controller_impl.cc",
"media/media_notification_controller_impl.h",
"media/media_notification_item.cc", "media/media_notification_item.cc",
"media/media_notification_item.h", "media/media_notification_item.h",
"media/media_notification_view.cc", "media/media_notification_view.cc",
...@@ -1693,7 +1694,7 @@ test("ash_unittests") { ...@@ -1693,7 +1694,7 @@ test("ash_unittests") {
"magnifier/partial_magnification_controller_unittest.cc", "magnifier/partial_magnification_controller_unittest.cc",
"media/media_controller_unittest.cc", "media/media_controller_unittest.cc",
"media/media_notification_background_unittest.cc", "media/media_notification_background_unittest.cc",
"media/media_notification_controller_unittest.cc", "media/media_notification_controller_impl_unittest.cc",
"media/media_notification_view_unittest.cc", "media/media_notification_view_unittest.cc",
"metrics/demo_session_metrics_recorder_unittest.cc", "metrics/demo_session_metrics_recorder_unittest.cc",
"metrics/desktop_task_switch_metric_recorder_unittest.cc", "metrics/desktop_task_switch_metric_recorder_unittest.cc",
......
// Copyright 2018 The Chromium Authors. All rights reserved. // Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#ifndef ASH_MEDIA_MEDIA_NOTIFICATION_CONTROLLER_H_ #ifndef ASH_MEDIA_MEDIA_NOTIFICATION_CONTROLLER_H_
#define ASH_MEDIA_MEDIA_NOTIFICATION_CONTROLLER_H_ #define ASH_MEDIA_MEDIA_NOTIFICATION_CONTROLLER_H_
#include <map>
#include <memory>
#include <string> #include <string>
#include "ash/ash_export.h" #include "ash/ash_export.h"
#include "ash/media/media_notification_item.h"
#include "base/macros.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "services/media_session/public/mojom/audio_focus.mojom.h"
#include "services/media_session/public/mojom/media_controller.mojom.h"
namespace service_manager {
class Connector;
} // namespace service_manager
namespace ash { namespace ash {
namespace { // MediaNotificationController does the actual hiding and showing of the media
class MediaNotificationBlocker; // notification.
} // namespace class ASH_EXPORT MediaNotificationController {
class MediaNotificationItem;
class MediaNotificationView;
// MediaNotificationController will show/hide media notifications when media
// sessions are active. These notifications will show metadata and playback
// controls.
class ASH_EXPORT MediaNotificationController
: public media_session::mojom::AudioFocusObserver {
public: public:
// The name of the histogram used to record the number of concurrent media // Shows/hides a notification with the given request id. Called by
// notifications. // MediaNotificationItem when the notification should be shown/hidden.
static const char kCountHistogramName[]; virtual void ShowNotification(const std::string& id) = 0;
virtual void HideNotification(const std::string& id) = 0;
explicit MediaNotificationController(service_manager::Connector* connector);
~MediaNotificationController() override;
// media_session::mojom::AudioFocusObserver:
void OnFocusGained(
media_session::mojom::AudioFocusRequestStatePtr session) override;
void OnFocusLost(
media_session::mojom::AudioFocusRequestStatePtr session) override;
void SetView(const std::string& id, MediaNotificationView* view);
MediaNotificationItem* GetItem(const std::string& id) {
auto it = notifications_.find(id);
DCHECK(it != notifications_.end());
return &it->second;
}
// Called by |MediaNotificationItem| when it displays a new media
// notification. It will record the concurrent number of media notifications
// displayed.
void RecordConcurrentNotificationCount();
private:
media_session::mojom::MediaControllerManagerPtr controller_manager_ptr_;
mojo::Binding<media_session::mojom::AudioFocusObserver>
audio_focus_observer_binding_{this};
// Stores a |MediaNotificationItem| for each media session keyed by its
// |request_id| in string format.
std::map<const std::string, MediaNotificationItem> notifications_;
std::unique_ptr<MediaNotificationBlocker> blocker_;
DISALLOW_COPY_AND_ASSIGN(MediaNotificationController);
}; };
} // namespace ash } // namespace ash
......
...@@ -2,10 +2,12 @@ ...@@ -2,10 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include "ash/media/media_notification_controller.h" #include "ash/media/media_notification_controller_impl.h"
#include "ash/media/media_notification_constants.h" #include "ash/media/media_notification_constants.h"
#include "ash/media/media_notification_item.h"
#include "ash/media/media_notification_view.h" #include "ash/media/media_notification_view.h"
#include "ash/public/cpp/notification_utils.h"
#include "ash/session/session_controller_impl.h" #include "ash/session/session_controller_impl.h"
#include "ash/session/session_observer.h" #include "ash/session/session_observer.h"
#include "ash/shell.h" #include "ash/shell.h"
...@@ -16,6 +18,8 @@ ...@@ -16,6 +18,8 @@
#include "services/service_manager/public/cpp/connector.h" #include "services/service_manager/public/cpp/connector.h"
#include "ui/message_center/message_center.h" #include "ui/message_center/message_center.h"
#include "ui/message_center/notification_blocker.h" #include "ui/message_center/notification_blocker.h"
#include "ui/message_center/public/cpp/notification.h"
#include "ui/message_center/public/cpp/notifier_id.h"
#include "ui/message_center/views/message_view_factory.h" #include "ui/message_center/views/message_view_factory.h"
namespace ash { namespace ash {
...@@ -26,7 +30,10 @@ std::unique_ptr<message_center::MessageView> CreateCustomMediaNotificationView( ...@@ -26,7 +30,10 @@ std::unique_ptr<message_center::MessageView> CreateCustomMediaNotificationView(
const message_center::Notification& notification) { const message_center::Notification& notification) {
DCHECK_EQ(kMediaSessionNotificationCustomViewType, DCHECK_EQ(kMediaSessionNotificationCustomViewType,
notification.custom_view_type()); notification.custom_view_type());
return std::make_unique<MediaNotificationView>(notification); auto* controller = Shell::Get()->media_notification_controller();
if (controller)
return controller->CreateMediaNotification(notification);
return nullptr;
} }
// The maximum number of media notifications to count when recording the // The maximum number of media notifications to count when recording the
...@@ -95,10 +102,10 @@ class MediaNotificationBlocker : public message_center::NotificationBlocker, ...@@ -95,10 +102,10 @@ class MediaNotificationBlocker : public message_center::NotificationBlocker,
} // namespace } // namespace
// static // static
const char MediaNotificationController::kCountHistogramName[] = const char MediaNotificationControllerImpl::kCountHistogramName[] =
"Media.Notification.Count"; "Media.Notification.Count";
MediaNotificationController::MediaNotificationController( MediaNotificationControllerImpl::MediaNotificationControllerImpl(
service_manager::Connector* connector) service_manager::Connector* connector)
: blocker_(std::make_unique<MediaNotificationBlocker>( : blocker_(std::make_unique<MediaNotificationBlocker>(
message_center::MessageCenter::Get(), message_center::MessageCenter::Get(),
...@@ -125,9 +132,9 @@ MediaNotificationController::MediaNotificationController( ...@@ -125,9 +132,9 @@ MediaNotificationController::MediaNotificationController(
audio_focus_ptr->AddObserver(std::move(audio_focus_observer)); audio_focus_ptr->AddObserver(std::move(audio_focus_observer));
} }
MediaNotificationController::~MediaNotificationController() = default; MediaNotificationControllerImpl::~MediaNotificationControllerImpl() = default;
void MediaNotificationController::OnFocusGained( void MediaNotificationControllerImpl::OnFocusGained(
media_session::mojom::AudioFocusRequestStatePtr session) { media_session::mojom::AudioFocusRequestStatePtr session) {
const std::string id = session->request_id->ToString(); const std::string id = session->request_id->ToString();
...@@ -145,25 +152,60 @@ void MediaNotificationController::OnFocusGained( ...@@ -145,25 +152,60 @@ void MediaNotificationController::OnFocusGained(
notifications_.emplace( notifications_.emplace(
std::piecewise_construct, std::forward_as_tuple(id), std::piecewise_construct, std::forward_as_tuple(id),
std::forward_as_tuple(id, session->source_name.value_or(std::string()), std::forward_as_tuple(
std::move(controller), this, id, session->source_name.value_or(std::string()),
std::move(session->session_info))); std::move(controller), std::move(session->session_info)));
} }
void MediaNotificationController::OnFocusLost( void MediaNotificationControllerImpl::OnFocusLost(
media_session::mojom::AudioFocusRequestStatePtr session) { media_session::mojom::AudioFocusRequestStatePtr session) {
notifications_.erase(session->request_id->ToString()); notifications_.erase(session->request_id->ToString());
} }
void MediaNotificationController::SetView(const std::string& id, void MediaNotificationControllerImpl::ShowNotification(const std::string& id) {
MediaNotificationView* view) { // If a notification already exists, do nothing.
auto it = notifications_.find(id); if (message_center::MessageCenter::Get()->FindVisibleNotificationById(id))
if (it == notifications_.end())
return; return;
it->second.SetView(view);
std::unique_ptr<message_center::Notification> notification =
ash::CreateSystemNotification(
message_center::NotificationType::NOTIFICATION_TYPE_CUSTOM, id,
base::string16(), base::string16(), base::string16(), GURL(),
message_center::NotifierId(
message_center::NotifierType::SYSTEM_COMPONENT,
kMediaSessionNotifierId),
message_center::RichNotificationData(), nullptr, gfx::VectorIcon(),
message_center::SystemNotificationWarningLevel::NORMAL);
// 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));
RecordConcurrentNotificationCount();
}
void MediaNotificationControllerImpl::HideNotification(const std::string& id) {
message_center::MessageCenter::Get()->RemoveNotification(id, false);
}
std::unique_ptr<MediaNotificationView>
MediaNotificationControllerImpl::CreateMediaNotification(
const message_center::Notification& notification) {
base::WeakPtr<MediaNotificationItem> item;
auto it = notifications_.find(notification.id());
if (it != notifications_.end())
item = it->second.GetWeakPtr();
return std::make_unique<MediaNotificationView>(notification, std::move(item));
} }
void MediaNotificationController::RecordConcurrentNotificationCount() { void MediaNotificationControllerImpl::RecordConcurrentNotificationCount() {
UMA_HISTOGRAM_EXACT_LINEAR( UMA_HISTOGRAM_EXACT_LINEAR(
kCountHistogramName, kCountHistogramName,
message_center::MessageCenter::Get() message_center::MessageCenter::Get()
......
// 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_CONTROLLER_IMPL_H_
#define ASH_MEDIA_MEDIA_NOTIFICATION_CONTROLLER_IMPL_H_
#include <map>
#include <memory>
#include <string>
#include "ash/ash_export.h"
#include "ash/media/media_notification_controller.h"
#include "ash/media/media_notification_item.h"
#include "base/macros.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "services/media_session/public/mojom/audio_focus.mojom.h"
#include "services/media_session/public/mojom/media_controller.mojom.h"
namespace service_manager {
class Connector;
} // namespace service_manager
namespace message_center {
class Notification;
} // namespace message_center
namespace ash {
namespace {
class MediaNotificationBlocker;
} // namespace
class MediaNotificationView;
// MediaNotificationControllerImpl will show/hide media notifications when media
// sessions are active. These notifications will show metadata and playback
// controls.
class ASH_EXPORT MediaNotificationControllerImpl
: public media_session::mojom::AudioFocusObserver,
public MediaNotificationController {
public:
// The name of the histogram used to record the number of concurrent media
// notifications.
static const char kCountHistogramName[];
explicit MediaNotificationControllerImpl(
service_manager::Connector* connector);
~MediaNotificationControllerImpl() override;
// media_session::mojom::AudioFocusObserver:
void OnFocusGained(
media_session::mojom::AudioFocusRequestStatePtr session) override;
void OnFocusLost(
media_session::mojom::AudioFocusRequestStatePtr session) override;
// MediaNotificationController:
void ShowNotification(const std::string& id) override;
void HideNotification(const std::string& id) override;
std::unique_ptr<MediaNotificationView> CreateMediaNotification(
const message_center::Notification& notification);
ash::MediaNotificationItem* GetItem(const std::string& id) {
auto it = notifications_.find(id);
DCHECK(it != notifications_.end());
return &it->second;
}
private:
// Called when we display a new media notification. It will record the
// concurrent number of media notifications displayed.
void RecordConcurrentNotificationCount();
media_session::mojom::MediaControllerManagerPtr controller_manager_ptr_;
mojo::Binding<media_session::mojom::AudioFocusObserver>
audio_focus_observer_binding_{this};
// Stores a |MediaNotificationItem| for each media session keyed by its
// |request_id| in string format.
std::map<const std::string, MediaNotificationItem> notifications_;
std::unique_ptr<MediaNotificationBlocker> blocker_;
DISALLOW_COPY_AND_ASSIGN(MediaNotificationControllerImpl);
};
} // namespace ash
#endif // ASH_MEDIA_MEDIA_NOTIFICATION_CONTROLLER_IMPL_H_
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include "ash/media/media_notification_controller.h" #include "ash/media/media_notification_controller_impl.h"
#include <memory> #include <memory>
...@@ -44,10 +44,10 @@ media_session::mojom::AudioFocusRequestStatePtr GetRequestStateWithId( ...@@ -44,10 +44,10 @@ media_session::mojom::AudioFocusRequestStatePtr GetRequestStateWithId(
} // namespace } // namespace
class MediaNotificationControllerTest : public AshTestBase { class MediaNotificationControllerImplTest : public AshTestBase {
public: public:
MediaNotificationControllerTest() = default; MediaNotificationControllerImplTest() = default;
~MediaNotificationControllerTest() override = default; ~MediaNotificationControllerImplTest() override = default;
// AshTestBase // AshTestBase
void SetUp() override { void SetUp() override {
...@@ -77,7 +77,7 @@ class MediaNotificationControllerTest : public AshTestBase { ...@@ -77,7 +77,7 @@ class MediaNotificationControllerTest : public AshTestBase {
void ExpectHistogramCountRecorded(int count, int size) { void ExpectHistogramCountRecorded(int count, int size) {
histogram_tester_.ExpectBucketCount( histogram_tester_.ExpectBucketCount(
MediaNotificationController::kCountHistogramName, count, size); MediaNotificationControllerImpl::kCountHistogramName, count, size);
} }
void ExpectHistogramSourceRecorded(MediaNotificationItem::Source source) { void ExpectHistogramSourceRecorded(MediaNotificationItem::Source source) {
...@@ -98,12 +98,12 @@ class MediaNotificationControllerTest : public AshTestBase { ...@@ -98,12 +98,12 @@ class MediaNotificationControllerTest : public AshTestBase {
base::HistogramTester histogram_tester_; base::HistogramTester histogram_tester_;
DISALLOW_COPY_AND_ASSIGN(MediaNotificationControllerTest); DISALLOW_COPY_AND_ASSIGN(MediaNotificationControllerImplTest);
}; };
// Test toggling the notification multiple times with the same ID. Since the // Test toggling the notification multiple times with the same ID. Since the
// notification is keyed by ID we should only ever show one. // notification is keyed by ID we should only ever show one.
TEST_F(MediaNotificationControllerTest, OnFocusGainedLost_SameId) { TEST_F(MediaNotificationControllerImplTest, OnFocusGainedLost_SameId) {
base::UnguessableToken id = base::UnguessableToken::Create(); base::UnguessableToken id = base::UnguessableToken::Create();
ExpectNotificationCount(0); ExpectNotificationCount(0);
...@@ -133,7 +133,7 @@ TEST_F(MediaNotificationControllerTest, OnFocusGainedLost_SameId) { ...@@ -133,7 +133,7 @@ TEST_F(MediaNotificationControllerTest, OnFocusGainedLost_SameId) {
// Test toggling the notification multiple times with different IDs. This should // Test toggling the notification multiple times with different IDs. This should
// show one notification per ID. // show one notification per ID.
TEST_F(MediaNotificationControllerTest, OnFocusGainedLost_MultipleIds) { TEST_F(MediaNotificationControllerImplTest, OnFocusGainedLost_MultipleIds) {
base::UnguessableToken id1 = base::UnguessableToken::Create(); base::UnguessableToken id1 = base::UnguessableToken::Create();
base::UnguessableToken id2 = base::UnguessableToken::Create(); base::UnguessableToken id2 = base::UnguessableToken::Create();
...@@ -169,8 +169,9 @@ TEST_F(MediaNotificationControllerTest, OnFocusGainedLost_MultipleIds) { ...@@ -169,8 +169,9 @@ TEST_F(MediaNotificationControllerTest, OnFocusGainedLost_MultipleIds) {
} }
// Test that a notification is hidden when it becomes uncontrollable. We still // Test that a notification is hidden when it becomes uncontrollable. We still
// keep the MediaNotificationItem around in case it becomes controllable again. // keep the MediaNotificationItem around in case it becomes
TEST_F(MediaNotificationControllerTest, // controllable again.
TEST_F(MediaNotificationControllerImplTest,
OnFocusGained_ControllableBecomesUncontrollable) { OnFocusGained_ControllableBecomesUncontrollable) {
base::UnguessableToken id = base::UnguessableToken::Create(); base::UnguessableToken id = base::UnguessableToken::Create();
...@@ -196,7 +197,7 @@ TEST_F(MediaNotificationControllerTest, ...@@ -196,7 +197,7 @@ TEST_F(MediaNotificationControllerTest,
} }
// Test that a notification is shown when it becomes controllable. // Test that a notification is shown when it becomes controllable.
TEST_F(MediaNotificationControllerTest, TEST_F(MediaNotificationControllerImplTest,
OnFocusGained_NotControllableBecomesControllable) { OnFocusGained_NotControllableBecomesControllable) {
base::UnguessableToken id = base::UnguessableToken::Create(); base::UnguessableToken id = base::UnguessableToken::Create();
...@@ -225,7 +226,7 @@ TEST_F(MediaNotificationControllerTest, ...@@ -225,7 +226,7 @@ TEST_F(MediaNotificationControllerTest,
} }
// Test hiding a notification with an invalid ID. // Test hiding a notification with an invalid ID.
TEST_F(MediaNotificationControllerTest, OnFocusLost_Noop) { TEST_F(MediaNotificationControllerImplTest, OnFocusLost_Noop) {
ExpectNotificationCount(0); ExpectNotificationCount(0);
Shell::Get()->media_notification_controller()->OnFocusLost( Shell::Get()->media_notification_controller()->OnFocusLost(
...@@ -235,7 +236,7 @@ TEST_F(MediaNotificationControllerTest, OnFocusLost_Noop) { ...@@ -235,7 +236,7 @@ TEST_F(MediaNotificationControllerTest, OnFocusLost_Noop) {
} }
// Test that media notifications have the correct custom view type. // Test that media notifications have the correct custom view type.
TEST_F(MediaNotificationControllerTest, NotificationHasCustomViewType) { TEST_F(MediaNotificationControllerImplTest, NotificationHasCustomViewType) {
ExpectNotificationCount(0); ExpectNotificationCount(0);
base::UnguessableToken id = base::UnguessableToken::Create(); base::UnguessableToken id = base::UnguessableToken::Create();
...@@ -262,7 +263,7 @@ TEST_F(MediaNotificationControllerTest, NotificationHasCustomViewType) { ...@@ -262,7 +263,7 @@ TEST_F(MediaNotificationControllerTest, NotificationHasCustomViewType) {
// Test that if we recieve a null media session info that we hide the // Test that if we recieve a null media session info that we hide the
// notification. // notification.
TEST_F(MediaNotificationControllerTest, HandleNullMediaSessionInfo) { TEST_F(MediaNotificationControllerImplTest, HandleNullMediaSessionInfo) {
ExpectNotificationCount(0); ExpectNotificationCount(0);
base::UnguessableToken id = base::UnguessableToken::Create(); base::UnguessableToken id = base::UnguessableToken::Create();
...@@ -286,7 +287,7 @@ TEST_F(MediaNotificationControllerTest, HandleNullMediaSessionInfo) { ...@@ -286,7 +287,7 @@ TEST_F(MediaNotificationControllerTest, HandleNullMediaSessionInfo) {
ExpectNotificationCount(0); ExpectNotificationCount(0);
} }
TEST_F(MediaNotificationControllerTest, MediaMetadata_NoArtist) { TEST_F(MediaNotificationControllerImplTest, MediaMetadata_NoArtist) {
base::UnguessableToken id = base::UnguessableToken::Create(); base::UnguessableToken id = base::UnguessableToken::Create();
ExpectNotificationCount(0); ExpectNotificationCount(0);
...@@ -305,7 +306,7 @@ TEST_F(MediaNotificationControllerTest, MediaMetadata_NoArtist) { ...@@ -305,7 +306,7 @@ TEST_F(MediaNotificationControllerTest, MediaMetadata_NoArtist) {
ExpectNotificationCount(0); ExpectNotificationCount(0);
} }
TEST_F(MediaNotificationControllerTest, MediaMetadata_NoTitle) { TEST_F(MediaNotificationControllerImplTest, MediaMetadata_NoTitle) {
base::UnguessableToken id = base::UnguessableToken::Create(); base::UnguessableToken id = base::UnguessableToken::Create();
ExpectNotificationCount(0); ExpectNotificationCount(0);
...@@ -324,7 +325,7 @@ TEST_F(MediaNotificationControllerTest, MediaMetadata_NoTitle) { ...@@ -324,7 +325,7 @@ TEST_F(MediaNotificationControllerTest, MediaMetadata_NoTitle) {
ExpectNotificationCount(0); ExpectNotificationCount(0);
} }
TEST_F(MediaNotificationControllerTest, MediaMetadataUpdated_MissingInfo) { TEST_F(MediaNotificationControllerImplTest, MediaMetadataUpdated_MissingInfo) {
base::UnguessableToken id = base::UnguessableToken::Create(); base::UnguessableToken id = base::UnguessableToken::Create();
ExpectNotificationCount(0); ExpectNotificationCount(0);
...@@ -348,7 +349,7 @@ TEST_F(MediaNotificationControllerTest, MediaMetadataUpdated_MissingInfo) { ...@@ -348,7 +349,7 @@ TEST_F(MediaNotificationControllerTest, MediaMetadataUpdated_MissingInfo) {
ExpectNotificationCount(0); ExpectNotificationCount(0);
} }
TEST_F(MediaNotificationControllerTest, RecordHistogramSource_Unknown) { TEST_F(MediaNotificationControllerImplTest, RecordHistogramSource_Unknown) {
base::UnguessableToken id = base::UnguessableToken::Create(); base::UnguessableToken id = base::UnguessableToken::Create();
ExpectNotificationCount(0); ExpectNotificationCount(0);
...@@ -365,7 +366,7 @@ TEST_F(MediaNotificationControllerTest, RecordHistogramSource_Unknown) { ...@@ -365,7 +366,7 @@ TEST_F(MediaNotificationControllerTest, RecordHistogramSource_Unknown) {
ExpectHistogramSourceRecorded(MediaNotificationItem::Source::kUnknown); ExpectHistogramSourceRecorded(MediaNotificationItem::Source::kUnknown);
} }
TEST_F(MediaNotificationControllerTest, RecordHistogramSource_Web) { TEST_F(MediaNotificationControllerImplTest, RecordHistogramSource_Web) {
base::UnguessableToken id = base::UnguessableToken::Create(); base::UnguessableToken id = base::UnguessableToken::Create();
ExpectNotificationCount(0); ExpectNotificationCount(0);
...@@ -386,7 +387,7 @@ TEST_F(MediaNotificationControllerTest, RecordHistogramSource_Web) { ...@@ -386,7 +387,7 @@ TEST_F(MediaNotificationControllerTest, RecordHistogramSource_Web) {
ExpectHistogramSourceRecorded(MediaNotificationItem::Source::kWeb); ExpectHistogramSourceRecorded(MediaNotificationItem::Source::kWeb);
} }
TEST_F(MediaNotificationControllerTest, RecordHistogramSource_Assistant) { TEST_F(MediaNotificationControllerImplTest, RecordHistogramSource_Assistant) {
base::UnguessableToken id = base::UnguessableToken::Create(); base::UnguessableToken id = base::UnguessableToken::Create();
ExpectNotificationCount(0); ExpectNotificationCount(0);
...@@ -407,7 +408,7 @@ TEST_F(MediaNotificationControllerTest, RecordHistogramSource_Assistant) { ...@@ -407,7 +408,7 @@ TEST_F(MediaNotificationControllerTest, RecordHistogramSource_Assistant) {
ExpectHistogramSourceRecorded(MediaNotificationItem::Source::kAssistant); ExpectHistogramSourceRecorded(MediaNotificationItem::Source::kAssistant);
} }
TEST_F(MediaNotificationControllerTest, RecordHistogramSource_Arc) { TEST_F(MediaNotificationControllerImplTest, RecordHistogramSource_Arc) {
base::UnguessableToken id = base::UnguessableToken::Create(); base::UnguessableToken id = base::UnguessableToken::Create();
ExpectNotificationCount(0); ExpectNotificationCount(0);
...@@ -430,7 +431,7 @@ TEST_F(MediaNotificationControllerTest, RecordHistogramSource_Arc) { ...@@ -430,7 +431,7 @@ TEST_F(MediaNotificationControllerTest, RecordHistogramSource_Arc) {
// Test that locking the screen will hide the media notifications. Unlocking the // Test that locking the screen will hide the media notifications. Unlocking the
// screen should re-show the notifications. // screen should re-show the notifications.
TEST_F(MediaNotificationControllerTest, HideWhenScreenLocked) { TEST_F(MediaNotificationControllerImplTest, HideWhenScreenLocked) {
message_center::MessageCenter* message_center = message_center::MessageCenter* message_center =
message_center::MessageCenter::Get(); message_center::MessageCenter::Get();
......
...@@ -7,22 +7,14 @@ ...@@ -7,22 +7,14 @@
#include "ash/media/media_notification_constants.h" #include "ash/media/media_notification_constants.h"
#include "ash/media/media_notification_controller.h" #include "ash/media/media_notification_controller.h"
#include "ash/media/media_notification_view.h" #include "ash/media/media_notification_view.h"
#include "ash/public/cpp/notification_utils.h"
#include "ash/shell.h"
#include "base/bind.h" #include "base/bind.h"
#include "base/metrics/histogram_macros.h" #include "base/metrics/histogram_macros.h"
#include "base/strings/string16.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "services/media_session/public/mojom/constants.mojom.h" #include "services/media_session/public/mojom/constants.mojom.h"
#include "services/media_session/public/mojom/media_controller.mojom.h" #include "services/media_session/public/mojom/media_controller.mojom.h"
#include "services/media_session/public/mojom/media_session.mojom.h" #include "services/media_session/public/mojom/media_session.mojom.h"
#include "ui/gfx/image/image.h" #include "ui/gfx/image/image.h"
#include "ui/message_center/message_center.h"
#include "ui/message_center/public/cpp/message_center_constants.h" #include "ui/message_center/public/cpp/message_center_constants.h"
#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 "url/gurl.h"
namespace ash { namespace ash {
...@@ -57,14 +49,18 @@ const char MediaNotificationItem::kUserActionHistogramName[] = ...@@ -57,14 +49,18 @@ const char MediaNotificationItem::kUserActionHistogramName[] =
"Media.Notification.UserAction"; "Media.Notification.UserAction";
MediaNotificationItem::MediaNotificationItem( MediaNotificationItem::MediaNotificationItem(
const std::string& id, MediaNotificationController* notification_controller,
const std::string& request_id,
const std::string& source_name, const std::string& source_name,
media_session::mojom::MediaControllerPtr controller, media_session::mojom::MediaControllerPtr controller,
media_session::mojom::MediaSessionInfoPtr session_info) media_session::mojom::MediaSessionInfoPtr session_info)
: id_(id), : controller_(notification_controller),
request_id_(request_id),
source_(GetSource(source_name)), source_(GetSource(source_name)),
media_controller_ptr_(std::move(controller)), media_controller_ptr_(std::move(controller)),
session_info_(std::move(session_info)) { session_info_(std::move(session_info)) {
DCHECK(controller_);
if (media_controller_ptr_.is_bound()) { if (media_controller_ptr_.is_bound()) {
// Bind an observer to the associated media controller. // Bind an observer to the associated media controller.
media_session::mojom::MediaControllerObserverPtr media_controller_observer; media_session::mojom::MediaControllerObserverPtr media_controller_observer;
...@@ -93,7 +89,7 @@ MediaNotificationItem::MediaNotificationItem( ...@@ -93,7 +89,7 @@ MediaNotificationItem::MediaNotificationItem(
} }
MediaNotificationItem::~MediaNotificationItem() { MediaNotificationItem::~MediaNotificationItem() {
HideNotification(); controller_->HideNotification(request_id_);
} }
void MediaNotificationItem::MediaSessionInfoChanged( void MediaNotificationItem::MediaSessionInfoChanged(
...@@ -110,10 +106,19 @@ void MediaNotificationItem::MediaSessionMetadataChanged( ...@@ -110,10 +106,19 @@ void MediaNotificationItem::MediaSessionMetadataChanged(
const base::Optional<media_session::MediaMetadata>& metadata) { const base::Optional<media_session::MediaMetadata>& metadata) {
session_metadata_ = metadata.value_or(media_session::MediaMetadata()); session_metadata_ = metadata.value_or(media_session::MediaMetadata());
view_needs_metadata_update_ = true;
MaybeHideOrShowNotification(); MaybeHideOrShowNotification();
if (view_) // |MaybeHideOrShowNotification()| can synchronously create a
// MediaNotificationView that calls |SetView()|. If that happens, then we
// don't want to call |view_->UpdateWithMediaMetadata()| below since |view_|
// will have already received the metadata when calling |SetView()|.
// |view_needs_metadata_update_| is set to false in |SetView()|.
if (view_ && view_needs_metadata_update_)
view_->UpdateWithMediaMetadata(session_metadata_); view_->UpdateWithMediaMetadata(session_metadata_);
view_needs_metadata_update_ = false;
} }
void MediaNotificationItem::MediaSessionActionsChanged( void MediaNotificationItem::MediaSessionActionsChanged(
...@@ -150,6 +155,7 @@ void MediaNotificationItem::SetView(MediaNotificationView* view) { ...@@ -150,6 +155,7 @@ void MediaNotificationItem::SetView(MediaNotificationView* view) {
view_ = view; view_ = view;
if (view) { if (view) {
view_needs_metadata_update_ = false;
view_->UpdateWithMediaSessionInfo(session_info_); view_->UpdateWithMediaSessionInfo(session_info_);
view_->UpdateWithMediaMetadata(session_metadata_); view_->UpdateWithMediaMetadata(session_metadata_);
view_->UpdateWithMediaActions(session_actions_); view_->UpdateWithMediaActions(session_actions_);
...@@ -167,61 +173,28 @@ void MediaNotificationItem::MaybeHideOrShowNotification() { ...@@ -167,61 +173,28 @@ void MediaNotificationItem::MaybeHideOrShowNotification() {
// If the |is_controllable| bit is set in MediaSessionInfo then we should show // If the |is_controllable| bit is set in MediaSessionInfo then we should show
// a media notification. // a media notification.
if (!session_info_ || !session_info_->is_controllable) { if (!session_info_ || !session_info_->is_controllable) {
HideNotification(); controller_->HideNotification(request_id_);
return; return;
} }
// If we do not have a title and an artist then we should hide the // If we do not have a title and an artist then we should hide the
// notification. // notification.
if (session_metadata_.title.empty() || session_metadata_.artist.empty()) { if (session_metadata_.title.empty() || session_metadata_.artist.empty()) {
HideNotification(); controller_->HideNotification(request_id_);
return; return;
} }
if (message_center::MessageCenter::Get()->FindVisibleNotificationById(id_)) // If we have an existing view, then we don't need to create a new one.
if (view_)
return; return;
std::unique_ptr<message_center::Notification> notification = controller_->ShowNotification(request_id_);
ash::CreateSystemNotification(
message_center::NotificationType::NOTIFICATION_TYPE_CUSTOM, id_,
base::string16(), base::string16(), base::string16(), GURL(),
message_center::NotifierId(
message_center::NotifierType::SYSTEM_COMPONENT,
kMediaSessionNotifierId),
message_center::RichNotificationData(),
base::MakeRefCounted<message_center::HandleNotificationClickDelegate>(
base::BindRepeating(&MediaNotificationItem::OnNotificationClicked,
weak_ptr_factory_.GetWeakPtr())),
gfx::VectorIcon(),
message_center::SystemNotificationWarningLevel::NORMAL);
// 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));
Shell::Get()
->media_notification_controller()
->RecordConcurrentNotificationCount();
UMA_HISTOGRAM_ENUMERATION(kSourceHistogramName, source_); UMA_HISTOGRAM_ENUMERATION(kSourceHistogramName, source_);
} }
void MediaNotificationItem::HideNotification() { void MediaNotificationItem::OnMediaSessionActionButtonPressed(
message_center::MessageCenter::Get()->RemoveNotification(id_, false); MediaSessionAction action) {
}
void MediaNotificationItem::OnNotificationClicked(
base::Optional<int> button_id) {
if (!button_id)
return;
const MediaSessionAction action = static_cast<MediaSessionAction>(*button_id);
UMA_HISTOGRAM_ENUMERATION(kUserActionHistogramName, action); UMA_HISTOGRAM_ENUMERATION(kUserActionHistogramName, action);
switch (action) { switch (action) {
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
namespace ash { namespace ash {
class MediaNotificationController;
class MediaNotificationView; class MediaNotificationView;
// MediaNotificationItem manages hiding/showing a media notification and // MediaNotificationItem manages hiding/showing a media notification and
...@@ -43,7 +44,8 @@ class ASH_EXPORT MediaNotificationItem ...@@ -43,7 +44,8 @@ class ASH_EXPORT MediaNotificationItem
kMaxValue = kArc, kMaxValue = kArc,
}; };
MediaNotificationItem(const std::string& id, MediaNotificationItem(MediaNotificationController* notification_controller,
const std::string& request_id,
const std::string& source_name, const std::string& source_name,
media_session::mojom::MediaControllerPtr controller, media_session::mojom::MediaControllerPtr controller,
media_session::mojom::MediaSessionInfoPtr session_info); media_session::mojom::MediaSessionInfoPtr session_info);
...@@ -65,8 +67,16 @@ class ASH_EXPORT MediaNotificationItem ...@@ -65,8 +67,16 @@ class ASH_EXPORT MediaNotificationItem
media_session::mojom::MediaSessionImageType type, media_session::mojom::MediaSessionImageType type,
const SkBitmap& bitmap) override; const SkBitmap& bitmap) override;
// Called by MediaNotificationView when created or destroyed.
void SetView(MediaNotificationView* view); void SetView(MediaNotificationView* view);
void OnMediaSessionActionButtonPressed(
media_session::mojom::MediaSessionAction action);
base::WeakPtr<MediaNotificationItem> GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
void FlushForTesting(); void FlushForTesting();
void SetMediaControllerForTesting( void SetMediaControllerForTesting(
...@@ -79,15 +89,14 @@ class ASH_EXPORT MediaNotificationItem ...@@ -79,15 +89,14 @@ class ASH_EXPORT MediaNotificationItem
void HideNotification(); void HideNotification();
MediaNotificationController* controller_;
// Weak reference to the view of the currently shown media notification. // Weak reference to the view of the currently shown media notification.
MediaNotificationView* view_ = nullptr; MediaNotificationView* view_ = nullptr;
void OnNotificationClicked(base::Optional<int> button_id); // The |request_id_| is the request id of the media session and is guaranteed
// to be globally unique.
// The id is the |request_id| of the media session and is guaranteed to be const std::string request_id_;
// globally unique. It is also used as the id of the notification for this
// media session.
const std::string id_;
// The source of the media session (e.g. arc, web). // The source of the media session (e.g. arc, web).
const Source source_; const Source source_;
...@@ -104,6 +113,10 @@ class ASH_EXPORT MediaNotificationItem ...@@ -104,6 +113,10 @@ class ASH_EXPORT MediaNotificationItem
gfx::ImageSkia session_icon_; gfx::ImageSkia session_icon_;
// True if the metadata needs to be updated on |view_|. Used to prevent
// updating |view_|'s metadata twice on a single change.
bool view_needs_metadata_update_ = false;
mojo::Binding<media_session::mojom::MediaControllerObserver> mojo::Binding<media_session::mojom::MediaControllerObserver>
observer_binding_{this}; observer_binding_{this};
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
#include "ash/media/media_notification_background.h" #include "ash/media/media_notification_background.h"
#include "ash/media/media_notification_constants.h" #include "ash/media/media_notification_constants.h"
#include "ash/media/media_notification_controller.h" #include "ash/media/media_notification_item.h"
#include "ash/shell.h" #include "ash/shell.h"
#include "ash/strings/grit/ash_strings.h" #include "ash/strings/grit/ash_strings.h"
#include "base/metrics/histogram_macros.h" #include "base/metrics/histogram_macros.h"
...@@ -108,8 +108,9 @@ const char MediaNotificationView::kMetadataHistogramName[] = ...@@ -108,8 +108,9 @@ const char MediaNotificationView::kMetadataHistogramName[] =
"Media.Notification.MetadataPresent"; "Media.Notification.MetadataPresent";
MediaNotificationView::MediaNotificationView( MediaNotificationView::MediaNotificationView(
const message_center::Notification& notification) const message_center::Notification& notification,
: message_center::MessageView(notification) { base::WeakPtr<MediaNotificationItem> item)
: message_center::MessageView(notification), item_(std::move(item)) {
SetLayoutManager(std::make_unique<views::BoxLayout>( SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::kVertical, gfx::Insets(), 0)); views::BoxLayout::kVertical, gfx::Insets(), 0));
...@@ -209,13 +210,13 @@ MediaNotificationView::MediaNotificationView( ...@@ -209,13 +210,13 @@ MediaNotificationView::MediaNotificationView(
message_center::kNotificationCornerRadius); message_center::kNotificationCornerRadius);
UpdateViewForExpandedState(); UpdateViewForExpandedState();
Shell::Get()->media_notification_controller()->SetView(notification_id(), if (item_)
this); item_->SetView(this);
} }
MediaNotificationView::~MediaNotificationView() { MediaNotificationView::~MediaNotificationView() {
Shell::Get()->media_notification_controller()->SetView(notification_id(), if (item_)
nullptr); item_->SetView(nullptr);
} }
void MediaNotificationView::UpdateWithNotification( void MediaNotificationView::UpdateWithNotification(
...@@ -284,8 +285,10 @@ void MediaNotificationView::ButtonPressed(views::Button* sender, ...@@ -284,8 +285,10 @@ void MediaNotificationView::ButtonPressed(views::Button* sender,
} }
if (sender->parent() == button_row_) { if (sender->parent() == button_row_) {
message_center::MessageCenter::Get()->ClickOnNotificationButton( if (item_) {
notification_id(), sender->tag()); item_->OnMediaSessionActionButtonPressed(
static_cast<MediaSessionAction>(sender->tag()));
}
return; return;
} }
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#define ASH_MEDIA_MEDIA_NOTIFICATION_VIEW_H_ #define ASH_MEDIA_MEDIA_NOTIFICATION_VIEW_H_
#include "ash/ash_export.h" #include "ash/ash_export.h"
#include "base/memory/weak_ptr.h"
#include "services/media_session/public/mojom/media_session.mojom.h" #include "services/media_session/public/mojom/media_session.mojom.h"
#include "ui/message_center/views/message_view.h" #include "ui/message_center/views/message_view.h"
#include "ui/views/controls/button/button.h" #include "ui/views/controls/button/button.h"
...@@ -18,9 +19,6 @@ class ImageSkia; ...@@ -18,9 +19,6 @@ class ImageSkia;
namespace media_session { namespace media_session {
struct MediaMetadata; struct MediaMetadata;
} // namespace media_session
namespace media_session {
enum class MediaSessionAction; enum class MediaSessionAction;
} // namespace media_session } // namespace media_session
...@@ -37,6 +35,7 @@ class View; ...@@ -37,6 +35,7 @@ class View;
namespace ash { namespace ash {
class MediaNotificationBackground; class MediaNotificationBackground;
class MediaNotificationItem;
// MediaNotificationView will show up as a custom notification. It will show the // MediaNotificationView will show up as a custom notification. It will show the
// currently playing media and provide playback controls. There will also be // currently playing media and provide playback controls. There will also be
...@@ -63,8 +62,8 @@ class ASH_EXPORT MediaNotificationView : public message_center::MessageView, ...@@ -63,8 +62,8 @@ class ASH_EXPORT MediaNotificationView : public message_center::MessageView,
kMaxValue = kCount, kMaxValue = kCount,
}; };
explicit MediaNotificationView( MediaNotificationView(const message_center::Notification& notification,
const message_center::Notification& notification); base::WeakPtr<MediaNotificationItem> item);
~MediaNotificationView() override; ~MediaNotificationView() override;
// message_center::MessageView: // message_center::MessageView:
...@@ -115,6 +114,8 @@ class ASH_EXPORT MediaNotificationView : public message_center::MessageView, ...@@ -115,6 +114,8 @@ class ASH_EXPORT MediaNotificationView : public message_center::MessageView,
void UpdateForegroundColor(); void UpdateForegroundColor();
base::WeakPtr<MediaNotificationItem> item_;
// View containing close and settings buttons. // View containing close and settings buttons.
std::unique_ptr<message_center::NotificationControlButtonsView> std::unique_ptr<message_center::NotificationControlButtonsView>
control_buttons_view_; control_buttons_view_;
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
#include "ash/focus_cycler.h" #include "ash/focus_cycler.h"
#include "ash/media/media_notification_background.h" #include "ash/media/media_notification_background.h"
#include "ash/media/media_notification_constants.h" #include "ash/media/media_notification_constants.h"
#include "ash/media/media_notification_controller.h" #include "ash/media/media_notification_controller_impl.h"
#include "ash/media/media_notification_item.h" #include "ash/media/media_notification_item.h"
#include "ash/public/cpp/ash_features.h" #include "ash/public/cpp/ash_features.h"
#include "ash/public/cpp/shell_window_ids.h" #include "ash/public/cpp/shell_window_ids.h"
...@@ -262,7 +262,8 @@ class MediaNotificationViewTest : public AshTestBase { ...@@ -262,7 +262,8 @@ class MediaNotificationViewTest : public AshTestBase {
private: private:
std::unique_ptr<message_center::MessageView> CreateAndCaptureCustomView( std::unique_ptr<message_center::MessageView> CreateAndCaptureCustomView(
const message_center::Notification& notification) { const message_center::Notification& notification) {
auto view = std::make_unique<MediaNotificationView>(notification); auto view = std::make_unique<MediaNotificationView>(
notification, GetItem()->GetWeakPtr());
view_ = view.get(); view_ = view.get();
return view; return view;
} }
......
...@@ -65,7 +65,7 @@ ...@@ -65,7 +65,7 @@
#include "ash/magnifier/magnification_controller.h" #include "ash/magnifier/magnification_controller.h"
#include "ash/magnifier/partial_magnification_controller.h" #include "ash/magnifier/partial_magnification_controller.h"
#include "ash/media/media_controller.h" #include "ash/media/media_controller.h"
#include "ash/media/media_notification_controller.h" #include "ash/media/media_notification_controller_impl.h"
#include "ash/multi_device_setup/multi_device_notification_presenter.h" #include "ash/multi_device_setup/multi_device_notification_presenter.h"
#include "ash/new_window_controller.h" #include "ash/new_window_controller.h"
#include "ash/note_taking_controller.h" #include "ash/note_taking_controller.h"
...@@ -849,8 +849,8 @@ Shell::~Shell() { ...@@ -849,8 +849,8 @@ Shell::~Shell() {
// before it. // before it.
detachable_base_handler_.reset(); detachable_base_handler_.reset();
// MediaNotificationController depends on MessageCenter and must be destructed // MediaNotificationControllerImpl depends on MessageCenter and must be
// before it. // destructed before it.
media_notification_controller_.reset(); media_notification_controller_.reset();
// Destroys the MessageCenter singleton, so must happen late. // Destroys the MessageCenter singleton, so must happen late.
...@@ -1154,7 +1154,7 @@ void Shell::Init( ...@@ -1154,7 +1154,7 @@ void Shell::Init(
if (base::FeatureList::IsEnabled(features::kMediaSessionNotification)) { if (base::FeatureList::IsEnabled(features::kMediaSessionNotification)) {
media_notification_controller_ = media_notification_controller_ =
std::make_unique<MediaNotificationController>(connector_); std::make_unique<MediaNotificationControllerImpl>(connector_);
} }
for (auto& observer : shell_observers_) for (auto& observer : shell_observers_)
......
...@@ -140,7 +140,7 @@ class LoginScreenController; ...@@ -140,7 +140,7 @@ class LoginScreenController;
class MagnificationController; class MagnificationController;
class TabletModeController; class TabletModeController;
class MediaController; class MediaController;
class MediaNotificationController; class MediaNotificationControllerImpl;
class MessageCenterController; class MessageCenterController;
class MouseCursorEventFilter; class MouseCursorEventFilter;
class MruWindowTracker; class MruWindowTracker;
...@@ -414,7 +414,7 @@ class ASH_EXPORT Shell : public SessionObserver, ...@@ -414,7 +414,7 @@ class ASH_EXPORT Shell : public SessionObserver,
return magnification_controller_.get(); return magnification_controller_.get();
} }
MediaController* media_controller() { return media_controller_.get(); } MediaController* media_controller() { return media_controller_.get(); }
MediaNotificationController* media_notification_controller() { MediaNotificationControllerImpl* media_notification_controller() {
return media_notification_controller_.get(); return media_notification_controller_.get();
} }
MessageCenterController* message_center_controller() { MessageCenterController* message_center_controller() {
...@@ -695,7 +695,8 @@ class ASH_EXPORT Shell : public SessionObserver, ...@@ -695,7 +695,8 @@ class ASH_EXPORT Shell : public SessionObserver,
std::unique_ptr<LogoutConfirmationController> logout_confirmation_controller_; std::unique_ptr<LogoutConfirmationController> logout_confirmation_controller_;
std::unique_ptr<TabletModeController> tablet_mode_controller_; std::unique_ptr<TabletModeController> tablet_mode_controller_;
std::unique_ptr<MediaController> media_controller_; std::unique_ptr<MediaController> media_controller_;
std::unique_ptr<MediaNotificationController> media_notification_controller_; std::unique_ptr<MediaNotificationControllerImpl>
media_notification_controller_;
std::unique_ptr<MruWindowTracker> mru_window_tracker_; std::unique_ptr<MruWindowTracker> mru_window_tracker_;
std::unique_ptr<MultiDeviceNotificationPresenter> std::unique_ptr<MultiDeviceNotificationPresenter>
multidevice_notification_presenter_; multidevice_notification_presenter_;
......
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