// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <memory>
#include "ash/public/cpp/style/dark_light_mode_controller.h"
#include "ash/style/system_shadow.h"
#include "ash/test/ash_test_base.h"
#include "base/test/scoped_feature_list.h"
#include "chromeos/constants/chromeos_features.h"
#include "ui/aura/window.h"
#include "ui/chromeos/styles/cros_tokens_color_mappings.h"
#include "ui/color/color_id.h"
#include "ui/color/color_provider.h"
#include "ui/compositor/layer.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
namespace ash {
namespace {
// Different types of SystemShadow extensions.
enum class SystemShadowType {
kShadowOnNinePatchLayer, // Instance of `SystemShadowOnNinePatchLayer`.
kViewShadowOnNinePatchLayer, // Instance of
// `SystemViewShadowOnNinePatchLayer`.
kWindowShadowOnNinePatchLayer, // Instance of
// `SystemWindowShadowOnNinePatchLayer`.
kShadowOnTextureLayer, // Instance of `SystemShadowOnTextureLayer`.
};
// Gets the key and ambient shadow colors from a shadow.
std::pair<SkColor, SkColor> GetShadowColors(SystemShadow* shadow) {
gfx::ShadowValues values = shadow->GetShadowValuesForTesting();
return std::make_pair(values[0].color(), values[1].color());
}
// Add a shadow to the bottom of the native window of a widget and make the
// shadow observe the theme change of the widget.
void AddShadowToWidget(SystemShadow* shadow, views::Widget* widget) {
auto* window_layer = widget->GetNativeWindow()->layer();
auto* shadow_layer = shadow->GetLayer();
window_layer->Add(shadow_layer);
window_layer->StackAtBottom(shadow_layer);
shadow->SetContentBounds(gfx::Rect(window_layer->bounds().size()));
shadow->ObserveColorProviderSource(widget);
}
} // namespace
// The parameterized test class for dynamic system shadow colors.
class SystemShadowColorTest
: public AshTestBase,
public testing::WithParamInterface<SystemShadowType> {
public:
SystemShadowColorTest() = default;
SystemShadowColorTest(const SystemShadowColorTest&) = delete;
SystemShadowColorTest& operator=(const SystemShadowColorTest&) = delete;
~SystemShadowColorTest() override = default;
// AshTestBase:
void SetUp() override {
AshTestBase::SetUp();
// Enable Jelly and Jellyroll features.
scoped_feature_list_.InitWithFeatures(
{chromeos::features::kJelly, chromeos::features::kJellyroll}, {});
// Create a test widget as the owner of the shadow instances.
widget_ = CreateTestWidget(
views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET,
/*delegate=*/nullptr,
/*container_id=*/desks_util::GetActiveDeskContainerId(),
/*bounds=*/gfx::Rect(100, 100, 320, 200));
}
protected:
// Gets the dynamic color resolved by the color provider according to the
// theme of the `widget_`.
SkColor GetColor(ui::ColorId color_id) {
return widget_->GetColorProvider()->GetColor(color_id);
}
// Creates a certain type of SystemShadow instance according to the test
// parameter.
std::unique_ptr<SystemShadow> MakeShadowAccordingToParam(
SystemShadow::Type type) {
switch (GetParam()) {
case SystemShadowType::kShadowOnNinePatchLayer:
return MakeShadowOnNinePatchLayer(type);
case SystemShadowType::kViewShadowOnNinePatchLayer:
return MakeViewShadowOnNinePatchLayer(type);
case SystemShadowType::kWindowShadowOnNinePatchLayer:
return MakeWindowShadowOnNinePatchLayer(type);
case SystemShadowType::kShadowOnTextureLayer:
return MakeShadowOnTextureLayer(type);
}
}
private:
// Creates an instance of `SystemShadowOnNinePatchLayer`.
std::unique_ptr<SystemShadow> MakeShadowOnNinePatchLayer(
SystemShadow::Type type) {
auto shadow = SystemShadow::CreateShadowOnNinePatchLayer(
type, SystemShadow::LayerRecreatedCallback());
AddShadowToWidget(shadow.get(), widget_.get());
return shadow;
}
// Creates an instance of `SystemViewShadowOnNinePatchLayer`.
std::unique_ptr<SystemShadow> MakeViewShadowOnNinePatchLayer(
SystemShadow::Type type) {
auto shadow = SystemShadow::CreateShadowOnNinePatchLayerForView(
widget_->GetContentsView(), type);
return shadow;
}
// Creates an instance of `SystemWindowShadowOnNinePatchLayer`.
std::unique_ptr<SystemShadow> MakeWindowShadowOnNinePatchLayer(
SystemShadow::Type type) {
auto shadow = SystemShadow::CreateShadowOnNinePatchLayerForWindow(
widget_->GetNativeWindow(), type);
return shadow;
}
// Creates an instance of `SystemShadowOnTextureLayer`.
std::unique_ptr<SystemShadow> MakeShadowOnTextureLayer(
SystemShadow::Type type) {
auto shadow = SystemShadow::CreateShadowOnTextureLayer(type);
AddShadowToWidget(shadow.get(), widget_.get());
return shadow;
}
base::test::ScopedFeatureList scoped_feature_list_;
// The test widget used as a shadow owner.
std::unique_ptr<views::Widget> widget_;
};
INSTANTIATE_TEST_SUITE_P(
MaterialNext,
SystemShadowColorTest,
testing::Values(SystemShadowType::kShadowOnNinePatchLayer,
SystemShadowType::kViewShadowOnNinePatchLayer,
SystemShadowType::kWindowShadowOnNinePatchLayer,
SystemShadowType::kShadowOnTextureLayer),
[](const testing::TestParamInfo<SystemShadowColorTest::ParamType>& info) {
switch (info.param) {
case SystemShadowType::kShadowOnNinePatchLayer:
return "ShadowOnNinePatchLayer";
case SystemShadowType::kViewShadowOnNinePatchLayer:
return "ViewShadowOnNinePatchLayer";
case SystemShadowType::kWindowShadowOnNinePatchLayer:
return "WindowShadowOnNinePatcherLayer";
case SystemShadowType::kShadowOnTextureLayer:
return "ShadowOnTextureLayer";
}
});
// Tests if the colors of system shadow change with shadow types.
TEST_P(SystemShadowColorTest, UpdateShadowColorsWithType) {
auto shadow = MakeShadowAccordingToParam(SystemShadow::Type::kElevation4);
EXPECT_EQ(GetShadowColors(shadow.get()),
std::make_pair(
GetColor(ui::kColorShadowValueKeyShadowElevationFour),
GetColor(ui::kColorShadowValueAmbientShadowElevationFour)));
// Change type to kElevation12.
shadow->SetType(SystemShadow::Type::kElevation12);
EXPECT_EQ(GetShadowColors(shadow.get()),
std::make_pair(
GetColor(ui::kColorShadowValueKeyShadowElevationTwelve),
GetColor(ui::kColorShadowValueAmbientShadowElevationTwelve)));
// Change type to kElevation24;
shadow->SetType(SystemShadow::Type::kElevation24);
EXPECT_EQ(
GetShadowColors(shadow.get()),
std::make_pair(
GetColor(ui::kColorShadowValueKeyShadowElevationTwentyFour),
GetColor(ui::kColorShadowValueAmbientShadowElevationTwentyFour)));
}
// Tests if the colors of system shadow change with the themes.
TEST_P(SystemShadowColorTest, UpdateShadowColorsWithTheme) {
auto shadow = MakeShadowAccordingToParam(SystemShadow::Type::kElevation4);
// Set light mode.
DarkLightModeController::Get()->SetDarkModeEnabledForTest(false);
EXPECT_EQ(GetShadowColors(shadow.get()),
std::make_pair(
GetColor(ui::kColorShadowValueKeyShadowElevationFour),
GetColor(ui::kColorShadowValueAmbientShadowElevationFour)));
// Set dark mode.
DarkLightModeController::Get()->SetDarkModeEnabledForTest(true);
EXPECT_EQ(GetShadowColors(shadow.get()),
std::make_pair(
GetColor(ui::kColorShadowValueKeyShadowElevationFour),
GetColor(ui::kColorShadowValueAmbientShadowElevationFour)));
}
} // namespace ash