Commit 6e9c4c80 authored by Tommy Steimel's avatar Tommy Steimel Committed by Commit Bot

GMC: Reland "Add interactive UI tests"

This CL relands the interactive UI tests for the global media controls.
The original CL was flaky for the ShowsMetadataAndControlsMedia test
because sometimes it checked for toolbar icon visibility after media
started but before the media starting caused the icon to appear. This
CL fixes that by waiting for the icon to appear.

TESTED=Was locally flaking about once every 20 runs before the fix.
After the fix, I ran it 300 times and it passed every time.

Description from original CL (crrev.com/c/1753690):
This CL adds some basic interactive UI tests for the global media
controls. This ensures we have better coverage than just unit tests.

Bug: 993879, 999297
Change-Id: I7abf36e4f82b64b262d3d0a7eb9d426e8ae1c5f2
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1814671Reviewed-by: default avatarScott Violet <sky@chromium.org>
Commit-Queue: Tommy Steimel <steimel@chromium.org>
Cr-Commit-Position: refs/heads/master@{#702882}
parent 71afe050
...@@ -41,6 +41,7 @@ class ASH_EXPORT MediaNotificationContainerImpl ...@@ -41,6 +41,7 @@ class ASH_EXPORT MediaNotificationContainerImpl
void OnExpanded(bool expanded) override; void OnExpanded(bool expanded) override;
void OnMediaSessionInfoChanged( void OnMediaSessionInfoChanged(
const media_session::mojom::MediaSessionInfoPtr& session_info) override {} const media_session::mojom::MediaSessionInfoPtr& session_info) override {}
void OnMediaSessionMetadataChanged() override {}
void OnVisibleActionsChanged( void OnVisibleActionsChanged(
const std::set<media_session::mojom::MediaSessionAction>& actions) const std::set<media_session::mojom::MediaSessionAction>& actions)
override {} override {}
......
...@@ -2811,6 +2811,7 @@ jumbo_split_static_library("ui") { ...@@ -2811,6 +2811,7 @@ jumbo_split_static_library("ui") {
"views/global_error_bubble_view.h", "views/global_error_bubble_view.h",
"views/global_media_controls/media_dialog_view.cc", "views/global_media_controls/media_dialog_view.cc",
"views/global_media_controls/media_dialog_view.h", "views/global_media_controls/media_dialog_view.h",
"views/global_media_controls/media_dialog_view_observer.h",
"views/global_media_controls/media_notification_container_impl.cc", "views/global_media_controls/media_notification_container_impl.cc",
"views/global_media_controls/media_notification_container_impl.h", "views/global_media_controls/media_notification_container_impl.h",
"views/global_media_controls/media_notification_list_view.cc", "views/global_media_controls/media_notification_list_view.cc",
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "chrome/browser/ui/global_media_controls/media_toolbar_button_controller.h" #include "chrome/browser/ui/global_media_controls/media_toolbar_button_controller.h"
#include "chrome/browser/ui/views/chrome_layout_provider.h" #include "chrome/browser/ui/views/chrome_layout_provider.h"
#include "chrome/browser/ui/views/global_media_controls/media_dialog_view_observer.h"
#include "chrome/browser/ui/views/global_media_controls/media_notification_container_impl.h" #include "chrome/browser/ui/views/global_media_controls/media_notification_container_impl.h"
#include "chrome/browser/ui/views/global_media_controls/media_notification_list_view.h" #include "chrome/browser/ui/views/global_media_controls/media_notification_list_view.h"
#include "services/media_session/public/mojom/media_session.mojom.h" #include "services/media_session/public/mojom/media_session.mojom.h"
...@@ -66,6 +67,9 @@ void MediaDialogView::ShowMediaSession( ...@@ -66,6 +67,9 @@ void MediaDialogView::ShowMediaSession(
id, std::make_unique<MediaNotificationContainerImpl>(this, controller_, id, std::make_unique<MediaNotificationContainerImpl>(this, controller_,
id, item)); id, item));
OnAnchorBoundsChanged(); OnAnchorBoundsChanged();
for (auto& observer : observers_)
observer.OnMediaSessionShown();
} }
void MediaDialogView::HideMediaSession(const std::string& id) { void MediaDialogView::HideMediaSession(const std::string& id) {
...@@ -75,6 +79,9 @@ void MediaDialogView::HideMediaSession(const std::string& id) { ...@@ -75,6 +79,9 @@ void MediaDialogView::HideMediaSession(const std::string& id) {
HideDialog(); HideDialog();
else else
OnAnchorBoundsChanged(); OnAnchorBoundsChanged();
for (auto& observer : observers_)
observer.OnMediaSessionHidden();
} }
int MediaDialogView::GetDialogButtons() const { int MediaDialogView::GetDialogButtons() const {
...@@ -111,6 +118,19 @@ gfx::Size MediaDialogView::CalculatePreferredSize() const { ...@@ -111,6 +118,19 @@ gfx::Size MediaDialogView::CalculatePreferredSize() const {
return gfx::Size(width, 1); return gfx::Size(width, 1);
} }
void MediaDialogView::AddObserver(MediaDialogViewObserver* observer) {
observers_.AddObserver(observer);
}
void MediaDialogView::RemoveObserver(MediaDialogViewObserver* observer) {
observers_.RemoveObserver(observer);
}
void MediaDialogView::OnMediaSessionMetadataChanged() {
for (auto& observer : observers_)
observer.OnMediaSessionMetadataUpdated();
}
MediaDialogView::MediaDialogView(views::View* anchor_view, MediaDialogView::MediaDialogView(views::View* anchor_view,
MediaToolbarButtonController* controller, MediaToolbarButtonController* controller,
service_manager::Connector* connector) service_manager::Connector* connector)
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#ifndef CHROME_BROWSER_UI_VIEWS_GLOBAL_MEDIA_CONTROLS_MEDIA_DIALOG_VIEW_H_ #ifndef CHROME_BROWSER_UI_VIEWS_GLOBAL_MEDIA_CONTROLS_MEDIA_DIALOG_VIEW_H_
#define CHROME_BROWSER_UI_VIEWS_GLOBAL_MEDIA_CONTROLS_MEDIA_DIALOG_VIEW_H_ #define CHROME_BROWSER_UI_VIEWS_GLOBAL_MEDIA_CONTROLS_MEDIA_DIALOG_VIEW_H_
#include "base/observer_list.h"
#include "base/optional.h" #include "base/optional.h"
#include "chrome/browser/ui/global_media_controls/media_dialog_delegate.h" #include "chrome/browser/ui/global_media_controls/media_dialog_delegate.h"
#include "ui/views/bubble/bubble_dialog_delegate_view.h" #include "ui/views/bubble/bubble_dialog_delegate_view.h"
...@@ -13,6 +14,7 @@ namespace service_manager { ...@@ -13,6 +14,7 @@ namespace service_manager {
class Connector; class Connector;
} // namespace service_manager } // namespace service_manager
class MediaDialogViewObserver;
class MediaNotificationListView; class MediaNotificationListView;
class MediaToolbarButtonController; class MediaToolbarButtonController;
...@@ -26,6 +28,8 @@ class MediaDialogView : public views::BubbleDialogDelegateView, ...@@ -26,6 +28,8 @@ class MediaDialogView : public views::BubbleDialogDelegateView,
static void HideDialog(); static void HideDialog();
static bool IsShowing(); static bool IsShowing();
static MediaDialogView* GetDialogViewForTesting() { return instance_; }
// MediaDialogDelegate implementation. // MediaDialogDelegate implementation.
void ShowMediaSession( void ShowMediaSession(
const std::string& id, const std::string& id,
...@@ -40,6 +44,11 @@ class MediaDialogView : public views::BubbleDialogDelegateView, ...@@ -40,6 +44,11 @@ class MediaDialogView : public views::BubbleDialogDelegateView,
void AddedToWidget() override; void AddedToWidget() override;
gfx::Size CalculatePreferredSize() const override; gfx::Size CalculatePreferredSize() const override;
void AddObserver(MediaDialogViewObserver* observer);
void RemoveObserver(MediaDialogViewObserver* observer);
void OnMediaSessionMetadataChanged();
private: private:
explicit MediaDialogView(views::View* anchor_view, explicit MediaDialogView(views::View* anchor_view,
MediaToolbarButtonController* controller, MediaToolbarButtonController* controller,
...@@ -59,6 +68,8 @@ class MediaDialogView : public views::BubbleDialogDelegateView, ...@@ -59,6 +68,8 @@ class MediaDialogView : public views::BubbleDialogDelegateView,
MediaNotificationListView* const active_sessions_view_; MediaNotificationListView* const active_sessions_view_;
base::ObserverList<MediaDialogViewObserver> observers_;
DISALLOW_COPY_AND_ASSIGN(MediaDialogView); DISALLOW_COPY_AND_ASSIGN(MediaDialogView);
}; };
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/views/global_media_controls/media_dialog_view.h"
#include "base/run_loop.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/global_media_controls/media_toolbar_button_observer.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/browser/ui/views/global_media_controls/media_dialog_view_observer.h"
#include "chrome/browser/ui/views/global_media_controls/media_toolbar_button_view.h"
#include "chrome/browser/ui/views/toolbar/toolbar_view.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/interactive_test_utils.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/media_start_stop_observer.h"
#include "media/base/media_switches.h"
#include "services/media_session/public/mojom/media_session.mojom.h"
#include "ui/views/controls/button/image_button.h"
using media_session::mojom::MediaSessionAction;
namespace {
class MediaToolbarButtonWatcher : public MediaToolbarButtonObserver,
public MediaDialogViewObserver {
public:
explicit MediaToolbarButtonWatcher(MediaToolbarButtonView* button)
: button_(button) {
button_->AddObserver(this);
}
~MediaToolbarButtonWatcher() override {
button_->RemoveObserver(this);
if (observed_dialog_ != nullptr &&
observed_dialog_ == MediaDialogView::GetDialogViewForTesting()) {
observed_dialog_->RemoveObserver(this);
}
}
// MediaDialogViewObserver implementation.
void OnMediaSessionShown() override { CheckDialogForText(); }
void OnMediaSessionHidden() override {}
void OnMediaSessionMetadataUpdated() override { CheckDialogForText(); }
// MediaToolbarButtonObserver implementation.
void OnMediaDialogOpened() override {
waiting_for_dialog_opened_ = false;
MaybeStopWaiting();
}
void OnMediaButtonShown() override {
waiting_for_button_shown_ = false;
MaybeStopWaiting();
}
void OnMediaButtonHidden() override {}
void OnMediaButtonEnabled() override {}
void OnMediaButtonDisabled() override {}
void WaitForDialogOpened() {
if (MediaDialogView::IsShowing())
return;
waiting_for_dialog_opened_ = true;
Wait();
}
void WaitForButtonShown() {
if (button_->GetVisible())
return;
waiting_for_button_shown_ = true;
Wait();
}
void WaitForDialogToContainText(const base::string16& text) {
if (DialogContainsText(text))
return;
waiting_for_dialog_to_contain_text_ = true;
expected_text_ = text;
observed_dialog_ = MediaDialogView::GetDialogViewForTesting();
observed_dialog_->AddObserver(this);
Wait();
}
private:
void CheckDialogForText() {
if (!waiting_for_dialog_to_contain_text_)
return;
if (!DialogContainsText(expected_text_))
return;
waiting_for_dialog_to_contain_text_ = false;
MaybeStopWaiting();
}
void MaybeStopWaiting() {
if (!run_loop_)
return;
if (!waiting_for_dialog_opened_ && !waiting_for_button_shown_ &&
!waiting_for_dialog_to_contain_text_) {
run_loop_->Quit();
}
}
void Wait() {
ASSERT_EQ(nullptr, run_loop_.get());
run_loop_ = std::make_unique<base::RunLoop>();
run_loop_->Run();
}
bool DialogContainsText(const base::string16& text) {
return ViewContainsText(MediaDialogView::GetDialogViewForTesting(), text);
}
// Recursively tries to find a views::Label containing |text| within |view|
// and its children.
bool ViewContainsText(const views::View* view, const base::string16& text) {
if (view->GetClassName() == views::Label::kViewClassName) {
const views::Label* label = static_cast<const views::Label*>(view);
if (label->GetText().find(text) != std::string::npos)
return true;
}
for (const views::View* child : view->children()) {
if (ViewContainsText(child, text))
return true;
}
return false;
}
MediaToolbarButtonView* const button_;
std::unique_ptr<base::RunLoop> run_loop_;
bool waiting_for_dialog_opened_ = false;
bool waiting_for_button_shown_ = false;
MediaDialogView* observed_dialog_ = nullptr;
bool waiting_for_dialog_to_contain_text_ = false;
base::string16 expected_text_;
DISALLOW_COPY_AND_ASSIGN(MediaToolbarButtonWatcher);
};
} // anonymous namespace
class MediaDialogViewBrowserTest : public InProcessBrowserTest {
public:
MediaDialogViewBrowserTest() = default;
~MediaDialogViewBrowserTest() override = default;
void SetUpCommandLine(base::CommandLine* command_line) override {
command_line->AppendSwitchASCII(
switches::kAutoplayPolicy,
switches::autoplay::kNoUserGestureRequiredPolicy);
}
MediaToolbarButtonView* GetToolbarIcon() {
return BrowserView::GetBrowserViewForBrowser(browser())
->toolbar()
->media_button();
}
void ClickToolbarIcon() { ClickButton(GetToolbarIcon()); }
bool IsToolbarIconVisible() { return GetToolbarIcon()->GetVisible(); }
void WaitForVisibleToolbarIcon() {
MediaToolbarButtonWatcher(GetToolbarIcon()).WaitForButtonShown();
}
void OpenTestURL() {
GURL url = ui_test_utils::GetTestUrl(
base::FilePath(FILE_PATH_LITERAL("media/session")),
base::FilePath(FILE_PATH_LITERAL("video-with-metadata.html")));
ui_test_utils::NavigateToURL(browser(), url);
}
void OpenDifferentMetadataURLInNewTab() {
GURL url = ui_test_utils::GetTestUrl(
base::FilePath(FILE_PATH_LITERAL("media/session")),
base::FilePath(
FILE_PATH_LITERAL("video-with-different-metadata.html")));
ui_test_utils::NavigateToURLWithDisposition(
browser(), url, WindowOpenDisposition::NEW_FOREGROUND_TAB,
ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
}
void StartPlayback() {
// The test HTML files used in these tests contain "play()" functions that
// play the video.
GetWebContents()->GetMainFrame()->ExecuteJavaScriptForTests(
base::ASCIIToUTF16("play()"), base::NullCallback());
}
void WaitForStart() {
content::MediaStartStopObserver observer(
GetWebContents(), content::MediaStartStopObserver::Type::kStart);
observer.Wait();
}
void WaitForStop() {
content::MediaStartStopObserver observer(
GetWebContents(), content::MediaStartStopObserver::Type::kStop);
observer.Wait();
}
void WaitForDialogOpened() {
MediaToolbarButtonWatcher(GetToolbarIcon()).WaitForDialogOpened();
}
bool IsDialogVisible() { return MediaDialogView::IsShowing(); }
void WaitForDialogToContainText(const base::string16& text) {
MediaToolbarButtonWatcher(GetToolbarIcon())
.WaitForDialogToContainText(text);
}
void ClickPauseButtonOnDialog() {
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(MediaDialogView::IsShowing());
ClickButton(GetButtonForAction(MediaSessionAction::kPause));
}
void ClickPlayButtonOnDialog() {
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(MediaDialogView::IsShowing());
ClickButton(GetButtonForAction(MediaSessionAction::kPlay));
}
private:
void ClickButton(views::Button* button) {
base::RunLoop closure_loop;
ui_test_utils::MoveMouseToCenterAndPress(
button, ui_controls::LEFT, ui_controls::DOWN | ui_controls::UP,
closure_loop.QuitClosure());
closure_loop.Run();
}
views::ImageButton* GetButtonForAction(MediaSessionAction action) {
return GetButtonForAction(
MediaDialogView::GetDialogViewForTesting()->children().front(),
static_cast<int>(action));
}
// Recursively tries to find a views::ImageButton for the given
// MediaSessionAction. This operates under the assumption that
// media_message_center::MediaNotificationView sets the tags of its action
// buttons to the MediaSessionAction value.
views::ImageButton* GetButtonForAction(views::View* view, int action) {
if (view->GetClassName() == views::ImageButton::kViewClassName) {
views::ImageButton* image_button = static_cast<views::ImageButton*>(view);
if (image_button->tag() == action)
return image_button;
}
for (views::View* child : view->children()) {
views::ImageButton* result = GetButtonForAction(child, action);
if (result)
return result;
}
return nullptr;
}
content::WebContents* GetWebContents() {
return browser()->tab_strip_model()->GetActiveWebContents();
}
DISALLOW_COPY_AND_ASSIGN(MediaDialogViewBrowserTest);
};
IN_PROC_BROWSER_TEST_F(MediaDialogViewBrowserTest,
ShowsMetadataAndControlsMedia) {
// The toolbar icon should not start visible.
EXPECT_FALSE(IsToolbarIconVisible());
// Opening a page with media that hasn't played yet should not make the
// toolbar icon visible.
OpenTestURL();
EXPECT_FALSE(IsToolbarIconVisible());
// Once playback starts, the icon should be visible, but the dialog should not
// appear if it hasn't been clicked.
StartPlayback();
WaitForStart();
WaitForVisibleToolbarIcon();
EXPECT_TRUE(IsToolbarIconVisible());
EXPECT_FALSE(IsDialogVisible());
// Clicking on the toolbar icon should open the dialog.
ClickToolbarIcon();
WaitForDialogOpened();
EXPECT_TRUE(IsDialogVisible());
// The dialog should contain the title and artist. These are taken from
// video-with-metadata.html.
WaitForDialogToContainText(base::ASCIIToUTF16("Big Buck Bunny"));
WaitForDialogToContainText(base::ASCIIToUTF16("Blender Foundation"));
// Clicking on the pause button in the dialog should pause the media on the
// page.
ClickPauseButtonOnDialog();
WaitForStop();
// Clicking on the play button in the dialog should play the media on the
// page.
ClickPlayButtonOnDialog();
WaitForStart();
// Clicking on the toolbar icon again should hide the dialog.
EXPECT_TRUE(IsDialogVisible());
ClickToolbarIcon();
EXPECT_FALSE(IsDialogVisible());
}
IN_PROC_BROWSER_TEST_F(MediaDialogViewBrowserTest, ShowsMultipleMediaSessions) {
// Open a tab and play media.
OpenTestURL();
StartPlayback();
WaitForStart();
// Open another tab and play different media.
OpenDifferentMetadataURLInNewTab();
StartPlayback();
WaitForStart();
// Open the media dialog.
ClickToolbarIcon();
WaitForDialogOpened();
EXPECT_TRUE(IsDialogVisible());
// The dialog should show both media sessions.
WaitForDialogToContainText(base::ASCIIToUTF16("Big Buck Bunny"));
WaitForDialogToContainText(base::ASCIIToUTF16("Blender Foundation"));
WaitForDialogToContainText(base::ASCIIToUTF16("Different Title"));
WaitForDialogToContainText(base::ASCIIToUTF16("Another Artist"));
}
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_UI_VIEWS_GLOBAL_MEDIA_CONTROLS_MEDIA_DIALOG_VIEW_OBSERVER_H_
#define CHROME_BROWSER_UI_VIEWS_GLOBAL_MEDIA_CONTROLS_MEDIA_DIALOG_VIEW_OBSERVER_H_
#include "base/observer_list_types.h"
class MediaDialogViewObserver : public base::CheckedObserver {
public:
// Called when a new media session is added to the dialog.
virtual void OnMediaSessionShown() = 0;
// Called when a media session is hidden from the dialog.
virtual void OnMediaSessionHidden() = 0;
// Called when a shown media session's metadata is updated.
virtual void OnMediaSessionMetadataUpdated() = 0;
protected:
~MediaDialogViewObserver() override = default;
};
#endif // CHROME_BROWSER_UI_VIEWS_GLOBAL_MEDIA_CONTROLS_MEDIA_DIALOG_VIEW_OBSERVER_H_
...@@ -108,6 +108,10 @@ void MediaNotificationContainerImpl::OnMediaSessionInfoChanged( ...@@ -108,6 +108,10 @@ void MediaNotificationContainerImpl::OnMediaSessionInfoChanged(
media_session::mojom::MediaPlaybackState::kPlaying); media_session::mojom::MediaPlaybackState::kPlaying);
} }
void MediaNotificationContainerImpl::OnMediaSessionMetadataChanged() {
parent_->OnMediaSessionMetadataChanged();
}
void MediaNotificationContainerImpl::OnVisibleActionsChanged( void MediaNotificationContainerImpl::OnVisibleActionsChanged(
const std::set<media_session::mojom::MediaSessionAction>& actions) { const std::set<media_session::mojom::MediaSessionAction>& actions) {
has_many_actions_ = actions.size() >= kMinVisibleActionsForExpanding; has_many_actions_ = actions.size() >= kMinVisibleActionsForExpanding;
......
...@@ -39,6 +39,7 @@ class MediaNotificationContainerImpl ...@@ -39,6 +39,7 @@ class MediaNotificationContainerImpl
void OnExpanded(bool expanded) override; void OnExpanded(bool expanded) override;
void OnMediaSessionInfoChanged( void OnMediaSessionInfoChanged(
const media_session::mojom::MediaSessionInfoPtr& session_info) override; const media_session::mojom::MediaSessionInfoPtr& session_info) override;
void OnMediaSessionMetadataChanged() override;
void OnVisibleActionsChanged( void OnVisibleActionsChanged(
const std::set<media_session::mojom::MediaSessionAction>& actions) const std::set<media_session::mojom::MediaSessionAction>& actions)
override; override;
......
...@@ -5683,6 +5683,9 @@ if (!is_android) { ...@@ -5683,6 +5683,9 @@ if (!is_android) {
deps += [ "//build/config/linux/gtk" ] deps += [ "//build/config/linux/gtk" ]
} }
} }
if (!is_chromeos) {
sources += [ "../browser/ui/views/global_media_controls/media_dialog_view_interactive_browsertest.cc" ]
}
if (use_aura || is_mac) { if (use_aura || is_mac) {
deps += [ "//ui/touch_selection" ] deps += [ "//ui/touch_selection" ]
} }
......
<!DOCTYPE html>
<html>
<head>
<title>Test page showing a video with media session actions and metadata</title>
</head>
<body>
<video id="video" controls loop>
<source src="../bigbuck.webm">
</video>
<script>
const video = document.getElementById('video');
// Called by the browser test to start playback. Note that the browser test
// needs to explicitly disable user gesture requirements for autoplay for this
// function to work.
function play() {
video.play().then(_ => {
setupMetadata();
setupActionHandlers();
});
}
function setupMetadata() {
// Use different metadata than the other test file.
navigator.mediaSession.metadata = new MediaMetadata({
title: "Different Title",
artist: "Another Artist"
});
}
function setupActionHandlers() {
// Add empty action handlers to tell the browser we want to show all the
// possible action buttons.
function doNothing() {}
navigator.mediaSession.setActionHandler('previoustrack', doNothing);
navigator.mediaSession.setActionHandler('nexttrack', doNothing);
navigator.mediaSession.setActionHandler('seekbackward', doNothing);
navigator.mediaSession.setActionHandler('seekforward', doNothing);
navigator.mediaSession.setActionHandler('play', _ => { video.play(); });
navigator.mediaSession.setActionHandler('pause', _ => { video.pause(); });
}
</script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<title>Test page showing a video with media session actions and metadata</title>
</head>
<body>
<video id="video" controls loop>
<source src="../bigbuck.webm">
</video>
<script>
const video = document.getElementById('video');
// Called by the browser test to start playback. Note that the browser test
// needs to explicitly disable user gesture requirements for autoplay for this
// function to work.
function play() {
video.play().then(_ => {
setupMetadata();
setupActionHandlers();
});
}
function setupMetadata() {
navigator.mediaSession.metadata = new MediaMetadata({
title: "Big Buck Bunny",
artist: "Blender Foundation"
});
}
function setupActionHandlers() {
// Add empty action handlers to tell the browser we want to show all the
// possible action buttons.
function doNothing() {}
navigator.mediaSession.setActionHandler('previoustrack', doNothing);
navigator.mediaSession.setActionHandler('nexttrack', doNothing);
navigator.mediaSession.setActionHandler('seekbackward', doNothing);
navigator.mediaSession.setActionHandler('seekforward', doNothing);
navigator.mediaSession.setActionHandler('play', _ => { video.play(); });
navigator.mediaSession.setActionHandler('pause', _ => { video.pause(); });
}
</script>
</body>
</html>
...@@ -28,6 +28,9 @@ class COMPONENT_EXPORT(MEDIA_MESSAGE_CENTER) MediaNotificationContainer { ...@@ -28,6 +28,9 @@ class COMPONENT_EXPORT(MEDIA_MESSAGE_CENTER) MediaNotificationContainer {
virtual void OnMediaSessionInfoChanged( virtual void OnMediaSessionInfoChanged(
const media_session::mojom::MediaSessionInfoPtr& session_info) = 0; const media_session::mojom::MediaSessionInfoPtr& session_info) = 0;
// Called when the metadata changes.
virtual void OnMediaSessionMetadataChanged() = 0;
// TODO(https://crbug.com/1003847): Use base::flat_set isntead. // TODO(https://crbug.com/1003847): Use base::flat_set isntead.
// Called when the set of visible MediaSessionActions changes. // Called when the set of visible MediaSessionActions changes.
virtual void OnVisibleActionsChanged( virtual void OnVisibleActionsChanged(
......
...@@ -328,6 +328,8 @@ void MediaNotificationView::UpdateWithMediaMetadata( ...@@ -328,6 +328,8 @@ void MediaNotificationView::UpdateWithMediaMetadata(
RecordMetadataHistogram(Metadata::kCount); RecordMetadataHistogram(Metadata::kCount);
container_->OnMediaSessionMetadataChanged();
PreferredSizeChanged(); PreferredSizeChanged();
Layout(); Layout();
SchedulePaint(); SchedulePaint();
......
...@@ -90,6 +90,7 @@ class MockMediaNotificationContainer : public MediaNotificationContainer { ...@@ -90,6 +90,7 @@ class MockMediaNotificationContainer : public MediaNotificationContainer {
MOCK_METHOD1( MOCK_METHOD1(
OnMediaSessionInfoChanged, OnMediaSessionInfoChanged,
void(const media_session::mojom::MediaSessionInfoPtr& session_info)); void(const media_session::mojom::MediaSessionInfoPtr& session_info));
MOCK_METHOD0(OnMediaSessionMetadataChanged, void());
MOCK_METHOD1(OnVisibleActionsChanged, MOCK_METHOD1(OnVisibleActionsChanged,
void(const std::set<MediaSessionAction>& actions)); void(const std::set<MediaSessionAction>& actions));
MOCK_METHOD1(OnMediaArtworkChanged, void(const gfx::ImageSkia& image)); MOCK_METHOD1(OnMediaArtworkChanged, void(const gfx::ImageSkia& image));
...@@ -598,6 +599,7 @@ TEST_F(MAYBE_MediaNotificationViewTest, UpdateMetadata_FromObserver) { ...@@ -598,6 +599,7 @@ TEST_F(MAYBE_MediaNotificationViewTest, UpdateMetadata_FromObserver) {
metadata.artist = base::ASCIIToUTF16("artist2"); metadata.artist = base::ASCIIToUTF16("artist2");
metadata.album = base::ASCIIToUTF16("album"); metadata.album = base::ASCIIToUTF16("album");
EXPECT_CALL(container(), OnMediaSessionMetadataChanged());
GetItem()->MediaSessionMetadataChanged(metadata); GetItem()->MediaSessionMetadataChanged(metadata);
view()->SetExpanded(true); view()->SetExpanded(true);
...@@ -962,6 +964,7 @@ TEST_F(MAYBE_MediaNotificationViewTest, Freezing_DoNotUpdateMetadata) { ...@@ -962,6 +964,7 @@ TEST_F(MAYBE_MediaNotificationViewTest, Freezing_DoNotUpdateMetadata) {
metadata.artist = base::ASCIIToUTF16("artist2"); metadata.artist = base::ASCIIToUTF16("artist2");
metadata.album = base::ASCIIToUTF16("album"); metadata.album = base::ASCIIToUTF16("album");
EXPECT_CALL(container(), OnMediaSessionMetadataChanged()).Times(0);
GetItem()->Freeze(); GetItem()->Freeze();
GetItem()->MediaSessionMetadataChanged(metadata); GetItem()->MediaSessionMetadataChanged(metadata);
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include "content/public/test/browser_test_utils.h" #include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_browser_test.h" #include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_utils.h" #include "content/public/test/content_browser_test_utils.h"
#include "content/public/test/media_start_stop_observer.h"
#include "content/public/test/test_utils.h" #include "content/public/test/test_utils.h"
#include "content/shell/browser/shell.h" #include "content/shell/browser/shell.h"
#include "media/base/media_switches.h" #include "media/base/media_switches.h"
...@@ -177,40 +178,6 @@ class MediaSessionBrowserTest : public ContentBrowserTest { ...@@ -177,40 +178,6 @@ class MediaSessionBrowserTest : public ContentBrowserTest {
base::test::ScopedFeatureList disabled_feature_list_; base::test::ScopedFeatureList disabled_feature_list_;
private: private:
class MediaStartStopObserver : public WebContentsObserver {
public:
enum class Type { kStart, kStop };
MediaStartStopObserver(WebContents* web_contents, Type type)
: WebContentsObserver(web_contents), type_(type) {}
void MediaStartedPlaying(const MediaPlayerInfo& info,
const MediaPlayerId& id) override {
if (type_ != Type::kStart)
return;
run_loop_.Quit();
}
void MediaStoppedPlaying(
const MediaPlayerInfo& info,
const MediaPlayerId& id,
WebContentsObserver::MediaStoppedReason reason) override {
if (type_ != Type::kStop)
return;
run_loop_.Quit();
}
void Wait() { run_loop_.Run(); }
private:
base::RunLoop run_loop_;
Type type_;
DISALLOW_COPY_AND_ASSIGN(MediaStartStopObserver);
};
void OnServerRequest(const net::test_server::HttpRequest& request) { void OnServerRequest(const net::test_server::HttpRequest& request) {
// Note this method is called on the EmbeddedTestServer's background thread. // Note this method is called on the EmbeddedTestServer's background thread.
base::AutoLock lock(visited_urls_lock_); base::AutoLock lock(visited_urls_lock_);
......
// Copyright 2019 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 "content/public/test/media_start_stop_observer.h"
namespace content {
MediaStartStopObserver::MediaStartStopObserver(WebContents* web_contents,
Type type)
: WebContentsObserver(web_contents), type_(type) {}
MediaStartStopObserver::~MediaStartStopObserver() = default;
void MediaStartStopObserver::MediaStartedPlaying(const MediaPlayerInfo& info,
const MediaPlayerId& id) {
if (type_ != Type::kStart)
return;
run_loop_.Quit();
}
void MediaStartStopObserver::MediaStoppedPlaying(
const MediaPlayerInfo& info,
const MediaPlayerId& id,
WebContentsObserver::MediaStoppedReason reason) {
if (type_ != Type::kStop)
return;
run_loop_.Quit();
}
void MediaStartStopObserver::Wait() {
run_loop_.Run();
}
} // namespace content
// Copyright 2019 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 CONTENT_PUBLIC_TEST_MEDIA_START_STOP_OBSERVER_H_
#define CONTENT_PUBLIC_TEST_MEDIA_START_STOP_OBSERVER_H_
#include "base/macros.h"
#include "base/run_loop.h"
#include "content/public/browser/web_contents_observer.h"
namespace content {
class WebContents;
// Used in tests to wait for media in a WebContents to start or stop playing.
class MediaStartStopObserver : public WebContentsObserver {
public:
enum class Type { kStart, kStop };
MediaStartStopObserver(WebContents* web_contents, Type type);
~MediaStartStopObserver() override;
// WebContentsObserver implementation.
void MediaStartedPlaying(const MediaPlayerInfo& info,
const MediaPlayerId& id) override;
void MediaStoppedPlaying(
const MediaPlayerInfo& info,
const MediaPlayerId& id,
WebContentsObserver::MediaStoppedReason reason) override;
void Wait();
private:
base::RunLoop run_loop_;
const Type type_;
DISALLOW_COPY_AND_ASSIGN(MediaStartStopObserver);
};
} // namespace content
#endif // CONTENT_PUBLIC_TEST_MEDIA_START_STOP_OBSERVER_H_
...@@ -132,6 +132,8 @@ jumbo_static_library("test_support") { ...@@ -132,6 +132,8 @@ jumbo_static_library("test_support") {
"../public/test/hit_test_region_observer.h", "../public/test/hit_test_region_observer.h",
"../public/test/javascript_test_observer.cc", "../public/test/javascript_test_observer.cc",
"../public/test/javascript_test_observer.h", "../public/test/javascript_test_observer.h",
"../public/test/media_start_stop_observer.cc",
"../public/test/media_start_stop_observer.h",
"../public/test/mock_browsing_data_remover_delegate.cc", "../public/test/mock_browsing_data_remover_delegate.cc",
"../public/test/mock_browsing_data_remover_delegate.h", "../public/test/mock_browsing_data_remover_delegate.h",
"../public/test/mock_download_manager.cc", "../public/test/mock_download_manager.cc",
......
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