diff --git a/shell/platform/windows/flutter_windows_engine.cc b/shell/platform/windows/flutter_windows_engine.cc index 8a9f3f760074c..f0aab9220ea43 100644 --- a/shell/platform/windows/flutter_windows_engine.cc +++ b/shell/platform/windows/flutter_windows_engine.cc @@ -668,6 +668,7 @@ void FlutterWindowsEngine::UpdateHighContrastEnabled(bool enabled) { ~FlutterAccessibilityFeature::kFlutterAccessibilityFeatureHighContrast; } UpdateAccessibilityFeatures(static_cast(flags)); + settings_plugin_->UpdateHighContrastMode(enabled); } int FlutterWindowsEngine::EnabledAccessibilityFeatures() const { diff --git a/shell/platform/windows/settings_plugin.cc b/shell/platform/windows/settings_plugin.cc index 2754516e108be..094184703a030 100644 --- a/shell/platform/windows/settings_plugin.cc +++ b/shell/platform/windows/settings_plugin.cc @@ -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, @@ -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(); } } @@ -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 diff --git a/shell/platform/windows/settings_plugin.h b/shell/platform/windows/settings_plugin.h index 2c663fc048212..dbd770fa5bd6f 100644 --- a/shell/platform/windows/settings_plugin.h +++ b/shell/platform/windows/settings_plugin.h @@ -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(); @@ -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(); @@ -55,6 +58,8 @@ class SettingsPlugin { // Starts watching text scale factor changes. virtual void WatchTextScaleFactorChanged(); + bool is_high_contrast_ = false; + private: std::unique_ptr> channel_; diff --git a/shell/platform/windows/settings_plugin_unittests.cc b/shell/platform/windows/settings_plugin_unittests.cc index 2380f46017014..2ca1711c8faf4 100644 --- a/shell/platform/windows/settings_plugin_unittests.cc +++ b/shell/platform/windows/settings_plugin_unittests.cc @@ -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()); @@ -70,5 +72,24 @@ TEST(SettingsPluginTest, StartWatchingStartsWatchingChanges) { settings_plugin.StartWatching(); } +TEST(SettingsPluginTest, HighContrastModeHonored) { + int times = 0; + TestBinaryMessenger messenger( + [×](const std::string& channel, const uint8_t* message, + size_t message_size, BinaryReply reply) { + ASSERT_EQ(channel, "flutter/settings"); + times++; + }); + ::testing::NiceMock 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