Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Use Windows high contrast black/white theme with MaterialApp themes #39206

Merged
merged 9 commits into from
Feb 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions shell/platform/windows/flutter_windows_engine.cc
Original file line number Diff line number Diff line change
Expand Up @@ -668,6 +668,7 @@ void FlutterWindowsEngine::UpdateHighContrastEnabled(bool enabled) {
~FlutterAccessibilityFeature::kFlutterAccessibilityFeatureHighContrast;
}
UpdateAccessibilityFeatures(static_cast<FlutterAccessibilityFeature>(flags));
settings_plugin_->UpdateHighContrastMode(enabled);
}

int FlutterWindowsEngine::EnabledAccessibilityFeatures() const {
Expand Down
49 changes: 37 additions & 12 deletions shell/platform/windows/settings_plugin.cc
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,32 @@ constexpr wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme";
constexpr wchar_t kGetTextScaleFactorRegKey[] =
L"Software\\Microsoft\\Accessibility";
constexpr wchar_t kGetTextScaleFactorRegValue[] = L"TextScaleFactor";

// Return an approximation of the apparent luminance of a given color.
int GetLuminance(DWORD color) {
int r = GetRValue(color);
int g = GetGValue(color);
int b = GetBValue(color);
return (r + r + r + b + (g << 2)) >> 3;
}

// Return kLight if light mode for apps is selected, otherwise return kDark.
SettingsPlugin::PlatformBrightness GetThemeBrightness() {
DWORD use_light_theme;
DWORD use_light_theme_size = sizeof(use_light_theme);
LONG result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey,
kGetPreferredBrightnessRegValue, RRF_RT_REG_DWORD,
nullptr, &use_light_theme, &use_light_theme_size);

if (result == 0) {
return use_light_theme ? SettingsPlugin::PlatformBrightness::kLight
: SettingsPlugin::PlatformBrightness::kDark;
} else {
// The current OS does not support dark mode. (Older Windows 10 or before
// Windows 10)
return SettingsPlugin::PlatformBrightness::kLight;
}
}
} // namespace

SettingsPlugin::SettingsPlugin(BinaryMessenger* messenger,
Expand Down Expand Up @@ -103,19 +129,13 @@ float SettingsPlugin::GetTextScaleFactor() {
}

SettingsPlugin::PlatformBrightness SettingsPlugin::GetPreferredBrightness() {
DWORD use_light_theme;
DWORD use_light_theme_size = sizeof(use_light_theme);
LONG result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey,
kGetPreferredBrightnessRegValue, RRF_RT_REG_DWORD,
nullptr, &use_light_theme, &use_light_theme_size);

if (result == 0) {
return use_light_theme ? SettingsPlugin::PlatformBrightness::kLight
: SettingsPlugin::PlatformBrightness::kDark;
if (is_high_contrast_) {
DWORD window_color = GetSysColor(COLOR_WINDOW);
int luminance = GetLuminance(window_color);
return luminance >= 127 ? SettingsPlugin::PlatformBrightness::kLight
: SettingsPlugin::PlatformBrightness::kDark;
} else {
// The current OS does not support dark mode. (Older Windows 10 or before
// Windows 10)
return SettingsPlugin::PlatformBrightness::kLight;
return GetThemeBrightness();
}
}

Expand Down Expand Up @@ -146,4 +166,9 @@ void SettingsPlugin::WatchTextScaleFactorChanged() {
text_scale_factor_changed_watcher_->GetHandle(), TRUE);
}

void SettingsPlugin::UpdateHighContrastMode(bool is_high_contrast) {
is_high_contrast_ = is_high_contrast;
SendSettings();
}

} // namespace flutter
9 changes: 7 additions & 2 deletions shell/platform/windows/settings_plugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ namespace flutter {
// These are typically set in the control panel.
class SettingsPlugin {
public:
enum struct PlatformBrightness { kDark, kLight };

explicit SettingsPlugin(BinaryMessenger* messenger, TaskRunner* task_runner);

virtual ~SettingsPlugin();
Expand All @@ -37,9 +39,10 @@ class SettingsPlugin {
// this automatically.
virtual void StopWatching();

protected:
enum struct PlatformBrightness { kDark, kLight };
// Update the high contrast status of the system.
virtual void UpdateHighContrastMode(bool is_high_contrast);

protected:
// Returns `true` if the user uses 24 hour time.
virtual bool GetAlwaysUse24HourFormat();

Expand All @@ -55,6 +58,8 @@ class SettingsPlugin {
// Starts watching text scale factor changes.
virtual void WatchTextScaleFactorChanged();

bool is_high_contrast_ = false;

private:
std::unique_ptr<BasicMessageChannel<rapidjson::Document>> channel_;

Expand Down
21 changes: 21 additions & 0 deletions shell/platform/windows/settings_plugin_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ class MockSettingsPlugin : public SettingsPlugin {

virtual ~MockSettingsPlugin() = default;

bool is_high_contrast() { return is_high_contrast_; }

// |SettingsPlugin|
MOCK_METHOD0(GetAlwaysUse24HourFormat, bool());
MOCK_METHOD0(GetTextScaleFactor, float());
Expand Down Expand Up @@ -70,5 +72,24 @@ TEST(SettingsPluginTest, StartWatchingStartsWatchingChanges) {
settings_plugin.StartWatching();
}

TEST(SettingsPluginTest, HighContrastModeHonored) {
int times = 0;
TestBinaryMessenger messenger(
[&times](const std::string& channel, const uint8_t* message,
size_t message_size, BinaryReply reply) {
ASSERT_EQ(channel, "flutter/settings");
times++;
});
::testing::NiceMock<MockSettingsPlugin> settings_plugin(&messenger, nullptr);

settings_plugin.UpdateHighContrastMode(true);
EXPECT_TRUE(settings_plugin.is_high_contrast());

settings_plugin.UpdateHighContrastMode(false);
EXPECT_FALSE(settings_plugin.is_high_contrast());

EXPECT_EQ(times, 2);
}

} // namespace testing
} // namespace flutter