Skip to content

Commit

Permalink
gd: Add animation for hiding/showing the game dashboard button
Browse files Browse the repository at this point in the history
When a game window enters fullscreen, the game dashboard button slides
up, and its widget is hidden. When exiting fullscreen or when a user
presses the accelerator, the game dashboard buttton's widget is made
visible, and the button slides down.

Bug: b:286907307
Demo: b:286907307#comment6
Test: Ran ash unit test
Change-Id: I6f5fc6b149e1c4949ede57e06a4963198f520c10
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5332846
Commit-Queue: Prameet Shah <phshah@chromium.org>
Reviewed-by: Ahmed Fakhry <afakhry@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1274542}
  • Loading branch information
Prameet Shah authored and Chromium LUCI CQ committed Mar 18, 2024
1 parent 82a4c33 commit d158c6d
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 6 deletions.
45 changes: 43 additions & 2 deletions ash/game_dashboard/game_dashboard_button_reveal_controller.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@
#include "ash/game_dashboard/game_dashboard_context.h"
#include "ash/game_dashboard/game_dashboard_utils.h"
#include "ash/wm/window_state.h"
#include "base/functional/bind.h"
#include "base/functional/callback_forward.h"
#include "chromeos/ui/frame/immersive/immersive_fullscreen_controller.h"
#include "ui/aura/window.h"
#include "ui/display/screen.h"
#include "ui/gfx/geometry/point.h"
#include "ui/views/animation/animation_builder.h"
#include "ui/views/widget/widget.h"

namespace ash {
Expand All @@ -21,6 +24,9 @@ namespace {
// game dashboard button revealing.
constexpr base::TimeDelta kMouseRevealDelay = base::Milliseconds(200);

constexpr base::TimeDelta kSlideAnimationDuration = base::Milliseconds(200);
constexpr base::TimeDelta kNoSlideAnimationDuration = base::Milliseconds(0);

} // namespace

GameDashboardButtonRevealController::GameDashboardButtonRevealController(
Expand All @@ -29,12 +35,38 @@ GameDashboardButtonRevealController::GameDashboardButtonRevealController(
DCHECK(context_);
context_->game_window()->AddPreTargetHandler(
this, ui::EventTarget::Priority::kSystem);
UpdateVisibility(/*target_visibility=*/false, /*animate=*/false);
}

GameDashboardButtonRevealController::~GameDashboardButtonRevealController() {
UpdateVisibility(/*target_visibility=*/true, /*animate=*/false);
context_->game_window()->RemovePreTargetHandler(this);
}

void GameDashboardButtonRevealController::UpdateVisibility(
bool target_visibility,
bool animate) {
context_->SetGameDashboardButtonVisibility(/*visible=*/true);
views::AnimationBuilder()
.SetPreemptionStrategy(ui::LayerAnimator::PreemptionStrategy::
IMMEDIATELY_ANIMATE_TO_NEW_TARGET)
.OnEnded(
base::BindOnce(&GameDashboardButtonRevealController::OnAnimationEnd,
weak_ptr_factory_.GetWeakPtr(), target_visibility))
.Once()
.SetDuration(animate ? kSlideAnimationDuration
: kNoSlideAnimationDuration)
.SetTransform(
context_->game_dashboard_button_widget()->GetLayer(),
target_visibility
? gfx::Transform()
: gfx::Transform::MakeTranslation(
/*tx=*/0,
/*ty=*/-game_dashboard_utils::GetFrameHeaderHeight(
context_->game_window())),
gfx::Tween::EASE_OUT);
}

void GameDashboardButtonRevealController::OnMouseEvent(ui::MouseEvent* event) {
const auto event_type = event->type();
if (event_type != ui::ET_MOUSE_MOVED && event_type != ui::ET_MOUSE_RELEASED &&
Expand All @@ -59,7 +91,7 @@ void GameDashboardButtonRevealController::OnMouseEvent(ui::MouseEvent* event) {
top_edge_hover_timer_.Stop();
// If the main menu is closed, try to hide the game dashboard button.
if (CanHideGameDashboardButton(mouse_screen_location)) {
context_->SetGameDashboardButtonVisibility(/*visible=*/false);
UpdateVisibility(/*target_visibility=*/false, /*animate=*/true);
}
}

Expand Down Expand Up @@ -103,7 +135,16 @@ bool GameDashboardButtonRevealController::IsMouseOutsideHeaderBounds(
void GameDashboardButtonRevealController::OnTopEdgeHoverTimeout() {
if (CanShowGameDashboardButton(
display::Screen::GetScreen()->GetCursorScreenPoint())) {
context_->SetGameDashboardButtonVisibility(/*visible=*/true);
UpdateVisibility(/*target_visibility=*/true, /*animate=*/true);
}
}

void GameDashboardButtonRevealController::OnAnimationEnd(
bool target_visibility) {
if (!target_visibility) {
// The slide up animation has ended. Make the Game Dashboard button
// widget not visible.
context_->SetGameDashboardButtonVisibility(/*visible=*/false);
}
}

Expand Down
13 changes: 13 additions & 0 deletions ash/game_dashboard/game_dashboard_button_reveal_controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@ class GameDashboardButtonRevealController : public ui::EventHandler {

void StopTopEdgeTimer() { top_edge_hover_timer_.Stop(); }

// Updates the visibility of the Game Dashboard button widget. If
// `target_visibility` is true, then the widget will be visible, otherwise it
// will not be visible. If `animate` is true, the widget will slide up/down
// with a short animation to `target_visibility`, otherwise, the widget will
// move without any animation.
void UpdateVisibility(bool target_visibility, bool animate);

// ui::EventHandler:
void OnMouseEvent(ui::MouseEvent* event) override;

Expand Down Expand Up @@ -59,10 +66,16 @@ class GameDashboardButtonRevealController : public ui::EventHandler {
// Called when the `top_edge_hover_timer_` is fired.
void OnTopEdgeHoverTimeout();

// Callbacks when the animation has ended in `UpdateVisibility()`.
void OnAnimationEnd(bool target_visibility);

const raw_ptr<GameDashboardContext> context_;

// Timer to track cursor being held at the top edge of the screen.
base::OneShotTimer top_edge_hover_timer_;

base::WeakPtrFactory<GameDashboardButtonRevealController> weak_ptr_factory_{
this};
};

} // namespace ash
Expand Down
19 changes: 15 additions & 4 deletions ash/game_dashboard/game_dashboard_context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,14 @@ void GameDashboardContext::UpdateForGameControlsFlags() {
}

void GameDashboardContext::ToggleMainMenuByAccelerator() {
SetGameDashboardButtonVisibility(/*visible=*/true);
if (game_dashboard_button_reveal_controller_) {
// Window is in fullscreen, and `game_dashboard_button_widget_` may not be
// visible. Reset its position and make it visible. Don't animate the button
// so it and the main menu show up at the same time.
game_dashboard_button_reveal_controller_->UpdateVisibility(
/*target_visibility=*/true, /*animate=*/false);
}

ToggleMainMenu(GameDashboardMainMenuToggleMethod::kSearchPlusG);
}

Expand Down Expand Up @@ -411,7 +418,9 @@ void GameDashboardContext::OnPreWindowStateTypeChange(
chromeos::WindowStateType old_type) {
// Hide the Game Dashboard button before the window switches to fullscreen.
if (window_state->IsFullscreen()) {
SetGameDashboardButtonVisibility(/*visible=*/false);
DCHECK(!game_dashboard_button_reveal_controller_);
// The `GameDashboardButtonRevealController`'s ctor will hide
// `game_dashboard_button_widget_`.
game_dashboard_button_reveal_controller_ =
std::make_unique<GameDashboardButtonRevealController>(this);
}
Expand All @@ -420,9 +429,11 @@ void GameDashboardContext::OnPreWindowStateTypeChange(
void GameDashboardContext::OnPostWindowStateTypeChange(
WindowState* window_state,
chromeos::WindowStateType old_type) {
if (!window_state->IsFullscreen()) {
if (!window_state->IsFullscreen() &&
game_dashboard_button_reveal_controller_) {
// When exiting fullscreen, GameDashboardButtonRevealController dtor will
// make `game_dashboard_button_widget_` visible and reset its position.
game_dashboard_button_reveal_controller_.reset();
SetGameDashboardButtonVisibility(/*visible=*/true);
}
}

Expand Down
4 changes: 4 additions & 0 deletions ash/game_dashboard/game_dashboard_context_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1306,6 +1306,7 @@ TEST_F(GameDashboardContextTest, GameDashboardButtonFullscreen_MouseOver) {
auto* event_generator = GetEventGenerator();
auto app_bounds = game_window_->GetBoundsInScreen();
auto* window_state = WindowState::Get(game_window_.get());
ASSERT_TRUE(window_state->IsNormalStateType());
views::Widget* button_widget = test_api_->GetGameDashboardButtonWidget();
CHECK(button_widget);

Expand All @@ -1316,6 +1317,7 @@ TEST_F(GameDashboardContextTest, GameDashboardButtonFullscreen_MouseOver) {
ASSERT_TRUE(window_state->IsFullscreen());
ASSERT_FALSE(button_widget->IsVisible());
ASSERT_TRUE(test_api_->GetGameDashboardButtonRevealController());
ASSERT_FALSE(test_api_->GetGameDashboardButtonWidget()->IsVisible());

// Move mouse to top edge of window.
event_generator->MoveMouseTo(app_bounds.top_center());
Expand All @@ -1324,10 +1326,12 @@ TEST_F(GameDashboardContextTest, GameDashboardButtonFullscreen_MouseOver) {
ASSERT_TRUE(top_edge_hover_timer.IsRunning());
top_edge_hover_timer.FireNow();
ASSERT_TRUE(button_widget->IsVisible());
ASSERT_TRUE(test_api_->GetGameDashboardButtonWidget()->IsVisible());

// Move mouse to the center of the app, and verify Game Dashboard button
// widget is not visible.
event_generator->MoveMouseTo(app_bounds.CenterPoint());
ASSERT_FALSE(test_api_->GetGameDashboardButtonWidget()->IsVisible());
ASSERT_FALSE(button_widget->IsVisible());
}

Expand Down

0 comments on commit d158c6d

Please sign in to comment.