#include "content/public/browser/picture_in_picture_window_controller.h"
#include "base/barrier_closure.h"
#include "base/files/file_util.h"
#include "base/functional/bind.h"
#include "base/memory/raw_ptr.h"
#include "base/path_service.h"
#include "base/scoped_observation.h"
#include "base/test/bind.h"
#include "base/test/scoped_feature_list.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/chrome_content_browser_client.h"
#include "chrome/browser/devtools/devtools_window_testing.h"
#include "chrome/browser/picture_in_picture/picture_in_picture_window_manager.h"
#include "chrome/browser/platform_util.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/ui/views/overlay/hang_up_button.h"
#include "chrome/browser/ui/views/overlay/playback_image_button.h"
#include "chrome/browser/ui/views/overlay/simple_overlay_window_image_button.h"
#include "chrome/browser/ui/views/overlay/skip_ad_label_button.h"
#include "chrome/browser/ui/views/overlay/toggle_camera_button.h"
#include "chrome/browser/ui/views/overlay/toggle_microphone_button.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/viz/common/frame_sinks/copy_output_request.h"
#include "components/viz/common/frame_sinks/copy_output_result.h"
#include "content/public/browser/media_session.h"
#include "content/public/browser/overlay_window.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_client.h"
#include "content/public/common/content_switches.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/fenced_frame_test_util.h"
#include "content/public/test/media_start_stop_observer.h"
#include "content/public/test/prerender_test_util.h"
#include "content/public/test/test_navigation_observer.h"
#include "media/base/media_switches.h"
#include "net/dns/mock_host_resolver.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "services/media_session/public/cpp/features.h"
#include "skia/ext/image_operations.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "third_party/blink/public/common/web_preferences/web_preferences.h"
#include "ui/compositor/compositor.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/test/draw_waiter_for_test.h"
#include "ui/display/display_switches.h"
#include "ui/events/base_event_utils.h"
#include "ui/gfx/codec/png_codec.h"
#include "ui/views/controls/button/image_button.h"
#include "ui/views/test/button_test_api.h"
#include "ui/views/view_observer.h"
#include "ui/views/widget/widget_observer.h"
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "ui/base/hit_test.h"
#endif
EvalJs;
ExecJs;
_;
namespace {
PictureInPictureWindowManagerdObservation;
class MockPictureInPictureWindowManagerObserver
: public PictureInPictureWindowManager::Observer { … };
class MockVideoPictureInPictureWindowController
: public content::VideoPictureInPictureWindowController { … };
const base::FilePath::CharType kPictureInPictureWindowSizePage[] = …);
const base::FilePath::CharType kPictureInPictureVideoConferencingPage[] = …);
bool IsOverlayWindowControlVisible(views::View* control) { … }
class ControlVisibilityObserver : views::ViewObserver { … };
class WidgetSizeChangeWaiter final : public views::WidgetObserver { … };
void WaitForTitle(content::WebContents* web_contents,
const std::u16string& expected_title) { … }
class OverlayControlsBecomingVisibleObserver : public views::ViewObserver { … };
}
class VideoPictureInPictureWindowControllerBrowserTest
: public InProcessBrowserTest { … };
IN_PROC_BROWSER_TEST_F(VideoPictureInPictureWindowControllerBrowserTest,
CreationAndVisibilityAndActivation) { … }
IN_PROC_BROWSER_TEST_F(VideoPictureInPictureWindowControllerBrowserTest,
ControlsVisibility) { … }
#if !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_CHROMEOS_LACROS)
class PictureInPicturePixelComparisonBrowserTest
: public VideoPictureInPictureWindowControllerBrowserTest { … };
IN_PROC_BROWSER_TEST_F(PictureInPicturePixelComparisonBrowserTest, VideoPlay) { … }
#endif
IN_PROC_BROWSER_TEST_F(VideoPictureInPictureWindowControllerBrowserTest,
TabIconUpdated) { … }
IN_PROC_BROWSER_TEST_F(VideoPictureInPictureWindowControllerBrowserTest,
NotifyCallback) { … }
IN_PROC_BROWSER_TEST_F(VideoPictureInPictureWindowControllerBrowserTest,
ResizeEventFired) { … }
IN_PROC_BROWSER_TEST_F(VideoPictureInPictureWindowControllerBrowserTest,
CloseWindowWhilePlaying) { … }
IN_PROC_BROWSER_TEST_F(VideoPictureInPictureWindowControllerBrowserTest,
CloseWindowWithoutPlaying) { … }
IN_PROC_BROWSER_TEST_F(VideoPictureInPictureWindowControllerBrowserTest,
CloseWindowCantEnterPictureInPictureAgain) { … }
IN_PROC_BROWSER_TEST_F(VideoPictureInPictureWindowControllerBrowserTest,
CloseWindowFromWebAPIWhilePlaying) { … }
IN_PROC_BROWSER_TEST_F(VideoPictureInPictureWindowControllerBrowserTest,
RequestPictureInPictureTwiceFromSameVideo) { … }
IN_PROC_BROWSER_TEST_F(VideoPictureInPictureWindowControllerBrowserTest,
OpenSecondPictureInPictureStopsFirst) { … }
IN_PROC_BROWSER_TEST_F(VideoPictureInPictureWindowControllerBrowserTest,
ResetVideoSrcKeepsPictureInPictureWindowOpened) { … }
IN_PROC_BROWSER_TEST_F(VideoPictureInPictureWindowControllerBrowserTest,
UpdateVideoSrcKeepsPictureInPictureWindowOpened) { … }
IN_PROC_BROWSER_TEST_F(
VideoPictureInPictureWindowControllerBrowserTest,
ChangeVideoSrcToMediaStreamKeepsPictureInPictureWindowOpened) { … }
IN_PROC_BROWSER_TEST_F(VideoPictureInPictureWindowControllerBrowserTest,
EnterMetadataPosterOptimisation) { … }
IN_PROC_BROWSER_TEST_F(VideoPictureInPictureWindowControllerBrowserTest,
CloseTwiceSideEffects) { … }
IN_PROC_BROWSER_TEST_F(VideoPictureInPictureWindowControllerBrowserTest,
PictureInPictureAfterClosingTab) { … }
IN_PROC_BROWSER_TEST_F(VideoPictureInPictureWindowControllerBrowserTest,
PictureInPictureDoNotCloseAfterClosingTab) { … }
IN_PROC_BROWSER_TEST_F(VideoPictureInPictureWindowControllerBrowserTest,
PictureInPictureDoNotCloseAfterKillingFrame) { … }
IN_PROC_BROWSER_TEST_F(VideoPictureInPictureWindowControllerBrowserTest,
RequestPictureInPictureAfterDisablePictureInPicture) { … }
IN_PROC_BROWSER_TEST_F(VideoPictureInPictureWindowControllerBrowserTest,
FrameEnterLeaveClosesWindow) { … }
IN_PROC_BROWSER_TEST_F(VideoPictureInPictureWindowControllerBrowserTest,
CrossOriginFrameEnterLeaveCloseWindow) { … }
IN_PROC_BROWSER_TEST_F(VideoPictureInPictureWindowControllerBrowserTest,
MultipleBrowserWindowOnePIPWindow) { … }
IN_PROC_BROWSER_TEST_F(VideoPictureInPictureWindowControllerBrowserTest,
EnterPictureInPictureThenNavigateAwayCloseWindow) { … }
IN_PROC_BROWSER_TEST_F(VideoPictureInPictureWindowControllerBrowserTest,
CloseWindowNotifiesController) { … }
IN_PROC_BROWSER_TEST_F(VideoPictureInPictureWindowControllerBrowserTest,
PlayPauseStateAtCreation) { … }
IN_PROC_BROWSER_TEST_F(VideoPictureInPictureWindowControllerBrowserTest,
EnterUsingControllerShowsWindow) { … }
IN_PROC_BROWSER_TEST_F(VideoPictureInPictureWindowControllerBrowserTest,
EnterUsingWebContentsThenUsingController) { … }
IN_PROC_BROWSER_TEST_F(VideoPictureInPictureWindowControllerBrowserTest,
EnterUsingControllerThenEnterUsingWebContents) { … }
#if BUILDFLAG(IS_CHROMEOS)
#define MAYBE_PreloadNoneSrcChangeThenLoad …
#else
#define MAYBE_PreloadNoneSrcChangeThenLoad …
#endif
IN_PROC_BROWSER_TEST_F(VideoPictureInPictureWindowControllerBrowserTest,
MAYBE_PreloadNoneSrcChangeThenLoad) { … }
IN_PROC_BROWSER_TEST_F(VideoPictureInPictureWindowControllerBrowserTest,
OpenInFrameWithDevToolsDoesNotCrash) { … }
#if BUILDFLAG(IS_CHROMEOS_ASH)
IN_PROC_BROWSER_TEST_F(VideoPictureInPictureWindowControllerBrowserTest,
MovingQuadrantsMovesBackToTabAndResizeControls) {
GURL test_page_url = ui_test_utils::GetTestUrl(
base::FilePath(base::FilePath::kCurrentDirectory),
base::FilePath(kPictureInPictureWindowSizePage));
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), test_page_url));
content::WebContents* active_web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
ASSERT_TRUE(active_web_contents);
SetUpWindowController(active_web_contents);
ASSERT_TRUE(window_controller());
ASSERT_FALSE(GetOverlayWindow());
ASSERT_EQ(true, EvalJs(active_web_contents, "enterPictureInPicture();"));
ASSERT_TRUE(GetOverlayWindow());
ASSERT_TRUE(GetOverlayWindow()->IsVisible());
gfx::Rect bottom_right_bounds = GetOverlayWindow()->GetBounds();
gfx::Point center(bottom_right_bounds.width() / 2,
bottom_right_bounds.height() / 2);
gfx::Point close_button_position =
GetOverlayWindow()->close_image_position_for_testing();
gfx::Point resize_button_position =
GetOverlayWindow()->resize_handle_position_for_testing();
EXPECT_LT(center.x(), close_button_position.x());
EXPECT_GT(center.y(), close_button_position.y());
EXPECT_GT(center.x(), resize_button_position.x());
EXPECT_GT(center.y(), resize_button_position.y());
EXPECT_EQ(HTTOPLEFT, GetOverlayWindow()->GetResizeHTComponent());
gfx::Rect bottom_left_bounds(0, bottom_right_bounds.y(),
bottom_right_bounds.width(),
bottom_right_bounds.height());
GetOverlayWindow()->SetBounds(bottom_left_bounds);
close_button_position =
GetOverlayWindow()->close_image_position_for_testing();
resize_button_position =
GetOverlayWindow()->resize_handle_position_for_testing();
EXPECT_GT(center.x(), close_button_position.x());
EXPECT_GT(center.y(), close_button_position.y());
EXPECT_LT(center.x(), resize_button_position.x());
EXPECT_GT(center.y(), resize_button_position.y());
EXPECT_EQ(HTTOPRIGHT, GetOverlayWindow()->GetResizeHTComponent());
gfx::Rect top_right_bounds(bottom_right_bounds.x(), 0,
bottom_right_bounds.width(),
bottom_right_bounds.height());
GetOverlayWindow()->SetBounds(top_right_bounds);
close_button_position =
GetOverlayWindow()->close_image_position_for_testing();
resize_button_position =
GetOverlayWindow()->resize_handle_position_for_testing();
EXPECT_LT(center.x(), close_button_position.x());
EXPECT_GT(center.y(), close_button_position.y());
EXPECT_GT(center.x(), resize_button_position.x());
EXPECT_LT(center.y(), resize_button_position.y());
EXPECT_EQ(HTBOTTOMLEFT, GetOverlayWindow()->GetResizeHTComponent());
gfx::Rect top_left_bounds(0, 0, bottom_right_bounds.width(),
bottom_right_bounds.height());
GetOverlayWindow()->SetBounds(top_left_bounds);
close_button_position =
GetOverlayWindow()->close_image_position_for_testing();
resize_button_position =
GetOverlayWindow()->resize_handle_position_for_testing();
EXPECT_LT(center.x(), close_button_position.x());
EXPECT_GT(center.y(), close_button_position.y());
EXPECT_LT(center.x(), resize_button_position.x());
EXPECT_LT(center.y(), resize_button_position.y());
EXPECT_EQ(HTBOTTOMRIGHT, GetOverlayWindow()->GetResizeHTComponent());
}
#endif
IN_PROC_BROWSER_TEST_F(VideoPictureInPictureWindowControllerBrowserTest,
PlayPauseButtonVisibility) { … }
IN_PROC_BROWSER_TEST_F(VideoPictureInPictureWindowControllerBrowserTest,
PageVisibilityEventsFired) { … }
IN_PROC_BROWSER_TEST_F(VideoPictureInPictureWindowControllerBrowserTest,
PageVisibilityEventsFiredWhenPictureInPicture) { … }
class PictureInPictureWindowControllerPrerenderBrowserTest
: public VideoPictureInPictureWindowControllerBrowserTest { … };
#if BUILDFLAG(IS_LINUX) && defined(MEMORY_SANITIZER)
#define MAYBE_EnterPipThenNavigateAwayCloseWindow …
#else
#define MAYBE_EnterPipThenNavigateAwayCloseWindow …
#endif
IN_PROC_BROWSER_TEST_F(PictureInPictureWindowControllerPrerenderBrowserTest,
MAYBE_EnterPipThenNavigateAwayCloseWindow) { … }
class PictureInPictureWindowControllerFencedFrameBrowserTest
: public VideoPictureInPictureWindowControllerBrowserTest { … };
IN_PROC_BROWSER_TEST_F(PictureInPictureWindowControllerFencedFrameBrowserTest,
FencedFrameShouldNotCloseWindow) { … }
class MediaSessionVideoPictureInPictureWindowControllerBrowserTest
: public VideoPictureInPictureWindowControllerBrowserTest { … };
IN_PROC_BROWSER_TEST_F(
MediaSessionVideoPictureInPictureWindowControllerBrowserTest,
SkipAdButtonVisibility) { … }
IN_PROC_BROWSER_TEST_F(
MediaSessionVideoPictureInPictureWindowControllerBrowserTest,
PlayPauseButtonVisibility) { … }
IN_PROC_BROWSER_TEST_F(
MediaSessionVideoPictureInPictureWindowControllerBrowserTest,
NextTrackButtonVisibility) { … }
IN_PROC_BROWSER_TEST_F(
MediaSessionVideoPictureInPictureWindowControllerBrowserTest,
PreviousTrackButtonVisibility) { … }
IN_PROC_BROWSER_TEST_F(
MediaSessionVideoPictureInPictureWindowControllerBrowserTest,
NextSlideButtonVisibility) { … }
IN_PROC_BROWSER_TEST_F(
MediaSessionVideoPictureInPictureWindowControllerBrowserTest,
PreviousSlideButtonVisibility) { … }
IN_PROC_BROWSER_TEST_F(
MediaSessionVideoPictureInPictureWindowControllerBrowserTest,
SkipAdHandlerCalled) { … }
IN_PROC_BROWSER_TEST_F(
MediaSessionVideoPictureInPictureWindowControllerBrowserTest,
DISABLED_PlayPauseHandlersCalled) { … }
IN_PROC_BROWSER_TEST_F(
MediaSessionVideoPictureInPictureWindowControllerBrowserTest,
NextTrackHandlerCalled) { … }
IN_PROC_BROWSER_TEST_F(
MediaSessionVideoPictureInPictureWindowControllerBrowserTest,
PreviousTrackHandlerCalled) { … }
IN_PROC_BROWSER_TEST_F(
MediaSessionVideoPictureInPictureWindowControllerBrowserTest,
NextSlideHandlerCalled) { … }
IN_PROC_BROWSER_TEST_F(
MediaSessionVideoPictureInPictureWindowControllerBrowserTest,
PreviousSlideHandlerCalled) { … }
IN_PROC_BROWSER_TEST_F(
MediaSessionVideoPictureInPictureWindowControllerBrowserTest,
StopMediaSessionClosesPictureInPictureWindow) { … }
IN_PROC_BROWSER_TEST_F(VideoPictureInPictureWindowControllerBrowserTest,
VideoWithNoAudioPausedWhenHiddenResumesPlayback) { … }
IN_PROC_BROWSER_TEST_F(VideoPictureInPictureWindowControllerBrowserTest,
ExitFireEventAndCallbackWhenNoSource) { … }
IN_PROC_BROWSER_TEST_F(VideoPictureInPictureWindowControllerBrowserTest,
SpaceKeyTogglePlayPause) { … }
IN_PROC_BROWSER_TEST_F(VideoPictureInPictureWindowControllerBrowserTest,
VideoConferencingActions) { … }