blob: c1d16612a9617cb242c45a9409f2a2e0c7f45e69 [file] [log] [blame]
// Copyright 2017 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_OVERLAY_OVERLAY_WINDOW_VIEWS_H_
#define CHROME_BROWSER_UI_VIEWS_OVERLAY_OVERLAY_WINDOW_VIEWS_H_
#include "base/memory/raw_ptr.h"
#include "base/timer/timer.h"
#include "build/chromeos_buildflags.h"
#include "content/public/browser/overlay_window.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "ui/gfx/geometry/size.h"
#include "ui/views/widget/widget.h"
namespace viz {
class FrameSinkId;
} // namespace viz
class BackToTabImageButton;
class BackToTabLabelButton;
class CloseImageButton;
class HangUpButton;
class PlaybackImageButton;
class ResizeHandleButton;
class SkipAdLabelButton;
class ToggleMicrophoneButton;
class ToggleCameraButton;
class TrackImageButton;
// The Chrome desktop implementation of OverlayWindow. This will only be
// implemented in views, which will support all desktop platforms.
class OverlayWindowViews : public content::OverlayWindow,
public views::Widget {
public:
static std::unique_ptr<OverlayWindowViews> Create(
content::PictureInPictureWindowController* controller);
OverlayWindowViews(const OverlayWindowViews&) = delete;
OverlayWindowViews& operator=(const OverlayWindowViews&) = delete;
~OverlayWindowViews() override;
enum class WindowQuadrant { kBottomLeft, kBottomRight, kTopLeft, kTopRight };
// OverlayWindow:
bool IsActive() override;
void Close() override;
void ShowInactive() override;
void Hide() override;
bool IsVisible() override;
bool IsAlwaysOnTop() override;
gfx::Rect GetBounds() override;
void UpdateVideoSize(const gfx::Size& natural_size) override;
void SetPlaybackState(PlaybackState playback_state) override;
void SetPlayPauseButtonVisibility(bool is_visible) override;
void SetSkipAdButtonVisibility(bool is_visible) override;
void SetNextTrackButtonVisibility(bool is_visible) override;
void SetPreviousTrackButtonVisibility(bool is_visible) override;
void SetMicrophoneMuted(bool muted) override;
void SetCameraState(bool turned_on) override;
void SetToggleMicrophoneButtonVisibility(bool is_visible) override;
void SetToggleCameraButtonVisibility(bool is_visible) override;
void SetHangUpButtonVisibility(bool is_visible) override;
void SetSurfaceId(const viz::SurfaceId& surface_id) override;
// views::Widget:
bool IsActive() const override;
bool IsVisible() const override;
void OnNativeFocus() override;
void OnNativeBlur() override;
void OnNativeWidgetDestroying() override;
void OnNativeWidgetDestroyed() override;
gfx::Size GetMinimumSize() const override;
gfx::Size GetMaximumSize() const override;
void OnNativeWidgetMove() override;
void OnNativeWidgetSizeChanged(const gfx::Size& new_size) override;
void OnNativeWidgetWorkspaceChanged() override;
void OnNativeWidgetAddedToCompositor() override;
void OnNativeWidgetRemovingFromCompositor() override;
void OnKeyEvent(ui::KeyEvent* event) override;
void OnMouseEvent(ui::MouseEvent* event) override;
void OnGestureEvent(ui::GestureEvent* event) override;
// Gets the bounds of the controls.
gfx::Rect GetBackToTabControlsBounds();
gfx::Rect GetSkipAdControlsBounds();
gfx::Rect GetCloseControlsBounds();
gfx::Rect GetResizeHandleControlsBounds();
gfx::Rect GetPlayPauseControlsBounds();
gfx::Rect GetNextTrackControlsBounds();
gfx::Rect GetPreviousTrackControlsBounds();
gfx::Rect GetToggleMicrophoneButtonBounds();
gfx::Rect GetToggleCameraButtonBounds();
gfx::Rect GetHangUpButtonBounds();
// Gets the proper hit test component when the hit point is on the resize
// handle in order to force a drag-to-resize.
int GetResizeHTComponent() const;
// Returns true if the controls (e.g. close button, play/pause button) are
// visible.
bool AreControlsVisible() const;
void ForceControlsVisibleForTesting(bool visible);
// Determines whether a layout of the window controls has been scheduled but
// is not done yet.
bool IsLayoutPendingForTesting() const;
PlaybackImageButton* play_pause_controls_view_for_testing() const;
TrackImageButton* next_track_controls_view_for_testing() const;
TrackImageButton* previous_track_controls_view_for_testing() const;
SkipAdLabelButton* skip_ad_controls_view_for_testing() const;
ToggleMicrophoneButton* toggle_microphone_button_for_testing() const;
ToggleCameraButton* toggle_camera_button_for_testing() const;
HangUpButton* hang_up_button_for_testing() const;
BackToTabLabelButton* back_to_tab_label_button_for_testing() const;
CloseImageButton* close_button_for_testing() const;
gfx::Point close_image_position_for_testing() const;
gfx::Point resize_handle_position_for_testing() const;
OverlayWindowViews::PlaybackState playback_state_for_testing() const;
ui::Layer* video_layer_for_testing() const;
cc::Layer* GetLayerForTesting() override;
void set_minimum_size_for_testing(const gfx::Size& min_size) {
min_size_ = min_size;
}
private:
explicit OverlayWindowViews(
content::PictureInPictureWindowController* controller);
// Return the work area for the nearest display the widget is on.
gfx::Rect GetWorkAreaForWindow() const;
// Determine the intended bounds of |this|. This should be called when there
// is reason for the bounds to change, such as switching primary displays or
// playing a new video (i.e. different aspect ratio).
gfx::Rect CalculateAndUpdateWindowBounds();
// Set up the views::Views that will be shown on the window.
void SetUpViews();
// Finish initialization by performing the steps that require the root View.
void OnRootViewReady();
// Update the max size of the widget based on |work_area| and window size.
void UpdateMaxSize(const gfx::Rect& work_area);
// Update the bounds of the layers on the window. This may introduce
// letterboxing.
void UpdateLayerBoundsWithLetterboxing(gfx::Size window_size);
// Updates the controls view::Views to reflect |is_visible|.
void UpdateControlsVisibility(bool is_visible);
// Updates the bounds of the controls.
void UpdateControlsBounds();
// Called when the bounds of the controls should be updated.
void OnUpdateControlsBounds();
// Update the size of each controls view as the size of the window changes.
void UpdateButtonControlsSize();
// Calculate and set the bounds of the controls.
gfx::Rect CalculateControlsBounds(int x, const gfx::Size& size);
void UpdateControlsPositions();
#if BUILDFLAG(IS_CHROMEOS_ASH)
// Updates the bounds of |resize_handle_view_| based on what |quadrant| the
// PIP window is in.
void UpdateResizeHandleBounds(WindowQuadrant quadrant);
#endif
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
enum class OverlayWindowControl {
kBackToTab = 0,
kMuteDeprecated,
kSkipAd,
kClose,
kPlayPause,
kNextTrack,
kPreviousTrack,
kToggleMicrophone,
kToggleCamera,
kHangUp,
kMaxValue = kHangUp
};
void RecordButtonPressed(OverlayWindowControl);
void RecordTapGesture(OverlayWindowControl);
// Toggles the play/pause control through the |controller_| and updates the
// |play_pause_controls_view_| toggled state to reflect the current playing
// state.
void TogglePlayPause();
// Returns the current frame sink id for the surface displayed in the
// |video_view_|. If |video_view_| is not currently displaying a surface then
// returns nullptr.
const viz::FrameSinkId* GetCurrentFrameSinkId() const;
// Unregisters the current frame sink id for the surface displayed in the
// |video_view_| from its parent frame sink if the frame sink hierarchy has
// been registered before.
void MaybeUnregisterFrameSinkHierarchy();
// Not owned; |controller_| owns |this|.
raw_ptr<content::PictureInPictureWindowController> controller_;
// Whether or not the window has been shown before. This is used to determine
// sizing and placement. This is different from checking whether the window
// components has been initialized.
bool has_been_shown_ = false;
// Whether or not the play/pause button will be shown.
bool show_play_pause_button_ = false;
// The upper and lower bounds of |current_size_|. These are determined by the
// size of the primary display work area when Picture-in-Picture is initiated.
// TODO(apacible): Update these bounds when the display the window is on
// changes. http://crbug.com/819673
gfx::Size min_size_;
gfx::Size max_size_;
// The natural size of the video to show. This is used to compute sizing and
// ensuring factors such as aspect ratio is maintained.
gfx::Size natural_size_;
// Temporary storage for child Views. Used during the time between
// construction and initialization, when the views::View pointer members must
// already be initialized, but there is no root view to add them to yet.
std::vector<std::unique_ptr<views::View>> view_holder_;
// Views to be shown.
raw_ptr<views::View> window_background_view_ = nullptr;
raw_ptr<views::View> video_view_ = nullptr;
raw_ptr<views::View> controls_scrim_view_ = nullptr;
raw_ptr<views::View> controls_container_view_ = nullptr;
raw_ptr<CloseImageButton> close_controls_view_ = nullptr;
raw_ptr<BackToTabImageButton> back_to_tab_image_button_ = nullptr;
raw_ptr<BackToTabLabelButton> back_to_tab_label_button_ = nullptr;
raw_ptr<TrackImageButton> previous_track_controls_view_ = nullptr;
raw_ptr<PlaybackImageButton> play_pause_controls_view_ = nullptr;
raw_ptr<TrackImageButton> next_track_controls_view_ = nullptr;
raw_ptr<SkipAdLabelButton> skip_ad_controls_view_ = nullptr;
raw_ptr<ResizeHandleButton> resize_handle_view_ = nullptr;
raw_ptr<ToggleMicrophoneButton> toggle_microphone_button_ = nullptr;
raw_ptr<ToggleCameraButton> toggle_camera_button_ = nullptr;
raw_ptr<HangUpButton> hang_up_button_ = nullptr;
// Automatically hides the controls a few seconds after user tap gesture.
base::RetainingOneShotTimer hide_controls_timer_;
// Timer used to update controls bounds.
std::unique_ptr<base::OneShotTimer> update_controls_bounds_timer_;
// Current playback state on the video in Picture-in-Picture window. It is
// used to toggle play/pause/replay button.
PlaybackState playback_state_for_testing_ = kEndOfVideo;
// Whether or not the skip ad button will be shown. This is the
// case when Media Session "skipad" action is handled by the website.
bool show_skip_ad_button_ = false;
// Whether or not the next track button will be shown. This is the
// case when Media Session "nexttrack" action is handled by the website.
bool show_next_track_button_ = false;
// Whether or not the previous track button will be shown. This is the
// case when Media Session "previoustrack" action is handled by the website.
bool show_previous_track_button_ = false;
// Whether or not the toggle microphone button will be shown. This is the case
// when Media Session "togglemicrophone" action is handled by the website.
bool show_toggle_microphone_button_ = false;
// Whether or not the toggle camera button will be shown. This is the case
// when Media Session "togglecamera" action is handled by the website.
bool show_toggle_camera_button_ = false;
// Whether or not the hang up button will be shown. This is the case when
// Media Session "hangup" action is handled by the website.
bool show_hang_up_button_ = false;
// If set, controls will always either be shown or hidden, instead of showing
// and hiding automatically. Only used for testing via
// ForceControlsVisibleForTesting().
absl::optional<bool> force_controls_visible_;
// Whether or not the current frame sink for the surface displayed in the
// |video_view_| is registered as the child of the overlay window frame sink.
bool has_registered_frame_sink_hierarchy_ = false;
};
#endif // CHROME_BROWSER_UI_VIEWS_OVERLAY_OVERLAY_WINDOW_VIEWS_H_