#include "ash/shelf/shelf_background_animator.h"
#include <memory>
#include "ash/animation/animation_change_type.h"
#include "ash/public/cpp/shelf_config.h"
#include "ash/session/test_session_controller_client.h"
#include "ash/shelf/shelf.h"
#include "ash/shelf/shelf_background_animator_observer.h"
#include "ash/shelf/shelf_widget.h"
#include "ash/shell.h"
#include "ash/test/ash_test_base.h"
#include "base/command_line.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/run_loop.h"
#include "base/test/test_mock_time_task_runner.h"
#include "ui/gfx/animation/slide_animation.h"
#include "ui/gfx/scoped_animation_duration_scale_mode.h"
namespace ash {
namespace {
const SkColor kDummyColor = SK_ColorBLUE;
class TestShelfBackgroundObserver : public ShelfBackgroundAnimatorObserver {
public:
TestShelfBackgroundObserver() = default;
TestShelfBackgroundObserver(const TestShelfBackgroundObserver&) = delete;
TestShelfBackgroundObserver& operator=(const TestShelfBackgroundObserver&) =
delete;
~TestShelfBackgroundObserver() override = default;
SkColor background_color() const { return background_color_; }
int GetBackgroundAlpha() const;
void SetAnimationCompleteCallback(base::OnceClosure callback);
void UpdateShelfBackground(SkColor color) override;
void OnShelfBackgroundAnimationEnded() override;
private:
int background_color_ = SK_ColorTRANSPARENT;
base::OnceClosure animation_complete_callback_;
};
int TestShelfBackgroundObserver::GetBackgroundAlpha() const {
return SkColorGetA(background_color_);
}
void TestShelfBackgroundObserver::UpdateShelfBackground(SkColor color) {
background_color_ = color;
}
void TestShelfBackgroundObserver::OnShelfBackgroundAnimationEnded() {
if (!animation_complete_callback_.is_null())
std::move(animation_complete_callback_).Run();
}
void TestShelfBackgroundObserver::SetAnimationCompleteCallback(
base::OnceClosure callback) {
animation_complete_callback_ = std::move(callback);
}
}
class ShelfBackgroundAnimatorTestApi {
public:
explicit ShelfBackgroundAnimatorTestApi(ShelfBackgroundAnimator* animator)
: animator_(animator) {}
ShelfBackgroundAnimatorTestApi(const ShelfBackgroundAnimatorTestApi&) =
delete;
ShelfBackgroundAnimatorTestApi& operator=(
const ShelfBackgroundAnimatorTestApi&) = delete;
~ShelfBackgroundAnimatorTestApi() = default;
ShelfBackgroundType previous_background_type() const {
return animator_->previous_background_type_;
}
gfx::SlideAnimation* animator() const { return animator_->animator_.get(); }
SkColor shelf_background_target_color() const {
return animator_->shelf_background_values_.target_color();
}
private:
raw_ptr<ShelfBackgroundAnimator, DanglingUntriaged> animator_;
};
class ShelfBackgroundAnimatorTest : public AshTestBase {
public:
ShelfBackgroundAnimatorTest() = default;
ShelfBackgroundAnimatorTest(const ShelfBackgroundAnimatorTest&) = delete;
ShelfBackgroundAnimatorTest& operator=(const ShelfBackgroundAnimatorTest&) =
delete;
~ShelfBackgroundAnimatorTest() override = default;
void SetUp() override;
protected:
void PaintBackground(
ShelfBackgroundType background_type,
AnimationChangeType change_type = AnimationChangeType::IMMEDIATE);
void SetColorValuesOnObserver(SkColor color);
void WaitForAnimationCompletion();
TestShelfBackgroundObserver observer_;
raw_ptr<ShelfBackgroundAnimator, DanglingUntriaged> animator_;
std::unique_ptr<ShelfBackgroundAnimatorTestApi> test_api_;
};
void ShelfBackgroundAnimatorTest::SetUp() {
AshTestBase::SetUp();
animator_ =
GetPrimaryShelf()->shelf_widget()->background_animator_for_testing();
animator_->AddObserver(&observer_);
test_api_ = std::make_unique<ShelfBackgroundAnimatorTestApi>(animator_);
}
void ShelfBackgroundAnimatorTest::PaintBackground(
ShelfBackgroundType background_type,
AnimationChangeType change_type) {
animator_->PaintBackground(background_type, change_type);
}
void ShelfBackgroundAnimatorTest::SetColorValuesOnObserver(SkColor color) {
observer_.UpdateShelfBackground(color);
}
void ShelfBackgroundAnimatorTest::WaitForAnimationCompletion() {
base::RunLoop run_loop;
observer_.SetAnimationCompleteCallback(run_loop.QuitWhenIdleClosure());
run_loop.Run();
}
TEST_F(ShelfBackgroundAnimatorTest, BackgroundTypesWhenAnimatingToSameTarget) {
PaintBackground(ShelfBackgroundType::kMaximized);
EXPECT_EQ(ShelfBackgroundType::kMaximized,
animator_->target_background_type());
PaintBackground(ShelfBackgroundType::kDefaultBg);
EXPECT_EQ(ShelfBackgroundType::kDefaultBg,
animator_->target_background_type());
EXPECT_EQ(ShelfBackgroundType::kMaximized,
test_api_->previous_background_type());
PaintBackground(ShelfBackgroundType::kDefaultBg);
EXPECT_EQ(ShelfBackgroundType::kDefaultBg,
animator_->target_background_type());
EXPECT_EQ(ShelfBackgroundType::kMaximized,
test_api_->previous_background_type());
}
TEST_F(ShelfBackgroundAnimatorTest,
MultipleAnimateCallsToSameTargetAreIgnored) {
PaintBackground(ShelfBackgroundType::kMaximized);
SetColorValuesOnObserver(kDummyColor);
gfx::ScopedAnimationDurationScaleMode test_duration_mode(
gfx::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
animator_->PaintBackground(ShelfBackgroundType::kDefaultBg,
AnimationChangeType::ANIMATE);
WaitForAnimationCompletion();
EXPECT_NE(observer_.background_color(), kDummyColor);
SetColorValuesOnObserver(kDummyColor);
animator_->PaintBackground(ShelfBackgroundType::kDefaultBg,
AnimationChangeType::ANIMATE);
EXPECT_EQ(observer_.background_color(), kDummyColor);
}
TEST_F(ShelfBackgroundAnimatorTest, ObserversUpdatedWhenAdded) {
animator_->RemoveObserver(&observer_);
SetColorValuesOnObserver(kDummyColor);
animator_->AddObserver(&observer_);
EXPECT_NE(observer_.background_color(), kDummyColor);
}
TEST_F(ShelfBackgroundAnimatorTest, DefaultBackground) {
PaintBackground(ShelfBackgroundType::kDefaultBg);
EXPECT_EQ(ShelfBackgroundType::kDefaultBg,
animator_->target_background_type());
EXPECT_EQ((int)SkColorGetA(ShelfConfig::Get()->GetDefaultShelfColor(
GetPrimaryShelf()->shelf_widget())),
observer_.GetBackgroundAlpha());
}
TEST_F(ShelfBackgroundAnimatorTest, MaximizedBackground) {
PaintBackground(ShelfBackgroundType::kMaximized);
EXPECT_EQ(ShelfBackgroundType::kMaximized,
animator_->target_background_type());
EXPECT_EQ((int)SkColorGetA(ShelfConfig::Get()->GetMaximizedShelfColor(
GetPrimaryShelf()->shelf_widget())),
observer_.GetBackgroundAlpha());
}
TEST_F(ShelfBackgroundAnimatorTest,
AnimatorIsDetroyedWhenCompletingSuccessfully) {
gfx::ScopedAnimationDurationScaleMode test_duration_mode(
gfx::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
PaintBackground(ShelfBackgroundType::kMaximized,
AnimationChangeType::ANIMATE);
EXPECT_TRUE(test_api_->animator());
WaitForAnimationCompletion();
EXPECT_FALSE(test_api_->animator());
}
TEST_F(ShelfBackgroundAnimatorTest,
AnimatorDestroyedWhenChangingBackgroundImmediately) {
gfx::ScopedAnimationDurationScaleMode test_duration_mode(
gfx::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
PaintBackground(ShelfBackgroundType::kMaximized,
AnimationChangeType::ANIMATE);
EXPECT_TRUE(test_api_->animator());
PaintBackground(ShelfBackgroundType::kDefaultBg,
AnimationChangeType::IMMEDIATE);
EXPECT_FALSE(test_api_->animator());
}
TEST_F(ShelfBackgroundAnimatorTest,
ExistingAnimatorIsReusedWhenAnimatingToPreviousState) {
gfx::ScopedAnimationDurationScaleMode test_duration_mode(
gfx::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
PaintBackground(ShelfBackgroundType::kDefaultBg,
AnimationChangeType::IMMEDIATE);
PaintBackground(ShelfBackgroundType::kMaximized,
AnimationChangeType::ANIMATE);
const gfx::SlideAnimation* animator = test_api_->animator();
EXPECT_TRUE(animator);
PaintBackground(ShelfBackgroundType::kDefaultBg,
AnimationChangeType::ANIMATE);
EXPECT_EQ(animator, test_api_->animator());
}
TEST_F(ShelfBackgroundAnimatorTest,
ExistingAnimatorNotReusedWhenTargetBackgroundNotPreviousBackground) {
gfx::ScopedAnimationDurationScaleMode test_duration_mode(
gfx::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
PaintBackground(ShelfBackgroundType::kHomeLauncher,
AnimationChangeType::ANIMATE);
const gfx::SlideAnimation* animator = test_api_->animator();
EXPECT_TRUE(animator);
EXPECT_NE(ShelfBackgroundType::kMaximized,
test_api_->previous_background_type());
PaintBackground(ShelfBackgroundType::kMaximized,
AnimationChangeType::ANIMATE);
EXPECT_NE(animator, test_api_->animator());
}
TEST_F(ShelfBackgroundAnimatorTest,
ObserversAreNotifiedWhenSnappingToSameTargetBackground) {
PaintBackground(ShelfBackgroundType::kDefaultBg);
SetColorValuesOnObserver(kDummyColor);
PaintBackground(ShelfBackgroundType::kDefaultBg);
EXPECT_NE(observer_.background_color(), kDummyColor);
}
class ShelfBackgroundTargetColorTest : public NoSessionAshTestBase {
public:
ShelfBackgroundTargetColorTest() = default;
ShelfBackgroundTargetColorTest(const ShelfBackgroundTargetColorTest&) =
delete;
ShelfBackgroundTargetColorTest& operator=(
const ShelfBackgroundTargetColorTest&) = delete;
~ShelfBackgroundTargetColorTest() override = default;
protected:
void NotifySessionStateChanged(session_manager::SessionState state) {
GetSessionControllerClient()->SetSessionState(state);
}
};
TEST_F(ShelfBackgroundTargetColorTest, ShelfBackgroundColorUpdatedFromLogin) {
ShelfBackgroundAnimatorTestApi test_api(
Shelf::ForWindow(Shell::Get()->GetPrimaryRootWindow())
->shelf_widget()
->background_animator_for_testing());
NotifySessionStateChanged(session_manager::SessionState::LOGIN_PRIMARY);
EXPECT_EQ(test_api.shelf_background_target_color(), SK_ColorTRANSPARENT);
SimulateUserLogin({"user1@test.com"});
NotifySessionStateChanged(session_manager::SessionState::ACTIVE);
EXPECT_EQ(test_api.shelf_background_target_color(),
ShelfConfig::Get()->GetDefaultShelfColor(
GetPrimaryShelf()->shelf_widget()));
}
TEST_F(ShelfBackgroundTargetColorTest, ShelfBackgroundColorUpdatedFromOOBE) {
ShelfBackgroundAnimatorTestApi test_api(
Shelf::ForWindow(Shell::Get()->GetPrimaryRootWindow())
->shelf_widget()
->background_animator_for_testing());
NotifySessionStateChanged(session_manager::SessionState::OOBE);
EXPECT_EQ(test_api.shelf_background_target_color(), SK_ColorTRANSPARENT);
SimulateUserLogin({"user1@test.com"});
NotifySessionStateChanged(
session_manager::SessionState::LOGGED_IN_NOT_ACTIVE);
EXPECT_EQ(test_api.shelf_background_target_color(), SK_ColorTRANSPARENT);
NotifySessionStateChanged(session_manager::SessionState::ACTIVE);
EXPECT_EQ(test_api.shelf_background_target_color(),
ShelfConfig::Get()->GetDefaultShelfColor(
GetPrimaryShelf()->shelf_widget()));
}
}