Commit 28e9c18c authored by François Beaufort's avatar François Beaufort Committed by Commit Bot

Add replay button to Picture-in-Picture window when video ends

This CL makes sure there's a new replay button visible in the PiP window
when video ends. This icon comes from Material Icons library at
https://material.io/tools/icons/?icon=replay.

https://i.imgur.com/I1n90tM.png

Bug: 911620

Change-Id: Ibfcb96b9c69228ad74afe96ec00eb0e28d335ad8
Reviewed-on: https://chromium-review.googlesource.com/c/1360852
Commit-Queue: François Beaufort <beaufort.francois@gmail.com>
Reviewed-by: default avatarMounir Lamouri <mlamouri@chromium.org>
Reviewed-by: default avatarEvan Stade <estade@chromium.org>
Cr-Commit-Position: refs/heads/master@{#615846}
parent 3b571837
......@@ -5597,6 +5597,9 @@ the Bookmarks menu.">
<message name="IDS_PICTURE_IN_PICTURE_PLAY_CONTROL_TEXT" desc="Text label of the play control button. The button appears when the user hovers over the Picture-in-Picture window and the video is currently paused.">
Play
</message>
<message name="IDS_PICTURE_IN_PICTURE_REPLAY_CONTROL_TEXT" desc="Text label of the replay control button. The button appears when the user hovers over the Picture-in-Picture window and the video is ended.">
Play from the beginning
</message>
<message name="IDS_PICTURE_IN_PICTURE_CLOSE_CONTROL_TEXT" desc="Text label of the close control button. The button appears when the user hovers over the Picture-in-Picture window.">
Close
</message>
......
......@@ -1349,8 +1349,8 @@ IN_PROC_BROWSER_TEST_F(PictureInPictureWindowControllerBrowserTest,
OverlayWindowViews* overlay_window = static_cast<OverlayWindowViews*>(
window_controller()->GetWindowForTesting());
EXPECT_TRUE(overlay_window->play_pause_controls_view_for_testing()
->toggled_for_testing());
EXPECT_EQ(overlay_window->playback_state_for_testing(),
OverlayWindowViews::PlaybackState::kPlaying);
ASSERT_TRUE(
content::ExecuteScript(active_web_contents, "exitPictureInPicture();"));
......@@ -1376,8 +1376,8 @@ IN_PROC_BROWSER_TEST_F(PictureInPictureWindowControllerBrowserTest,
OverlayWindowViews* overlay_window = static_cast<OverlayWindowViews*>(
window_controller()->GetWindowForTesting());
EXPECT_FALSE(overlay_window->play_pause_controls_view_for_testing()
->toggled_for_testing());
EXPECT_EQ(overlay_window->playback_state_for_testing(),
OverlayWindowViews::PlaybackState::kPaused);
}
}
......
......@@ -2613,6 +2613,8 @@ jumbo_split_static_library("ui") {
"views/overlay/control_image_button.h",
"views/overlay/overlay_window_views.cc",
"views/overlay/overlay_window_views.h",
"views/overlay/playback_image_button.cc",
"views/overlay/playback_image_button.h",
"views/overlay/resize_handle_button.cc",
"views/overlay/resize_handle_button.h",
"views/page_action/page_action_icon_container_view.cc",
......
......@@ -14,6 +14,7 @@
#include "chrome/app/vector_icons/vector_icons.h"
#include "chrome/browser/ui/views/overlay/close_image_button.h"
#include "chrome/browser/ui/views/overlay/control_image_button.h"
#include "chrome/browser/ui/views/overlay/playback_image_button.h"
#include "chrome/browser/ui/views/overlay/resize_handle_button.h"
#include "chrome/grit/generated_resources.h"
#include "components/vector_icons/vector_icons.h"
......@@ -186,7 +187,7 @@ OverlayWindowViews::OverlayWindowViews(
#if defined(OS_CHROMEOS)
resize_handle_view_(new views::ResizeHandleButton(this)),
#endif
play_pause_controls_view_(new views::ToggleImageButton(this)),
play_pause_controls_view_(new views::PlaybackImageButton(this)),
hide_controls_timer_(
FROM_HERE,
base::TimeDelta::FromMilliseconds(2500 /* 2.5 seconds */),
......@@ -335,10 +336,9 @@ void OverlayWindowViews::SetUpViews() {
video_view_->SetPaintToLayer(ui::LAYER_TEXTURED);
video_view_->layer()->set_name("VideoView");
// views::View that toggles play/pause. -------------------------------------
play_pause_controls_view_->SetImageAlignment(
views::ImageButton::ALIGN_CENTER, views::ImageButton::ALIGN_MIDDLE);
play_pause_controls_view_->SetToggled(controller_->IsPlayerActive());
// views::View that toggles play/pause/replay. ------------------------------
play_pause_controls_view_->SetPlaybackState(
controller_->IsPlayerActive() ? kPlaying : kPaused);
play_pause_controls_view_->set_owned_by_client();
#if defined(OS_CHROMEOS)
......@@ -349,21 +349,6 @@ void OverlayWindowViews::SetUpViews() {
resize_handle_view_->set_owned_by_client();
#endif
// Accessibility.
play_pause_controls_view_->SetFocusForPlatform(); // Make button focusable.
const base::string16 play_pause_accessible_button_label(
l10n_util::GetStringUTF16(
IDS_PICTURE_IN_PICTURE_PLAY_PAUSE_CONTROL_ACCESSIBLE_TEXT));
play_pause_controls_view_->SetAccessibleName(
play_pause_accessible_button_label);
const base::string16 play_button_label(
l10n_util::GetStringUTF16(IDS_PICTURE_IN_PICTURE_PLAY_CONTROL_TEXT));
play_pause_controls_view_->SetTooltipText(play_button_label);
const base::string16 pause_button_label(
l10n_util::GetStringUTF16(IDS_PICTURE_IN_PICTURE_PAUSE_CONTROL_TEXT));
play_pause_controls_view_->SetToggledTooltipText(pause_button_label);
play_pause_controls_view_->SetInstallFocusRingOnFocus(true);
// Set up view::Views heirarchy. --------------------------------------------
controls_parent_view_->AddChildView(play_pause_controls_view_.get());
GetContentsView()->AddChildView(controls_scrim_view_.get());
......@@ -408,16 +393,13 @@ void OverlayWindowViews::UpdateControlsVisibility(bool is_visible) {
if (always_hide_play_pause_button_ && is_visible)
play_pause_controls_view_->SetVisible(false);
GetControlsScrimLayer()->SetVisible(is_visible);
GetControlsParentLayer()->SetVisible(is_visible);
GetCloseControlsLayer()->SetVisible(is_visible);
#if defined(OS_CHROMEOS)
GetResizeHandleLayer()->SetVisible(is_visible);
#endif
GetControlsScrimLayer()->SetVisible(
(playback_state_ == kEndOfVideo) ? false : is_visible);
GetControlsParentLayer()->SetVisible(
(playback_state_ == kEndOfVideo) ? false : is_visible);
}
void OverlayWindowViews::UpdateControlsBounds() {
......@@ -481,19 +463,7 @@ void OverlayWindowViews::UpdateCustomControlsSize(
void OverlayWindowViews::UpdatePlayPauseControlsSize() {
UpdateButtonSize();
play_pause_controls_view_->SetSize(button_size_);
play_pause_controls_view_->SetImage(
views::Button::STATE_NORMAL,
gfx::CreateVectorIcon(vector_icons::kPlayArrowIcon,
button_size_.width() / 2, kControlIconColor));
gfx::ImageSkia pause_icon = gfx::CreateVectorIcon(
vector_icons::kPauseIcon, button_size_.width() / 2, kControlIconColor);
play_pause_controls_view_->SetToggledImage(views::Button::STATE_NORMAL,
&pause_icon);
const gfx::ImageSkia play_pause_background = gfx::CreateVectorIcon(
kPictureInPictureControlBackgroundIcon, button_size_.width(), kBgColor);
play_pause_controls_view_->SetBackgroundImage(
kBgColor, &play_pause_background, &play_pause_background);
play_pause_controls_view_->SetButtonSize(button_size_);
}
void OverlayWindowViews::CreateCustomControl(
......@@ -625,28 +595,8 @@ void OverlayWindowViews::UpdateVideoSize(const gfx::Size& natural_size) {
}
void OverlayWindowViews::SetPlaybackState(PlaybackState playback_state) {
// TODO(apacible): have machine state for controls visibility.
bool controls_parent_layer_visible = GetControlsParentLayer()->visible();
playback_state_ = playback_state;
switch (playback_state_) {
case kPlaying:
play_pause_controls_view_->SetToggled(true);
controls_parent_view_->SetVisible(true);
GetControlsParentLayer()->SetVisible(controls_parent_layer_visible);
break;
case kPaused:
play_pause_controls_view_->SetToggled(false);
controls_parent_view_->SetVisible(true);
GetControlsParentLayer()->SetVisible(controls_parent_layer_visible);
break;
case kEndOfVideo:
controls_scrim_view_->SetVisible(false);
controls_parent_view_->SetVisible(false);
GetControlsParentLayer()->SetVisible(false);
break;
}
playback_state_for_testing_ = playback_state;
play_pause_controls_view_->SetPlaybackState(playback_state);
}
void OverlayWindowViews::SetAlwaysHidePlayPauseButton(bool is_visible) {
......@@ -903,10 +853,10 @@ void OverlayWindowViews::TogglePlayPause() {
// TogglePlayPause() since the IPC message may not have been propogated
// the media player yet.
bool is_active = controller_->TogglePlayPause();
play_pause_controls_view_->SetToggled(is_active);
play_pause_controls_view_->SetPlaybackState(is_active ? kPlaying : kPaused);
}
views::ToggleImageButton*
views::PlaybackImageButton*
OverlayWindowViews::play_pause_controls_view_for_testing() const {
return play_pause_controls_view_.get();
}
......@@ -925,5 +875,5 @@ views::View* OverlayWindowViews::controls_parent_view_for_testing() const {
OverlayWindowViews::PlaybackState
OverlayWindowViews::playback_state_for_testing() const {
return playback_state_;
return playback_state_for_testing_;
}
......@@ -18,8 +18,8 @@
namespace views {
class ControlImageButton;
class CloseImageButton;
class PlaybackImageButton;
class ResizeHandleButton;
class ToggleImageButton;
} // namespace views
// The Chrome desktop implementation of OverlayWindow. This will only be
......@@ -82,7 +82,7 @@ class OverlayWindowViews : public content::OverlayWindow,
// visible.
bool AreControlsVisible() const;
views::ToggleImageButton* play_pause_controls_view_for_testing() const;
views::PlaybackImageButton* play_pause_controls_view_for_testing() const;
gfx::Point close_image_position_for_testing() const;
gfx::Point resize_handle_position_for_testing() const;
views::View* controls_parent_view_for_testing() const;
......@@ -161,10 +161,6 @@ class OverlayWindowViews : public content::OverlayWindow,
// case for media streams video that user is not allowed to play/pause.
bool always_hide_play_pause_button_ = false;
// Current playback state on the video in Picture-in-Picture window. It is
// used to show/hide controls.
PlaybackState playback_state_ = kEndOfVideo;
// 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
......@@ -194,7 +190,7 @@ class OverlayWindowViews : public content::OverlayWindow,
std::unique_ptr<views::View> controls_parent_view_;
std::unique_ptr<views::CloseImageButton> close_controls_view_;
std::unique_ptr<views::ResizeHandleButton> resize_handle_view_;
std::unique_ptr<views::ToggleImageButton> play_pause_controls_view_;
std::unique_ptr<views::PlaybackImageButton> play_pause_controls_view_;
std::unique_ptr<views::ControlImageButton> first_custom_controls_view_;
std::unique_ptr<views::ControlImageButton> second_custom_controls_view_;
#if defined(OS_CHROMEOS)
......@@ -204,6 +200,10 @@ class OverlayWindowViews : public content::OverlayWindow,
// Automatically hides the controls a few seconds after user tap gesture.
base::RetainingOneShotTimer hide_controls_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;
DISALLOW_COPY_AND_ASSIGN(OverlayWindowViews);
};
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/views/overlay/playback_image_button.h"
#include "chrome/app/vector_icons/vector_icons.h"
#include "chrome/grit/generated_resources.h"
#include "components/vector_icons/vector_icons.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/paint_vector_icon.h"
#include "ui/views/vector_icons.h"
namespace {
SkColor kBackgroundColor = SK_ColorWHITE;
SkColor kPlaybackIconColor = SK_ColorBLACK;
} // namespace
namespace views {
PlaybackImageButton::PlaybackImageButton(ButtonListener* listener)
: ImageButton(listener) {
SetImageAlignment(views::ImageButton::ALIGN_CENTER,
views::ImageButton::ALIGN_MIDDLE);
SetFocusForPlatform();
const base::string16 playback_accessible_button_label(
l10n_util::GetStringUTF16(
IDS_PICTURE_IN_PICTURE_PLAY_PAUSE_CONTROL_ACCESSIBLE_TEXT));
SetAccessibleName(playback_accessible_button_label);
SetInstallFocusRingOnFocus(true);
}
PlaybackImageButton::~PlaybackImageButton() = default;
void PlaybackImageButton::SetButtonSize(const gfx::Size& size) {
SetSize(size);
play_image_ = gfx::CreateVectorIcon(vector_icons::kPlayArrowIcon,
size.width() / 2, kPlaybackIconColor);
pause_image_ = gfx::CreateVectorIcon(vector_icons::kPauseIcon,
size.width() / 2, kPlaybackIconColor);
replay_image_ = gfx::CreateVectorIcon(vector_icons::kReplayIcon,
size.width() / 2, kPlaybackIconColor);
const gfx::ImageSkia background_image_ = gfx::CreateVectorIcon(
kPictureInPictureControlBackgroundIcon, size.width(), kBackgroundColor);
SetBackgroundImage(kBackgroundColor, &background_image_, &background_image_);
UpdateImageAndTooltipText();
}
void PlaybackImageButton::SetPlaybackState(
const OverlayWindowViews::PlaybackState playback_state) {
if (playback_state_ == playback_state)
return;
playback_state_ = playback_state;
UpdateImageAndTooltipText();
}
void PlaybackImageButton::UpdateImageAndTooltipText() {
switch (playback_state_) {
case OverlayWindowViews::kPlaying:
SetImage(views::Button::STATE_NORMAL, pause_image_);
SetTooltipText(
l10n_util::GetStringUTF16(IDS_PICTURE_IN_PICTURE_PAUSE_CONTROL_TEXT));
break;
case OverlayWindowViews::kPaused:
SetImage(views::Button::STATE_NORMAL, play_image_);
SetTooltipText(
l10n_util::GetStringUTF16(IDS_PICTURE_IN_PICTURE_PLAY_CONTROL_TEXT));
break;
case OverlayWindowViews::kEndOfVideo:
SetImage(views::Button::STATE_NORMAL, replay_image_);
SetTooltipText(l10n_util::GetStringUTF16(
IDS_PICTURE_IN_PICTURE_REPLAY_CONTROL_TEXT));
break;
}
}
} // namespace views
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_UI_VIEWS_OVERLAY_PLAYBACK_IMAGE_BUTTON_H_
#define CHROME_BROWSER_UI_VIEWS_OVERLAY_PLAYBACK_IMAGE_BUTTON_H_
#include "chrome/browser/ui/views/overlay/overlay_window_views.h"
#include "ui/views/controls/button/image_button.h"
namespace views {
// A resizable playback button with 3 states: play/pause/replay.
class PlaybackImageButton : public views::ImageButton {
public:
explicit PlaybackImageButton(ButtonListener* listener);
~PlaybackImageButton() override;
// Set button size and make sure images are sized accordindly.
void SetButtonSize(const gfx::Size& size);
// Show appropriate images based on playback state.
void SetPlaybackState(const OverlayWindowViews::PlaybackState playback_state);
private:
void UpdateImageAndTooltipText();
OverlayWindowViews::PlaybackState playback_state_;
gfx::ImageSkia play_image_;
gfx::ImageSkia pause_image_;
gfx::ImageSkia replay_image_;
DISALLOW_COPY_AND_ASSIGN(PlaybackImageButton);
};
} // namespace views
#endif // CHROME_BROWSER_UI_VIEWS_OVERLAY_PLAYBACK_IMAGE_BUTTON_H_
......@@ -43,6 +43,7 @@ aggregate_vector_icons("components_vector_icons") {
"play_arrow.icon",
"protocol_handler.icon",
"reload.icon",
"replay.icon",
"screen_share.icon",
"search.icon",
"usb.icon",
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
CANVAS_DIMENSIONS, 24,
MOVE_TO, 12, 5,
V_LINE_TO, 1,
LINE_TO, 7, 6,
R_LINE_TO, 5, 5,
V_LINE_TO, 7,
R_CUBIC_TO, 3.31f, 0, 6, 2.69f, 6, 6,
R_CUBIC_TO, 0, 3.31f, -2.69f, 6, -6, 6,
R_CUBIC_TO, -3.31f, 0, -6, -2.69f, -6, -6,
H_LINE_TO, 4,
R_CUBIC_TO, 0, 4.42f, 3.58f, 8, 8, 8,
R_CUBIC_TO, 4.42f, 0, 8, -3.58f, 8, -8,
R_CUBIC_TO, 0, -4.42f, -3.58f, -8, -8, -8,
CLOSE
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