Commit 8d59fda0 authored by Wojciech Dzierżanowski's avatar Wojciech Dzierżanowski Committed by Chromium LUCI CQ

Fix PiP window control visibility handling and tests

MediaSessionPictureInPictureWindowControllerBrowserTest.PreviousTrackButtonVisibility
(and a few similar tests too) didn't test the exact scenario it was meant to
test.  If it had, it would have _always_ failed when trying to verify the
button bounds at the end: the button size is set to 0x0 upon hiding, so bounds
comparison of a hidden and visible button should always fail.

The reason it didn't fail most of the time is because the button size was,
unintentionally, 0x0 throughout the test.  The size was kept at 0x0 because
never throughout the test was OverlayWindowViews::OnUpdateControlsBounds()
called with `show_previous_track_button_` true.

The test didn't execute the intended paths because RunUntilIdle() is misleading
here.  Seeing it used after setMediaSessionActionHandler('previoustrack') and
video.play(), we were inclined to think the previous track button was now
visible and the layout had been updated.  What really happened was we would
become idle even though the delayed OnUpdateControlsBounds() task had been
posted.  As the mouse was hovered over the window the button became visible,
but the layout was still pending.  And so a plausible explanation for the flaky
failures is: when executing under heavy load sometimes the 1-second delayed
layout did happen early enough to store the 20x20 size in
`previous_track_bounds`.

In this CL, we rework the test to wait for the desired events explicitly
instead of calling RunUntilIdle().  Other tests checking control visibility are
mirated as well.  The tests that add/remove buttons with the controls hidden
are moved to the unit test because it's hard for a browser test to know when
it's the right time to make assertions about layout if all the controls are
hidden.

Once fixed, the test uncovered two issues with the implementation which were
subsequently fixed:

 - When creating the window, UpdateControlsVisibility(false) was called too
   early.  The operations in OnRootViewReady() would override its effect.

 - Control visibility must be updated along with their layout.  Otherwise, a
   change in control visibility has no effect on the views::View visibility if
   it happens while the controls are shown (during hover).

With that done, we can enable
MediaSessionPictureInPictureWindowControllerBrowserTest.PreviousTrackButtonVisibility
again.

Bug: 985303
Change-Id: I411cdd2d0a55489ec5b7eb82bab95e05d84d323d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2587053Reviewed-by: default avatarMounir Lamouri <mlamouri@chromium.org>
Commit-Queue: Wojciech Dzierżanowski <wdzierzanowski@opera.com>
Cr-Commit-Position: refs/heads/master@{#837992}
parent 1d9b3e01
...@@ -4,9 +4,11 @@ ...@@ -4,9 +4,11 @@
#include "content/public/browser/picture_in_picture_window_controller.h" #include "content/public/browser/picture_in_picture_window_controller.h"
#include "base/barrier_closure.h"
#include "base/bind.h" #include "base/bind.h"
#include "base/files/file_util.h" #include "base/files/file_util.h"
#include "base/path_service.h" #include "base/path_service.h"
#include "base/scoped_observation.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_feature_list.h" #include "base/test/scoped_feature_list.h"
#include "build/build_config.h" #include "build/build_config.h"
...@@ -52,6 +54,7 @@ ...@@ -52,6 +54,7 @@
#include "ui/events/base_event_utils.h" #include "ui/events/base_event_utils.h"
#include "ui/gfx/codec/png_codec.h" #include "ui/gfx/codec/png_codec.h"
#include "ui/views/controls/button/image_button.h" #include "ui/views/controls/button/image_button.h"
#include "ui/views/view_observer.h"
#include "ui/views/widget/widget_observer.h" #include "ui/views/widget/widget_observer.h"
#if BUILDFLAG(IS_CHROMEOS_ASH) #if BUILDFLAG(IS_CHROMEOS_ASH)
...@@ -95,6 +98,47 @@ class MockPictureInPictureWindowController ...@@ -95,6 +98,47 @@ class MockPictureInPictureWindowController
const base::FilePath::CharType kPictureInPictureWindowSizePage[] = const base::FilePath::CharType kPictureInPictureWindowSizePage[] =
FILE_PATH_LITERAL("media/picture-in-picture/window-size.html"); FILE_PATH_LITERAL("media/picture-in-picture/window-size.html");
// Determines whether |control| is visible taking into account OverlayWindow's
// custom control hiding that includes setting the size to 0x0.
bool IsOverlayWindowControlVisible(views::View* control) {
return control->IsDrawn() && !control->size().IsEmpty();
}
// An observer used to notify about control visibility changes.
class ControlVisibilityObserver : views::ViewObserver {
public:
explicit ControlVisibilityObserver(views::View* observed_view,
bool expected_visible,
base::OnceClosure callback)
: expected_visible_(expected_visible),
visibility_change_callback_(std::move(callback)) {
observation_.Observe(observed_view);
MaybeNotifyOfVisibilityChange(observed_view);
}
// views::ViewObserver overrides.
void OnViewVisibilityChanged(views::View* observed_view,
views::View* starting_view) override {
MaybeNotifyOfVisibilityChange(observed_view);
}
void OnViewBoundsChanged(views::View* observed_view) override {
MaybeNotifyOfVisibilityChange(observed_view);
}
private:
void MaybeNotifyOfVisibilityChange(views::View* observed_view) {
if (visibility_change_callback_ &&
IsOverlayWindowControlVisible(observed_view) == expected_visible_) {
std::move(visibility_change_callback_).Run();
}
}
base::ScopedObservation<views::View, views::ViewObserver> observation_{this};
bool expected_visible_;
base::OnceClosure visibility_change_callback_;
};
} // namespace } // namespace
class PictureInPictureWindowControllerBrowserTest class PictureInPictureWindowControllerBrowserTest
...@@ -164,6 +208,24 @@ class PictureInPictureWindowControllerBrowserTest ...@@ -164,6 +208,24 @@ class PictureInPictureWindowControllerBrowserTest
EXPECT_FALSE(in_picture_in_picture); EXPECT_FALSE(in_picture_in_picture);
} }
// Makes sure all |controls| have the expected visibility state, waiting if
// necessary.
void AssertControlsVisible(std::vector<views::View*> controls,
bool expected_visible) {
base::RunLoop run_loop;
const auto barrier =
base::BarrierClosure(controls.size(), run_loop.QuitClosure());
std::vector<std::unique_ptr<ControlVisibilityObserver>> observers;
for (views::View* control : controls) {
observers.push_back(std::make_unique<ControlVisibilityObserver>(
control, expected_visible, barrier));
}
run_loop.Run();
for (views::View* control : controls)
ASSERT_EQ(IsOverlayWindowControlVisible(control), expected_visible);
}
class WidgetBoundsChangeWaiter final : public views::WidgetObserver { class WidgetBoundsChangeWaiter final : public views::WidgetObserver {
public: public:
explicit WidgetBoundsChangeWaiter(views::Widget* widget) explicit WidgetBoundsChangeWaiter(views::Widget* widget)
...@@ -189,7 +251,8 @@ class PictureInPictureWindowControllerBrowserTest ...@@ -189,7 +251,8 @@ class PictureInPictureWindowControllerBrowserTest
base::RunLoop run_loop_; base::RunLoop run_loop_;
}; };
void MoveMouseOver(OverlayWindowViews* window) { void MoveMouseOverOverlayWindow() {
auto* const window = GetOverlayWindow();
gfx::Point p(window->GetBounds().x(), window->GetBounds().y()); gfx::Point p(window->GetBounds().x(), window->GetBounds().y());
ui::MouseEvent moved_over(ui::ET_MOUSE_MOVED, p, p, ui::EventTimeForNow(), ui::MouseEvent moved_over(ui::ET_MOUSE_MOVED, p, p, ui::EventTimeForNow(),
ui::EF_NONE, ui::EF_NONE); ui::EF_NONE, ui::EF_NONE);
...@@ -400,7 +463,7 @@ IN_PROC_BROWSER_TEST_F(PictureInPicturePixelComparisonBrowserTest, ...@@ -400,7 +463,7 @@ IN_PROC_BROWSER_TEST_F(PictureInPicturePixelComparisonBrowserTest,
EXPECT_TRUE(content::ExecuteScript(active_web_contents, "video.play();")); EXPECT_TRUE(content::ExecuteScript(active_web_contents, "video.play();"));
Wait(base::TimeDelta::FromSeconds(3)); Wait(base::TimeDelta::FromSeconds(3));
MoveMouseOver(GetOverlayWindow()); MoveMouseOverOverlayWindow();
TakeOverlayWindowScreenshot(GetOverlayWindow()); TakeOverlayWindowScreenshot(GetOverlayWindow());
base::FilePath expected_pause_image_path = base::FilePath expected_pause_image_path =
...@@ -428,7 +491,7 @@ IN_PROC_BROWSER_TEST_F(PictureInPicturePixelComparisonBrowserTest, ...@@ -428,7 +491,7 @@ IN_PROC_BROWSER_TEST_F(PictureInPicturePixelComparisonBrowserTest,
EXPECT_TRUE(content::ExecuteScript(active_web_contents, "video.pause();")); EXPECT_TRUE(content::ExecuteScript(active_web_contents, "video.pause();"));
Wait(base::TimeDelta::FromSeconds(3)); Wait(base::TimeDelta::FromSeconds(3));
MoveMouseOver(GetOverlayWindow()); MoveMouseOverOverlayWindow();
TakeOverlayWindowScreenshot(GetOverlayWindow()); TakeOverlayWindowScreenshot(GetOverlayWindow());
ASSERT_TRUE(ReadImageFile(expected_play_image_path, &expected_image)); ASSERT_TRUE(ReadImageFile(expected_play_image_path, &expected_image));
EXPECT_TRUE(CompareImages(GetResultBitmap(), expected_image)); EXPECT_TRUE(CompareImages(GetResultBitmap(), expected_image));
...@@ -831,18 +894,11 @@ IN_PROC_BROWSER_TEST_F( ...@@ -831,18 +894,11 @@ IN_PROC_BROWSER_TEST_F(
EXPECT_TRUE(window_controller()->GetWindowForTesting()->IsVisible()); EXPECT_TRUE(window_controller()->GetWindowForTesting()->IsVisible());
EXPECT_TRUE(GetOverlayWindow()->video_layer_for_testing()->visible()); EXPECT_TRUE(GetOverlayWindow()->video_layer_for_testing()->visible());
EXPECT_FALSE(GetOverlayWindow() AssertControlsVisible(
->previous_track_controls_view_for_testing() {GetOverlayWindow()->previous_track_controls_view_for_testing(),
->layer() GetOverlayWindow()->play_pause_controls_view_for_testing(),
->visible()); GetOverlayWindow()->next_track_controls_view_for_testing()},
EXPECT_FALSE(GetOverlayWindow() false);
->play_pause_controls_view_for_testing()
->layer()
->visible());
EXPECT_FALSE(GetOverlayWindow()
->next_track_controls_view_for_testing()
->layer()
->visible());
} }
// Tests that we can enter Picture-in-Picture when a video is not preloaded, // Tests that we can enter Picture-in-Picture when a video is not preloaded,
...@@ -1717,26 +1773,26 @@ IN_PROC_BROWSER_TEST_F(PictureInPictureWindowControllerBrowserTest, ...@@ -1717,26 +1773,26 @@ IN_PROC_BROWSER_TEST_F(PictureInPictureWindowControllerBrowserTest,
ASSERT_NE(nullptr, GetOverlayWindow()); ASSERT_NE(nullptr, GetOverlayWindow());
// Play/Pause button is displayed if video is not a mediastream. // Play/Pause button is displayed if video is not a mediastream.
MoveMouseOver(GetOverlayWindow()); MoveMouseOverOverlayWindow();
EXPECT_TRUE( AssertControlsVisible(
GetOverlayWindow()->play_pause_controls_view_for_testing()->IsDrawn()); {GetOverlayWindow()->play_pause_controls_view_for_testing()}, true);
// Play/Pause button is hidden if video is a mediastream. // Play/Pause button is hidden if video is a mediastream.
bool result = false; bool result = false;
ASSERT_TRUE(content::ExecuteScriptAndExtractBool( ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
active_web_contents, "changeVideoSrcToMediaStream();", &result)); active_web_contents, "changeVideoSrcToMediaStream();", &result));
EXPECT_TRUE(result); EXPECT_TRUE(result);
MoveMouseOver(GetOverlayWindow()); MoveMouseOverOverlayWindow();
EXPECT_FALSE( AssertControlsVisible(
GetOverlayWindow()->play_pause_controls_view_for_testing()->IsDrawn()); {GetOverlayWindow()->play_pause_controls_view_for_testing()}, false);
// Play/Pause button is not hidden anymore when video is not a mediastream. // Play/Pause button is not hidden anymore when video is not a mediastream.
ASSERT_TRUE(content::ExecuteScriptAndExtractBool( ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
active_web_contents, "changeVideoSrc();", &result)); active_web_contents, "changeVideoSrc();", &result));
EXPECT_TRUE(result); EXPECT_TRUE(result);
MoveMouseOver(GetOverlayWindow()); MoveMouseOverOverlayWindow();
EXPECT_TRUE( AssertControlsVisible(
GetOverlayWindow()->play_pause_controls_view_for_testing()->IsDrawn()); {GetOverlayWindow()->play_pause_controls_view_for_testing()}, true);
} }
// Check that page visibility API events are fired when tab is hidden, shown, // Check that page visibility API events are fired when tab is hidden, shown,
...@@ -1871,11 +1927,9 @@ IN_PROC_BROWSER_TEST_F(MediaSessionPictureInPictureWindowControllerBrowserTest, ...@@ -1871,11 +1927,9 @@ IN_PROC_BROWSER_TEST_F(MediaSessionPictureInPictureWindowControllerBrowserTest,
// Skip Ad button is not displayed initially when mouse is hovering over the // Skip Ad button is not displayed initially when mouse is hovering over the
// window. // window.
MoveMouseOver(GetOverlayWindow()); MoveMouseOverOverlayWindow();
EXPECT_FALSE(GetOverlayWindow() AssertControlsVisible(
->skip_ad_controls_view_for_testing() {GetOverlayWindow()->skip_ad_controls_view_for_testing()}, false);
->layer()
->visible());
content::WebContents* active_web_contents = content::WebContents* active_web_contents =
browser()->tab_strip_model()->GetActiveWebContents(); browser()->tab_strip_model()->GetActiveWebContents();
...@@ -1884,33 +1938,28 @@ IN_PROC_BROWSER_TEST_F(MediaSessionPictureInPictureWindowControllerBrowserTest, ...@@ -1884,33 +1938,28 @@ IN_PROC_BROWSER_TEST_F(MediaSessionPictureInPictureWindowControllerBrowserTest,
// hovering over the window and media session action handler has been set. // hovering over the window and media session action handler has been set.
ASSERT_TRUE(content::ExecuteScript( ASSERT_TRUE(content::ExecuteScript(
active_web_contents, "setMediaSessionActionHandler('skipad');")); active_web_contents, "setMediaSessionActionHandler('skipad');"));
base::RunLoop().RunUntilIdle(); MoveMouseOverOverlayWindow();
MoveMouseOver(GetOverlayWindow()); // Wait for the controls to show if necessary, then verify the Skip Ad button
EXPECT_FALSE(GetOverlayWindow() // is not among those shown.
->skip_ad_controls_view_for_testing() AssertControlsVisible(
->layer() {GetOverlayWindow()->back_to_tab_controls_for_testing()}, true);
->visible()); EXPECT_FALSE(IsOverlayWindowControlVisible(
GetOverlayWindow()->skip_ad_controls_view_for_testing()));
// Play video and check that Skip Ad button is now displayed when // Play video and check that Skip Ad button is now displayed when
// video plays and mouse is hovering over the window. // video plays and mouse is hovering over the window.
ASSERT_TRUE(content::ExecuteScript(active_web_contents, "video.play();")); ASSERT_TRUE(content::ExecuteScript(active_web_contents, "video.play();"));
base::RunLoop().RunUntilIdle(); MoveMouseOverOverlayWindow();
MoveMouseOver(GetOverlayWindow()); AssertControlsVisible(
EXPECT_TRUE(GetOverlayWindow() {GetOverlayWindow()->skip_ad_controls_view_for_testing()}, true);
->skip_ad_controls_view_for_testing()
->layer()
->visible());
// Unset action handler and check that Skip Ad button is not displayed when // Unset action handler and check that Skip Ad button is not displayed when
// video plays and mouse is hovering over the window. // video plays and mouse is hovering over the window.
ASSERT_TRUE(content::ExecuteScript( ASSERT_TRUE(content::ExecuteScript(
active_web_contents, "unsetMediaSessionActionHandler('skipad');")); active_web_contents, "unsetMediaSessionActionHandler('skipad');"));
base::RunLoop().RunUntilIdle(); MoveMouseOverOverlayWindow();
MoveMouseOver(GetOverlayWindow()); AssertControlsVisible(
EXPECT_FALSE(GetOverlayWindow() {GetOverlayWindow()->skip_ad_controls_view_for_testing()}, false);
->skip_ad_controls_view_for_testing()
->layer()
->visible());
} }
// Tests that the Play/Plause button is displayed in the Picture-in-Picture // Tests that the Play/Plause button is displayed in the Picture-in-Picture
...@@ -1932,10 +1981,13 @@ IN_PROC_BROWSER_TEST_F(MediaSessionPictureInPictureWindowControllerBrowserTest, ...@@ -1932,10 +1981,13 @@ IN_PROC_BROWSER_TEST_F(MediaSessionPictureInPictureWindowControllerBrowserTest,
ASSERT_TRUE(content::ExecuteScriptAndExtractBool( ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
active_web_contents, "changeVideoSrcToMediaStream();", &result)); active_web_contents, "changeVideoSrcToMediaStream();", &result));
EXPECT_TRUE(result); EXPECT_TRUE(result);
base::RunLoop().RunUntilIdle(); MoveMouseOverOverlayWindow();
MoveMouseOver(GetOverlayWindow()); // Wait for the controls to show if necessary, then verify the Play/Pause
EXPECT_FALSE( // button is not among those shown.
GetOverlayWindow()->play_pause_controls_view_for_testing()->IsDrawn()); AssertControlsVisible(
{GetOverlayWindow()->back_to_tab_controls_for_testing()}, true);
EXPECT_FALSE(IsOverlayWindowControlVisible(
GetOverlayWindow()->play_pause_controls_view_for_testing()));
// Play second video (non-muted) so that Media Session becomes active. // Play second video (non-muted) so that Media Session becomes active.
ASSERT_TRUE( ASSERT_TRUE(
...@@ -1945,28 +1997,29 @@ IN_PROC_BROWSER_TEST_F(MediaSessionPictureInPictureWindowControllerBrowserTest, ...@@ -1945,28 +1997,29 @@ IN_PROC_BROWSER_TEST_F(MediaSessionPictureInPictureWindowControllerBrowserTest,
// is still hidden when mouse is hovering over the window. // is still hidden when mouse is hovering over the window.
ASSERT_TRUE(content::ExecuteScript(active_web_contents, ASSERT_TRUE(content::ExecuteScript(active_web_contents,
"setMediaSessionActionHandler('play');")); "setMediaSessionActionHandler('play');"));
base::RunLoop().RunUntilIdle(); MoveMouseOverOverlayWindow();
MoveMouseOver(GetOverlayWindow()); // Wait for the controls to show if necessary, then verify the Play/Pause
EXPECT_FALSE( // button is not among those shown.
GetOverlayWindow()->play_pause_controls_view_for_testing()->IsDrawn()); AssertControlsVisible(
{GetOverlayWindow()->back_to_tab_controls_for_testing()}, true);
EXPECT_FALSE(IsOverlayWindowControlVisible(
GetOverlayWindow()->play_pause_controls_view_for_testing()));
// Set Media Session action "pause" handler and check that Play/Pause button // Set Media Session action "pause" handler and check that Play/Pause button
// is now displayed when mouse is hovering over the window. // is now displayed when mouse is hovering over the window.
ASSERT_TRUE(content::ExecuteScript(active_web_contents, ASSERT_TRUE(content::ExecuteScript(active_web_contents,
"setMediaSessionActionHandler('pause');")); "setMediaSessionActionHandler('pause');"));
base::RunLoop().RunUntilIdle(); MoveMouseOverOverlayWindow();
MoveMouseOver(GetOverlayWindow()); AssertControlsVisible(
EXPECT_TRUE( {GetOverlayWindow()->play_pause_controls_view_for_testing()}, true);
GetOverlayWindow()->play_pause_controls_view_for_testing()->IsDrawn());
// Unset Media Session action "pause" handler and check that Play/Pause button // Unset Media Session action "pause" handler and check that Play/Pause button
// is hidden when mouse is hovering over the window. // is hidden when mouse is hovering over the window.
ASSERT_TRUE(content::ExecuteScript( ASSERT_TRUE(content::ExecuteScript(
active_web_contents, "unsetMediaSessionActionHandler('pause');")); active_web_contents, "unsetMediaSessionActionHandler('pause');"));
base::RunLoop().RunUntilIdle(); MoveMouseOverOverlayWindow();
MoveMouseOver(GetOverlayWindow()); AssertControlsVisible(
EXPECT_FALSE( {GetOverlayWindow()->play_pause_controls_view_for_testing()}, false);
GetOverlayWindow()->play_pause_controls_view_for_testing()->IsDrawn());
ASSERT_TRUE( ASSERT_TRUE(
content::ExecuteScript(active_web_contents, "exitPictureInPicture();")); content::ExecuteScript(active_web_contents, "exitPictureInPicture();"));
...@@ -1974,16 +2027,14 @@ IN_PROC_BROWSER_TEST_F(MediaSessionPictureInPictureWindowControllerBrowserTest, ...@@ -1974,16 +2027,14 @@ IN_PROC_BROWSER_TEST_F(MediaSessionPictureInPictureWindowControllerBrowserTest,
// Reset Media Session action "pause" handler and check that Play/Pause button // Reset Media Session action "pause" handler and check that Play/Pause button
// is now displayed when mouse is hovering over the window when it enters // is now displayed when mouse is hovering over the window when it enters
// Picture-in-Picture again. // Picture-in-Picture again.
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(content::ExecuteScript(active_web_contents, ASSERT_TRUE(content::ExecuteScript(active_web_contents,
"setMediaSessionActionHandler('pause');")); "setMediaSessionActionHandler('pause');"));
ASSERT_TRUE(content::ExecuteScriptAndExtractBool( ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
active_web_contents, "enterPictureInPicture();", &result)); active_web_contents, "enterPictureInPicture();", &result));
EXPECT_TRUE(result); EXPECT_TRUE(result);
base::RunLoop().RunUntilIdle(); MoveMouseOverOverlayWindow();
MoveMouseOver(GetOverlayWindow()); AssertControlsVisible(
EXPECT_TRUE( {GetOverlayWindow()->play_pause_controls_view_for_testing()}, true);
GetOverlayWindow()->play_pause_controls_view_for_testing()->IsDrawn());
} }
// Tests that a Next Track button is displayed in the Picture-in-Picture window // Tests that a Next Track button is displayed in the Picture-in-Picture window
...@@ -1996,97 +2047,53 @@ IN_PROC_BROWSER_TEST_F(MediaSessionPictureInPictureWindowControllerBrowserTest, ...@@ -1996,97 +2047,53 @@ IN_PROC_BROWSER_TEST_F(MediaSessionPictureInPictureWindowControllerBrowserTest,
// Next Track button is not displayed initially when mouse is hovering over // Next Track button is not displayed initially when mouse is hovering over
// the window. // the window.
MoveMouseOver(GetOverlayWindow()); MoveMouseOverOverlayWindow();
EXPECT_FALSE( AssertControlsVisible(
GetOverlayWindow()->next_track_controls_view_for_testing()->IsDrawn()); {GetOverlayWindow()->next_track_controls_view_for_testing()}, false);
content::WebContents* active_web_contents = content::WebContents* active_web_contents =
browser()->tab_strip_model()->GetActiveWebContents(); browser()->tab_strip_model()->GetActiveWebContents();
// Next Track button is not displayed if video is not playing even if mouse is // Next Track button is not displayed if video is not playing even if mouse
// hovering over the window and media session action handler has been set. // is hovering over the window and media session action handler has been set.
ASSERT_TRUE(content::ExecuteScript( ASSERT_TRUE(content::ExecuteScript(
active_web_contents, "setMediaSessionActionHandler('nexttrack');")); active_web_contents, "setMediaSessionActionHandler('nexttrack');"));
base::RunLoop().RunUntilIdle(); MoveMouseOverOverlayWindow();
MoveMouseOver(GetOverlayWindow()); // Wait for the controls to show if necessary, then verify the Next Track
EXPECT_FALSE( // button is not among those shown.
GetOverlayWindow()->next_track_controls_view_for_testing()->IsDrawn()); AssertControlsVisible(
{GetOverlayWindow()->back_to_tab_controls_for_testing()}, true);
// Play video and check that Next Track button is now displayed when EXPECT_FALSE(IsOverlayWindowControlVisible(
// video plays and mouse is hovering over the window. GetOverlayWindow()->next_track_controls_view_for_testing()));
// Play video and check that Next Track button is now displayed when video
// plays and mouse is hovering over the window.
ASSERT_TRUE(content::ExecuteScript(active_web_contents, "video.play();")); ASSERT_TRUE(content::ExecuteScript(active_web_contents, "video.play();"));
base::RunLoop().RunUntilIdle(); MoveMouseOverOverlayWindow();
MoveMouseOver(GetOverlayWindow()); AssertControlsVisible(
EXPECT_TRUE( {GetOverlayWindow()->next_track_controls_view_for_testing()}, true);
GetOverlayWindow()->next_track_controls_view_for_testing()->IsDrawn());
gfx::Rect next_track_bounds = GetOverlayWindow()
->next_track_controls_view_for_testing()
->GetBoundsInScreen();
// Unset action handler and check that Next Track button is not displayed when // Unset action handler and check that Next Track button is not displayed
// video plays and mouse is hovering over the window. // when video plays and mouse is hovering over the window.
ASSERT_TRUE(content::ExecuteScript( ASSERT_TRUE(content::ExecuteScript(
active_web_contents, "unsetMediaSessionActionHandler('nexttrack');")); active_web_contents, "unsetMediaSessionActionHandler('nexttrack');"));
base::RunLoop().RunUntilIdle(); MoveMouseOverOverlayWindow();
MoveMouseOver(GetOverlayWindow()); AssertControlsVisible(
EXPECT_FALSE( {GetOverlayWindow()->next_track_controls_view_for_testing()}, false);
GetOverlayWindow()->next_track_controls_view_for_testing()->IsDrawn());
// Next Track button is still at the same previous location.
EXPECT_EQ(next_track_bounds, GetOverlayWindow()
->next_track_controls_view_for_testing()
->GetBoundsInScreen());
}
// Tests that Next Track button bounds are updated right away when
// Picture-in-Picture window controls are hidden.
IN_PROC_BROWSER_TEST_F(MediaSessionPictureInPictureWindowControllerBrowserTest,
NextTrackButtonBounds) {
LoadTabAndEnterPictureInPicture(
browser(), base::FilePath(kPictureInPictureWindowSizePage));
ASSERT_NE(GetOverlayWindow(), nullptr);
content::WebContents* active_web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
gfx::Rect next_track_bounds = GetOverlayWindow()
->next_track_controls_view_for_testing()
->GetBoundsInScreen();
ASSERT_TRUE(content::ExecuteScript(
active_web_contents, "setMediaSessionActionHandler('nexttrack');"));
ASSERT_TRUE(content::ExecuteScript(active_web_contents, "video.play();"));
base::RunLoop().RunUntilIdle();
EXPECT_NE(next_track_bounds, GetOverlayWindow()
->next_track_controls_view_for_testing()
->GetBoundsInScreen());
} }
// Tests that a Previous Track button is displayed in the Picture-in-Picture // Tests that a Previous Track button is displayed in the Picture-in-Picture
// window when Media Session Action "previoustrack" is handled by the website. // window when Media Session Action "previoustrack" is handled by the website.
// TODO(crbug.com/985303): Flaky on Linux.
// TODO(crbug.com/1052397): Revisit once build flag switch of lacros-chrome is
// complete.
#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
#define MAYBE_PreviousTrackButtonVisibility \
DISABLED_PreviousTrackButtonVisibility
#else
#define MAYBE_PreviousTrackButtonVisibility PreviousTrackButtonVisibility
#endif
IN_PROC_BROWSER_TEST_F(MediaSessionPictureInPictureWindowControllerBrowserTest, IN_PROC_BROWSER_TEST_F(MediaSessionPictureInPictureWindowControllerBrowserTest,
MAYBE_PreviousTrackButtonVisibility) { PreviousTrackButtonVisibility) {
LoadTabAndEnterPictureInPicture( LoadTabAndEnterPictureInPicture(
browser(), base::FilePath(kPictureInPictureWindowSizePage)); browser(), base::FilePath(kPictureInPictureWindowSizePage));
ASSERT_NE(GetOverlayWindow(), nullptr);
// Previous Track button is not displayed initially when mouse is hovering // Previous Track button is not displayed initially when mouse is hovering
// over the window. // over the window.
MoveMouseOver(GetOverlayWindow()); MoveMouseOverOverlayWindow();
EXPECT_FALSE(GetOverlayWindow() AssertControlsVisible(
->previous_track_controls_view_for_testing() {GetOverlayWindow()->previous_track_controls_view_for_testing()}, false);
->IsDrawn());
content::WebContents* active_web_contents = content::WebContents* active_web_contents =
browser()->tab_strip_model()->GetActiveWebContents(); browser()->tab_strip_model()->GetActiveWebContents();
...@@ -2096,67 +2103,28 @@ IN_PROC_BROWSER_TEST_F(MediaSessionPictureInPictureWindowControllerBrowserTest, ...@@ -2096,67 +2103,28 @@ IN_PROC_BROWSER_TEST_F(MediaSessionPictureInPictureWindowControllerBrowserTest,
// set. // set.
ASSERT_TRUE(content::ExecuteScript( ASSERT_TRUE(content::ExecuteScript(
active_web_contents, "setMediaSessionActionHandler('previoustrack');")); active_web_contents, "setMediaSessionActionHandler('previoustrack');"));
base::RunLoop().RunUntilIdle(); MoveMouseOverOverlayWindow();
MoveMouseOver(GetOverlayWindow()); // Wait for the controls to show if necessary, then verify the Previous Track
EXPECT_FALSE(GetOverlayWindow() // button is not among those shown.
->previous_track_controls_view_for_testing() AssertControlsVisible(
->IsDrawn()); {GetOverlayWindow()->back_to_tab_controls_for_testing()}, true);
EXPECT_FALSE(IsOverlayWindowControlVisible(
GetOverlayWindow()->previous_track_controls_view_for_testing()));
// Play video and check that Previous Track button is now displayed when // Play video and check that Previous Track button is now displayed when
// video plays and mouse is hovering over the window. // video plays and mouse is hovering over the window.
ASSERT_TRUE(content::ExecuteScript(active_web_contents, "video.play();")); ASSERT_TRUE(content::ExecuteScript(active_web_contents, "video.play();"));
base::RunLoop().RunUntilIdle(); MoveMouseOverOverlayWindow();
MoveMouseOver(GetOverlayWindow()); AssertControlsVisible(
EXPECT_TRUE(GetOverlayWindow() {GetOverlayWindow()->previous_track_controls_view_for_testing()}, true);
->previous_track_controls_view_for_testing()
->IsDrawn());
gfx::Rect previous_track_bounds =
GetOverlayWindow()
->previous_track_controls_view_for_testing()
->GetBoundsInScreen();
// Unset action handler and check that Previous Track button is not displayed // Unset action handler and check that Previous Track button is not displayed
// when video plays and mouse is hovering over the window. // when video plays and mouse is hovering over the window.
ASSERT_TRUE(content::ExecuteScript( ASSERT_TRUE(content::ExecuteScript(
active_web_contents, "unsetMediaSessionActionHandler('previoustrack');")); active_web_contents, "unsetMediaSessionActionHandler('previoustrack');"));
base::RunLoop().RunUntilIdle(); MoveMouseOverOverlayWindow();
MoveMouseOver(GetOverlayWindow()); AssertControlsVisible(
EXPECT_FALSE(GetOverlayWindow() {GetOverlayWindow()->previous_track_controls_view_for_testing()}, false);
->previous_track_controls_view_for_testing()
->IsDrawn());
// Previous Track button is still at the same previous location.
EXPECT_EQ(previous_track_bounds,
GetOverlayWindow()
->previous_track_controls_view_for_testing()
->GetBoundsInScreen());
}
// Tests that Previous Track button bounds are updated right away when
// Picture-in-Picture window controls are hidden.
IN_PROC_BROWSER_TEST_F(MediaSessionPictureInPictureWindowControllerBrowserTest,
PreviousTrackButtonBounds) {
LoadTabAndEnterPictureInPicture(
browser(), base::FilePath(kPictureInPictureWindowSizePage));
ASSERT_NE(GetOverlayWindow(), nullptr);
content::WebContents* active_web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
gfx::Rect previous_track_bounds =
GetOverlayWindow()
->previous_track_controls_view_for_testing()
->GetBoundsInScreen();
ASSERT_TRUE(content::ExecuteScript(
active_web_contents, "setMediaSessionActionHandler('previoustrack');"));
ASSERT_TRUE(content::ExecuteScript(active_web_contents, "video.play();"));
base::RunLoop().RunUntilIdle();
EXPECT_NE(previous_track_bounds,
GetOverlayWindow()
->previous_track_controls_view_for_testing()
->GetBoundsInScreen());
} }
// Tests that clicking the Skip Ad button in the Picture-in-Picture window // Tests that clicking the Skip Ad button in the Picture-in-Picture window
......
...@@ -480,7 +480,6 @@ void OverlayWindowViews::SetUpViews() { ...@@ -480,7 +480,6 @@ void OverlayWindowViews::SetUpViews() {
resize_handle_view_ = resize_handle_view_ =
AddChildView(&view_holder_, std::move(resize_handle_view)); AddChildView(&view_holder_, std::move(resize_handle_view));
#endif #endif
UpdateControlsVisibility(false);
} }
void OverlayWindowViews::OnRootViewReady() { void OverlayWindowViews::OnRootViewReady() {
...@@ -496,6 +495,9 @@ void OverlayWindowViews::OnRootViewReady() { ...@@ -496,6 +495,9 @@ void OverlayWindowViews::OnRootViewReady() {
for (std::unique_ptr<views::View>& child : view_holder_) for (std::unique_ptr<views::View>& child : view_holder_)
contents_view->AddChildView(std::move(child)); contents_view->AddChildView(std::move(child));
view_holder_.clear(); view_holder_.clear();
// Don't show the controls until the mouse hovers over the window.
UpdateControlsVisibility(false);
} }
void OverlayWindowViews::UpdateLayerBoundsWithLetterboxing( void OverlayWindowViews::UpdateLayerBoundsWithLetterboxing(
...@@ -626,7 +628,7 @@ void OverlayWindowViews::OnUpdateControlsBounds() { ...@@ -626,7 +628,7 @@ void OverlayWindowViews::OnUpdateControlsBounds() {
visible_controls_views[0]->SetPosition( visible_controls_views[0]->SetPosition(
gfx::Point(mid_window_x - kSecondaryControlSize.width() / 2, gfx::Point(mid_window_x - kSecondaryControlSize.width() / 2,
secondary_control_y)); secondary_control_y));
return; break;
} }
case 2: { case 2: {
/* | ----- [ ] [ ] ----- | */ /* | ----- [ ] [ ] ----- | */
...@@ -638,7 +640,7 @@ void OverlayWindowViews::OnUpdateControlsBounds() { ...@@ -638,7 +640,7 @@ void OverlayWindowViews::OnUpdateControlsBounds() {
visible_controls_views[1]->SetSize(kSecondaryControlSize); visible_controls_views[1]->SetSize(kSecondaryControlSize);
visible_controls_views[1]->SetPosition( visible_controls_views[1]->SetPosition(
gfx::Point(mid_window_x + kControlMargin / 2, secondary_control_y)); gfx::Point(mid_window_x + kControlMargin / 2, secondary_control_y));
return; break;
} }
case 3: { case 3: {
/* | --- [ ] [ ] [ ] --- | */ /* | --- [ ] [ ] [ ] --- | */
...@@ -669,7 +671,7 @@ void OverlayWindowViews::OnUpdateControlsBounds() { ...@@ -669,7 +671,7 @@ void OverlayWindowViews::OnUpdateControlsBounds() {
mid_window_x + kSecondaryControlSize.width() / 2 + kControlMargin, mid_window_x + kSecondaryControlSize.width() / 2 + kControlMargin,
secondary_control_y)); secondary_control_y));
} }
return; break;
} }
case 4: { case 4: {
/* | - [ ] [ ] [ ] [ ] - | */ /* | - [ ] [ ] [ ] [ ] - | */
...@@ -692,10 +694,15 @@ void OverlayWindowViews::OnUpdateControlsBounds() { ...@@ -692,10 +694,15 @@ void OverlayWindowViews::OnUpdateControlsBounds() {
visible_controls_views[3]->SetPosition(gfx::Point( visible_controls_views[3]->SetPosition(gfx::Point(
mid_window_x + kControlMargin * 3 / 2 + kSecondaryControlSize.width(), mid_window_x + kControlMargin * 3 / 2 + kSecondaryControlSize.width(),
secondary_control_y)); secondary_control_y));
return; break;
} }
default:
NOTREACHED();
} }
DCHECK(false);
// This will actually update the visibility of a control that was just added
// or removed, see SetPlayPauseButtonVisibility(), etc.
UpdateControlsVisibility(AreControlsVisible());
} }
gfx::Rect OverlayWindowViews::CalculateControlsBounds(int x, gfx::Rect OverlayWindowViews::CalculateControlsBounds(int x,
...@@ -779,7 +786,11 @@ void OverlayWindowViews::SetPlayPauseButtonVisibility(bool is_visible) { ...@@ -779,7 +786,11 @@ void OverlayWindowViews::SetPlayPauseButtonVisibility(bool is_visible) {
} }
void OverlayWindowViews::SetSkipAdButtonVisibility(bool is_visible) { void OverlayWindowViews::SetSkipAdButtonVisibility(bool is_visible) {
if (show_skip_ad_button_ == is_visible)
return;
show_skip_ad_button_ = is_visible; show_skip_ad_button_ = is_visible;
UpdateControlsBounds();
} }
void OverlayWindowViews::SetNextTrackButtonVisibility(bool is_visible) { void OverlayWindowViews::SetNextTrackButtonVisibility(bool is_visible) {
...@@ -1032,6 +1043,11 @@ bool OverlayWindowViews::AreControlsVisible() const { ...@@ -1032,6 +1043,11 @@ bool OverlayWindowViews::AreControlsVisible() const {
return controls_scrim_view_->layer()->visible(); return controls_scrim_view_->layer()->visible();
} }
bool OverlayWindowViews::IsLayoutPendingForTesting() const {
return update_controls_bounds_timer_ &&
update_controls_bounds_timer_->IsRunning();
}
ui::Layer* OverlayWindowViews::GetControlsScrimLayer() { ui::Layer* OverlayWindowViews::GetControlsScrimLayer() {
return controls_scrim_view_->layer(); return controls_scrim_view_->layer();
} }
...@@ -1108,8 +1124,8 @@ OverlayWindowViews::skip_ad_controls_view_for_testing() const { ...@@ -1108,8 +1124,8 @@ OverlayWindowViews::skip_ad_controls_view_for_testing() const {
return skip_ad_controls_view_; return skip_ad_controls_view_;
} }
gfx::Point OverlayWindowViews::back_to_tab_image_position_for_testing() const { views::View* OverlayWindowViews::back_to_tab_controls_for_testing() const {
return back_to_tab_controls_view_->origin(); return back_to_tab_controls_view_;
} }
gfx::Point OverlayWindowViews::close_image_position_for_testing() const { gfx::Point OverlayWindowViews::close_image_position_for_testing() const {
......
...@@ -84,11 +84,15 @@ class OverlayWindowViews : public content::OverlayWindow, ...@@ -84,11 +84,15 @@ class OverlayWindowViews : public content::OverlayWindow,
// visible. // visible.
bool AreControlsVisible() const; bool AreControlsVisible() const;
// Determines whether a layout of the window controls has been scheduled but
// is not done yet.
bool IsLayoutPendingForTesting() const;
views::PlaybackImageButton* play_pause_controls_view_for_testing() const; views::PlaybackImageButton* play_pause_controls_view_for_testing() const;
views::TrackImageButton* next_track_controls_view_for_testing() const; views::TrackImageButton* next_track_controls_view_for_testing() const;
views::TrackImageButton* previous_track_controls_view_for_testing() const; views::TrackImageButton* previous_track_controls_view_for_testing() const;
views::SkipAdLabelButton* skip_ad_controls_view_for_testing() const; views::SkipAdLabelButton* skip_ad_controls_view_for_testing() const;
gfx::Point back_to_tab_image_position_for_testing() const; views::View* back_to_tab_controls_for_testing() const;
gfx::Point close_image_position_for_testing() const; gfx::Point close_image_position_for_testing() const;
gfx::Point resize_handle_position_for_testing() const; gfx::Point resize_handle_position_for_testing() const;
OverlayWindowViews::PlaybackState playback_state_for_testing() const; OverlayWindowViews::PlaybackState playback_state_for_testing() const;
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <utility> #include <utility>
#include "chrome/browser/ui/views/overlay/overlay_window_views.h" #include "chrome/browser/ui/views/overlay/overlay_window_views.h"
#include "chrome/browser/ui/views/overlay/track_image_button.h"
#include "chrome/test/base/testing_profile.h" #include "chrome/test/base/testing_profile.h"
#include "chrome/test/views/chrome_views_test_base.h" #include "chrome/test/views/chrome_views_test_base.h"
#include "content/public/browser/picture_in_picture_window_controller.h" #include "content/public/browser/picture_in_picture_window_controller.h"
...@@ -276,3 +277,40 @@ TEST_F(OverlayWindowViewsTest, IgnoreInvalidMaximumSize) { ...@@ -276,3 +277,40 @@ TEST_F(OverlayWindowViewsTest, IgnoreInvalidMaximumSize) {
overlay_window().OnNativeWidgetMove(); overlay_window().OnNativeWidgetMove();
EXPECT_EQ(gfx::Size(500, 500), overlay_window().GetMaximumSize()); EXPECT_EQ(gfx::Size(500, 500), overlay_window().GetMaximumSize());
} }
// Tests that Next Track button bounds are updated right away when window
// controls are hidden.
TEST_F(OverlayWindowViewsTest, NextTrackButtonAddedWhenControlsHidden) {
ASSERT_FALSE(overlay_window().AreControlsVisible());
ASSERT_TRUE(overlay_window()
.next_track_controls_view_for_testing()
->size()
.IsEmpty());
const auto origin_before_layout =
overlay_window().next_track_controls_view_for_testing()->origin();
overlay_window().SetNextTrackButtonVisibility(true);
EXPECT_NE(overlay_window().next_track_controls_view_for_testing()->origin(),
origin_before_layout);
EXPECT_FALSE(overlay_window().IsLayoutPendingForTesting());
}
// Tests that Previous Track button bounds are updated right away when window
// controls are hidden.
TEST_F(OverlayWindowViewsTest, PreviousTrackButtonAddedWhenControlsHidden) {
ASSERT_FALSE(overlay_window().AreControlsVisible());
ASSERT_TRUE(overlay_window()
.previous_track_controls_view_for_testing()
->size()
.IsEmpty());
const auto origin_before_layout =
overlay_window().previous_track_controls_view_for_testing()->origin();
overlay_window().SetPreviousTrackButtonVisibility(true);
EXPECT_NE(
overlay_window().previous_track_controls_view_for_testing()->origin(),
origin_before_layout);
EXPECT_FALSE(overlay_window().IsLayoutPendingForTesting());
}
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