From 38c8574705daf2dfd33cb05b836bb327424f2c00 Mon Sep 17 00:00:00 2001 From: Dan Field Date: Thu, 23 Mar 2023 13:16:03 -0700 Subject: [PATCH 01/19] start --- lib/ui/BUILD.gn | 1 + lib/ui/hooks.dart | 19 +++++++++ lib/ui/platform_dispatcher.dart | 28 +++++++++++++ lib/ui/window.dart | 32 +++++++++++++++ lib/ui/window/platform_configuration.cc | 14 +++++++ lib/ui/window/platform_configuration.h | 19 +++++---- lib/ui/window/viewport_metrics.cc | 19 ++++++--- lib/ui/window/viewport_metrics.h | 7 +++- lib/ui/window/window.cc | 1 + shell/common/BUILD.gn | 12 +++++- shell/common/display.h | 41 ++++++++++++------- shell/common/display_manager.cc | 12 +----- shell/common/display_manager.h | 7 ---- shell/common/variable_refresh_rate_display.cc | 5 --- shell/common/variable_refresh_rate_display.h | 2 - ...variable_refresh_rate_display_unittests.cc | 8 ++-- .../ios/framework/Source/FlutterEngine.mm | 7 ++-- 17 files changed, 168 insertions(+), 66 deletions(-) diff --git a/lib/ui/BUILD.gn b/lib/ui/BUILD.gn index 9355c0880a326..2eba89530fea8 100644 --- a/lib/ui/BUILD.gn +++ b/lib/ui/BUILD.gn @@ -147,6 +147,7 @@ source_set("ui") { public_deps = [ "//flutter/flow", + "//flutter/shell/common:display", "//flutter/shell/common:platform_message_handler", "//flutter/third_party/txt", ] diff --git a/lib/ui/hooks.dart b/lib/ui/hooks.dart index f92d287cf0f14..e6d5bf5b0ed1f 100644 --- a/lib/ui/hooks.dart +++ b/lib/ui/hooks.dart @@ -4,6 +4,23 @@ part of dart.ui; +@pragma('vm:entry-point') +void _updateDisplays( + List ids, + List devicePixelRatios, + List sizes, +) { + final List displays = []; + for (int i = 0; i < ids.length; i += 1) { + displays.add(Display._( + id: ids[i], + devicePixelRatio: devicePixelRatios[i], + size: Size(sizes[i * 2], sizes[i * 2 + 1]), + )); + } + PlatformDispatcher.instance._updateDisplays(displays); +} + @pragma('vm:entry-point') void _updateWindowMetrics( Object id, @@ -26,6 +43,7 @@ void _updateWindowMetrics( List displayFeaturesBounds, List displayFeaturesType, List displayFeaturesState, + int displayId, ) { PlatformDispatcher.instance._updateWindowMetrics( id, @@ -48,6 +66,7 @@ void _updateWindowMetrics( displayFeaturesBounds, displayFeaturesType, displayFeaturesState, + displayId, ); } diff --git a/lib/ui/platform_dispatcher.dart b/lib/ui/platform_dispatcher.dart index f955bb5f1882d..879a84e65a3ea 100644 --- a/lib/ui/platform_dispatcher.dart +++ b/lib/ui/platform_dispatcher.dart @@ -149,6 +149,14 @@ class PlatformDispatcher { _onPlatformConfigurationChangedZone = Zone.current; } + /// The current list of displays. + /// + /// If any of their configurations change, [onMetricsChanged] will be called. + /// + /// To get the display for a [FlutterView], use [FlutterView.display]. + Iterable get displays => _displays.values; + final Map _displays = {}; + /// The current list of views, including top level platform windows used by /// the application. /// @@ -215,6 +223,17 @@ class PlatformDispatcher { _onMetricsChangedZone = Zone.current; } + // Called from the engine, via hooks.dart. + // + // Updates the available displays. + void _updateDisplays(List displays) { + _displays.clear(); + for (final Display display in displays) { + _displays[display.id] = display; + } + _invoke(onMetricsChanged, _onMetricsChangedZone); + } + // Called from the engine, via hooks.dart // // Updates the metrics of the window with the given id. @@ -239,6 +258,7 @@ class PlatformDispatcher { List displayFeaturesBounds, List displayFeaturesType, List displayFeaturesState, + int displayId, ) { final _ViewConfiguration previousConfiguration = _viewConfigurations[id] ?? const _ViewConfiguration(); @@ -283,6 +303,7 @@ class PlatformDispatcher { state: displayFeaturesState, devicePixelRatio: devicePixelRatio, ), + displayId: displayId, ); _invoke(onMetricsChanged, _onMetricsChangedZone); } @@ -1319,6 +1340,7 @@ class _ViewConfiguration { this.padding = ViewPadding.zero, this.gestureSettings = const GestureSettings(), this.displayFeatures = const [], + this.displayId = 0, }); /// Copy this configuration with some fields replaced. @@ -1333,6 +1355,7 @@ class _ViewConfiguration { ViewPadding? padding, GestureSettings? gestureSettings, List? displayFeatures, + int? displayId, }) { return _ViewConfiguration( view: view ?? this.view, @@ -1345,11 +1368,16 @@ class _ViewConfiguration { padding: padding ?? this.padding, gestureSettings: gestureSettings ?? this.gestureSettings, displayFeatures: displayFeatures ?? this.displayFeatures, + displayId: displayId ?? this.displayId, ); } final FlutterView? view; + /// The identifier for a display for this view, in + /// [PlatformDispatcher._displays]. + final int displayId; + /// The pixel density of the output surface. final double devicePixelRatio; diff --git a/lib/ui/window.dart b/lib/ui/window.dart index 185f183baef9d..8b484cad17cae 100644 --- a/lib/ui/window.dart +++ b/lib/ui/window.dart @@ -3,6 +3,35 @@ // found in the LICENSE file. part of dart.ui; +/// A configurable display that a [FlutterView] renders on. +/// +/// Use [FlutterView.display] to get the current display for that view. +class Display { + const Display._({ + required this.id, + required this.devicePixelRatio, + required this.size, + }); + + /// A unique identifier for this display. + /// + /// This identifier is unique among a list of displays the Flutter framework + /// is aware of, and is not derived from any platform specific identifiers for + /// displays. + final int id; + + /// The device pixel ratio of this display. + final double devicePixelRatio; + + /// The physical size of this display. + final Size size; + + // TODO(dnfield): Implement refresh rate here. This would have to be a native + // getter to avoid trying to send updates to the display array every time + // the refresh rate changes, particularly on platforms that dynamically adjust + // the refresh rate during scrolling. +} + /// A view into which a Flutter [Scene] is drawn. /// /// Each [FlutterView] has its own layer tree that is rendered @@ -67,6 +96,9 @@ class FlutterView { return platformDispatcher._viewConfigurations[viewId]!; } + /// + Display get display => _viewConfiguration.display; + /// The number of device pixels for each logical pixel for the screen this /// view is displayed on. /// diff --git a/lib/ui/window/platform_configuration.cc b/lib/ui/window/platform_configuration.cc index 4e6e583745d4d..57d0a0760f5a2 100644 --- a/lib/ui/window/platform_configuration.cc +++ b/lib/ui/window/platform_configuration.cc @@ -43,6 +43,9 @@ void PlatformConfiguration::DidCreateIsolate() { on_error_.Set(tonic::DartState::Current(), Dart_GetField(library, tonic::ToDart("_onError"))); + update_displays_.Set( + tonic::DartState::Current(), + Dart_GetField(library, tonic::ToDart("_updateDisplays"))); update_locales_.Set(tonic::DartState::Current(), Dart_GetField(library, tonic::ToDart("_updateLocales"))); update_user_settings_data_.Set( @@ -78,6 +81,17 @@ void PlatformConfiguration::DidCreateIsolate() { kImplicitViewId, ViewportMetrics{1.0, 0.0, 0.0, -1})); } +void PlatformConfiguration::UpdateDisplays( + const std::vector displays) { + std::vector ids; + std::vector sizes; + std::vector device_pixel_ratios; + for (const auto display : displays) { + ids.push_back(display.id); + refresh_rates.push_back(display.GetRefreshRate()); + } +} + void PlatformConfiguration::UpdateLocales( const std::vector& locales) { std::shared_ptr dart_state = diff --git a/lib/ui/window/platform_configuration.h b/lib/ui/window/platform_configuration.h index 381b8e02e1072..4264efc35b081 100644 --- a/lib/ui/window/platform_configuration.h +++ b/lib/ui/window/platform_configuration.h @@ -17,6 +17,7 @@ #include "flutter/lib/ui/window/pointer_data_packet.h" #include "flutter/lib/ui/window/viewport_metrics.h" #include "flutter/lib/ui/window/window.h" +#include "flutter/shell/common/display.h" #include "third_party/tonic/dart_persistent_value.h" #include "third_party/tonic/typed_data/dart_byte_data.h" @@ -268,10 +269,15 @@ class PlatformConfiguration final { void DidCreateIsolate(); //---------------------------------------------------------------------------- - /// @brief Update the specified locale data in the framework. + /// @brief Update the specified display data in the framework. /// - /// @deprecated The persistent isolate data must be used for this purpose - /// instead. + /// @param[in] locale_data The locale data. This should consist of groups of + /// 4 strings, each group representing a single locale. + /// + void UpdateDisplays(const std::vector& displays); + + //---------------------------------------------------------------------------- + /// @brief Update the specified locale data in the framework. /// /// @param[in] locale_data The locale data. This should consist of groups of /// 4 strings, each group representing a single locale. @@ -281,9 +287,6 @@ class PlatformConfiguration final { //---------------------------------------------------------------------------- /// @brief Update the user settings data in the framework. /// - /// @deprecated The persistent isolate data must be used for this purpose - /// instead. - /// /// @param[in] data The user settings data. /// void UpdateUserSettingsData(const std::string& data); @@ -291,9 +294,6 @@ class PlatformConfiguration final { //---------------------------------------------------------------------------- /// @brief Updates the lifecycle state data in the framework. /// - /// @deprecated The persistent isolate data must be used for this purpose - /// instead. - /// /// @param[in] data The lifecycle state data. /// void UpdateInitialLifecycleState(const std::string& data); @@ -434,6 +434,7 @@ class PlatformConfiguration final { private: PlatformConfigurationClient* client_; tonic::DartPersistentValue on_error_; + tonic::DartPersistentValue update_displays_; tonic::DartPersistentValue update_locales_; tonic::DartPersistentValue update_user_settings_data_; tonic::DartPersistentValue update_initial_lifecycle_state_; diff --git a/lib/ui/window/viewport_metrics.cc b/lib/ui/window/viewport_metrics.cc index 1d61a6fc552a3..b4bdb2bbe4151 100644 --- a/lib/ui/window/viewport_metrics.cc +++ b/lib/ui/window/viewport_metrics.cc @@ -13,11 +13,13 @@ ViewportMetrics::ViewportMetrics() = default; ViewportMetrics::ViewportMetrics(double p_device_pixel_ratio, double p_physical_width, double p_physical_height, - double p_physical_touch_slop) + double p_physical_touch_slop, + size_t p_display_id) : device_pixel_ratio(p_device_pixel_ratio), physical_width(p_physical_width), physical_height(p_physical_height), - physical_touch_slop(p_physical_touch_slop) {} + physical_touch_slop(p_physical_touch_slop), + display_id(p_display_id) {} ViewportMetrics::ViewportMetrics( double p_device_pixel_ratio, @@ -38,7 +40,8 @@ ViewportMetrics::ViewportMetrics( double p_physical_touch_slop, const std::vector& p_physical_display_features_bounds, const std::vector& p_physical_display_features_type, - const std::vector& p_physical_display_features_state) + const std::vector& p_physical_display_features_state, + size_t p_display_id) : device_pixel_ratio(p_device_pixel_ratio), physical_width(p_physical_width), physical_height(p_physical_height), @@ -59,7 +62,8 @@ ViewportMetrics::ViewportMetrics( physical_touch_slop(p_physical_touch_slop), physical_display_features_bounds(p_physical_display_features_bounds), physical_display_features_type(p_physical_display_features_type), - physical_display_features_state(p_physical_display_features_state) {} + physical_display_features_state(p_physical_display_features_state), + display_id(p_display_id) {} bool operator==(const ViewportMetrics& a, const ViewportMetrics& b) { return a.device_pixel_ratio == b.device_pixel_ratio && @@ -85,7 +89,9 @@ bool operator==(const ViewportMetrics& a, const ViewportMetrics& b) { a.physical_display_features_bounds == b.physical_display_features_bounds && a.physical_display_features_type == b.physical_display_features_type && - a.physical_display_features_state == b.physical_display_features_state; + a.physical_display_features_state == + b.physical_display_features_state && + a.display_id == b.display_id; } std::ostream& operator<<(std::ostream& os, const ViewportMetrics& a) { @@ -101,7 +107,8 @@ std::ostream& operator<<(std::ostream& os, const ViewportMetrics& a) { << a.physical_system_gesture_inset_right << "R " << a.physical_system_gesture_inset_bottom << "B " << a.physical_system_gesture_inset_left << "L] " - << "Display Features: " << a.physical_display_features_type.size(); + << "Display Features: " << a.physical_display_features_type.size() << " " + << "Display ID: " << a.display_id; return os; } diff --git a/lib/ui/window/viewport_metrics.h b/lib/ui/window/viewport_metrics.h index 414a8b132d56d..13a0dee9439ea 100644 --- a/lib/ui/window/viewport_metrics.h +++ b/lib/ui/window/viewport_metrics.h @@ -15,7 +15,8 @@ struct ViewportMetrics { ViewportMetrics(double p_device_pixel_ratio, double p_physical_width, double p_physical_height, - double p_physical_touch_slop); + double p_physical_touch_slop, + size_t display_id); ViewportMetrics(double p_device_pixel_ratio, double p_physical_width, double p_physical_height, @@ -34,7 +35,8 @@ struct ViewportMetrics { double p_physical_touch_slop, const std::vector& p_physical_display_features_bounds, const std::vector& p_physical_display_features_type, - const std::vector& p_physical_display_features_state); + const std::vector& p_physical_display_features_state, + size_t p_display_id); double device_pixel_ratio = 1.0; double physical_width = 0; @@ -55,6 +57,7 @@ struct ViewportMetrics { std::vector physical_display_features_bounds; std::vector physical_display_features_type; std::vector physical_display_features_state; + size_t display_id = 0; }; bool operator==(const ViewportMetrics& a, const ViewportMetrics& b); diff --git a/lib/ui/window/window.cc b/lib/ui/window/window.cc index b269e97f7bf87..b33f4fb53a3ba 100644 --- a/lib/ui/window/window.cc +++ b/lib/ui/window/window.cc @@ -69,6 +69,7 @@ void Window::UpdateWindowMetrics(const ViewportMetrics& metrics) { tonic::ToDart(metrics.physical_display_features_bounds), tonic::ToDart(metrics.physical_display_features_type), tonic::ToDart(metrics.physical_display_features_state), + tonic::ToDart(metrics.display_id), })); } diff --git a/shell/common/BUILD.gn b/shell/common/BUILD.gn index 32d63365b4d39..2b0bd7f8dc1a1 100644 --- a/shell/common/BUILD.gn +++ b/shell/common/BUILD.gn @@ -65,6 +65,15 @@ source_set("platform_message_handler") { deps = [ "//flutter/fml:fml" ] } +source_set("display") { + sources = [ + "display.cc", + "display.h", + ] + public_configs = [ "//flutter:config" ] + deps = [ "//flutter/fml:fml" ] +} + source_set("common") { sources = [ "animator.cc", @@ -73,8 +82,6 @@ source_set("common") { "canvas_spy.h", "context_options.cc", "context_options.h", - "display.cc", - "display.h", "display_manager.cc", "display_manager.h", "engine.cc", @@ -120,6 +127,7 @@ source_set("common") { public_configs = [ "//flutter:config" ] public_deps = [ + ":display", ":platform_message_handler", "//flutter/shell/version", "//flutter/third_party/tonic", diff --git a/shell/common/display.h b/shell/common/display.h index a4cd5aa0863e0..41b17916338f3 100644 --- a/shell/common/display.h +++ b/shell/common/display.h @@ -14,7 +14,7 @@ namespace flutter { /// Unique ID per display that is stable until the Flutter application restarts. /// See also: `flutter::Display` -typedef uint64_t DisplayId; +typedef size_t DisplayId; /// To be used when the display refresh rate is unknown. static constexpr double kUnknownDisplayRefreshRate = 0; @@ -26,18 +26,17 @@ class Display { public: //------------------------------------------------------------------------------ /// @brief Construct a new Display object in case where the display id of the - /// display is known. In cases where there is more than one display, every - /// display is expected to have a display id. - /// - Display(DisplayId display_id, double refresh_rate) - : display_id_(display_id), refresh_rate_(refresh_rate) {} - - //------------------------------------------------------------------------------ - /// @brief Construct a new Display object when there is only a single display. - /// When there are multiple displays, every display must have a display id. - /// - explicit Display(double refresh_rate) - : display_id_({}), refresh_rate_(refresh_rate) {} + /// display is known. + Display(DisplayId display_id, + double refresh_rate, + double width, + double height, + double device_pixel_ratio) + : display_id_(display_id), + refresh_rate_(refresh_rate), + width_(width), + height_(height), + device_pixel_ratio_(device_pixel_ratio) {} virtual ~Display() = default; @@ -46,11 +45,23 @@ class Display { virtual double GetRefreshRate() const; /// Returns the `DisplayId` of the display. - std::optional GetDisplayId() const { return display_id_; } + DisplayId GetDisplayId() const { return display_id_; } + + /// The width of the display in physical pixels. + double GetWidth() const { return width_; } + + /// The height of the display in physical pixels. + double GetHeight() const { return height_; } + + /// The device pixel ratio of the display. + double GetDevicePixelRatio() const { return device_pixel_ratio_; } private: - std::optional display_id_; + DisplayId display_id_; double refresh_rate_; + double width_; + double height_; + double device_pixel_ratio_; FML_DISALLOW_COPY_AND_ASSIGN(Display); }; diff --git a/shell/common/display_manager.cc b/shell/common/display_manager.cc index 75211308de727..ad575970339c8 100644 --- a/shell/common/display_manager.cc +++ b/shell/common/display_manager.cc @@ -26,7 +26,7 @@ void DisplayManager::HandleDisplayUpdates( DisplayUpdateType update_type, std::vector> displays) { std::scoped_lock lock(displays_mutex_); - CheckDisplayConfiguration(displays); + FML_CHECK(!displays.empty()); switch (update_type) { case DisplayUpdateType::kStartup: FML_CHECK(displays_.empty()); @@ -37,14 +37,4 @@ void DisplayManager::HandleDisplayUpdates( } } -void DisplayManager::CheckDisplayConfiguration( - const std::vector>& displays) const { - FML_CHECK(!displays.empty()); - if (displays.size() > 1) { - for (auto& display : displays) { - FML_CHECK(display->GetDisplayId().has_value()); - } - } -} - } // namespace flutter diff --git a/shell/common/display_manager.h b/shell/common/display_manager.h index 774373d54e70b..126b318b50f64 100644 --- a/shell/common/display_manager.h +++ b/shell/common/display_manager.h @@ -46,13 +46,6 @@ class DisplayManager { /// Guards `displays_` vector. mutable std::mutex displays_mutex_; std::vector> displays_; - - /// Checks that the provided display configuration is valid. Currently this - /// ensures that all the displays have an id in the case there are multiple - /// displays. In case where there is a single display, it is valid for the - /// display to not have an id. - void CheckDisplayConfiguration( - const std::vector>& displays) const; }; } // namespace flutter diff --git a/shell/common/variable_refresh_rate_display.cc b/shell/common/variable_refresh_rate_display.cc index d51af1a08a724..e53777eaacdba 100644 --- a/shell/common/variable_refresh_rate_display.cc +++ b/shell/common/variable_refresh_rate_display.cc @@ -22,11 +22,6 @@ VariableRefreshRateDisplay::VariableRefreshRateDisplay( : Display(display_id, GetInitialRefreshRate(refresh_rate_reporter)), refresh_rate_reporter_(refresh_rate_reporter) {} -VariableRefreshRateDisplay::VariableRefreshRateDisplay( - const std::weak_ptr& refresh_rate_reporter) - : Display(GetInitialRefreshRate(refresh_rate_reporter)), - refresh_rate_reporter_(refresh_rate_reporter) {} - double VariableRefreshRateDisplay::GetRefreshRate() const { return GetInitialRefreshRate(refresh_rate_reporter_); } diff --git a/shell/common/variable_refresh_rate_display.h b/shell/common/variable_refresh_rate_display.h index 38cb979c36926..475c0d3ea1c77 100644 --- a/shell/common/variable_refresh_rate_display.h +++ b/shell/common/variable_refresh_rate_display.h @@ -19,8 +19,6 @@ class VariableRefreshRateDisplay : public Display { explicit VariableRefreshRateDisplay( DisplayId display_id, const std::weak_ptr& refresh_rate_reporter); - explicit VariableRefreshRateDisplay( - const std::weak_ptr& refresh_rate_reporter); ~VariableRefreshRateDisplay() = default; // |Display| diff --git a/shell/common/variable_refresh_rate_display_unittests.cc b/shell/common/variable_refresh_rate_display_unittests.cc index e65641264d8e1..3d160b34c1d7e 100644 --- a/shell/common/variable_refresh_rate_display_unittests.cc +++ b/shell/common/variable_refresh_rate_display_unittests.cc @@ -13,14 +13,14 @@ namespace testing { TEST(VariableRefreshRateDisplayTest, ReportCorrectInitialRefreshRate) { auto refresh_rate_reporter = std::make_shared(60); auto display = flutter::VariableRefreshRateDisplay( - std::weak_ptr(refresh_rate_reporter)); + 0, std::weak_ptr(refresh_rate_reporter)); ASSERT_EQ(display.GetRefreshRate(), 60); } TEST(VariableRefreshRateDisplayTest, ReportCorrectRefreshRateWhenUpdated) { auto refresh_rate_reporter = std::make_shared(60); auto display = flutter::VariableRefreshRateDisplay( - std::weak_ptr(refresh_rate_reporter)); + 0, std::weak_ptr(refresh_rate_reporter)); refresh_rate_reporter->UpdateRefreshRate(30); ASSERT_EQ(display.GetRefreshRate(), 30); } @@ -29,7 +29,7 @@ TEST(VariableRefreshRateDisplayTest, Report0IfReporterSharedPointerIsDestroyedAfterDisplayCreation) { auto refresh_rate_reporter = std::make_shared(60); auto display = flutter::VariableRefreshRateDisplay( - std::weak_ptr(refresh_rate_reporter)); + 0, std::weak_ptr(refresh_rate_reporter)); refresh_rate_reporter.reset(); ASSERT_EQ(display.GetRefreshRate(), 0); } @@ -39,7 +39,7 @@ TEST(VariableRefreshRateDisplayTest, auto refresh_rate_reporter = std::make_shared(60); refresh_rate_reporter.reset(); auto display = flutter::VariableRefreshRateDisplay( - std::weak_ptr(refresh_rate_reporter)); + 0, std::weak_ptr(refresh_rate_reporter)); ASSERT_EQ(display.GetRefreshRate(), 0); } diff --git a/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm b/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm index ff94acaa2797b..cd630ef027742 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm @@ -395,6 +395,7 @@ - (void)setViewController:(FlutterViewController*)viewController { viewController ? [viewController getWeakPtr] : fml::WeakPtr(); self.iosPlatformView->SetOwnerViewController(_viewController); [self maybeSetupPlatformViewChannels]; + [self updateDisplays]; _textInputPlugin.get().viewController = viewController; _undoManagerPlugin.get().viewController = viewController; @@ -732,7 +733,7 @@ - (void)setupShell:(std::unique_ptr)shell _shell = std::move(shell); [self setupChannels]; [self onLocaleUpdated:nil]; - [self initializeDisplays]; + [self updateDisplays]; _publisher.reset([[FlutterDartVMServicePublisher alloc] initWithEnableVMServicePublication:doesVMServicePublication]); [self maybeSetupPlatformViewChannels]; @@ -873,11 +874,11 @@ - (BOOL)createShell:(NSString*)entrypoint return _shell != nullptr; } -- (void)initializeDisplays { +- (void)updateDisplays { auto vsync_waiter = std::shared_ptr(_shell->GetVsyncWaiter().lock()); auto vsync_waiter_ios = std::static_pointer_cast(vsync_waiter); std::vector> displays; - displays.push_back(std::make_unique(vsync_waiter_ios)); + displays.push_back(std::make_unique(0, vsync_waiter_ios)); _shell->OnDisplayUpdates(flutter::DisplayUpdateType::kStartup, std::move(displays)); } From 91d7e817478439165aad83024fc238e9175af0f5 Mon Sep 17 00:00:00 2001 From: Dan Field Date: Tue, 2 May 2023 20:48:41 -0700 Subject: [PATCH 02/19] Report display sizes for mobile to Flutter --- lib/ui/hooks.dart | 15 +++-- lib/ui/window.dart | 17 +++-- lib/ui/window/platform_configuration.cc | 27 ++++++-- lib/ui/window/platform_configuration.h | 2 +- .../platform_configuration_unittests.cc | 2 +- runtime/BUILD.gn | 1 + runtime/platform_data.h | 2 + runtime/runtime_controller.cc | 14 +++- runtime/runtime_controller.h | 8 +++ shell/common/BUILD.gn | 6 +- shell/common/display.h | 26 +++++++- shell/common/display_manager.cc | 1 - shell/common/engine.cc | 5 ++ shell/common/engine.h | 8 +++ shell/common/shell.cc | 13 ++++ shell/common/shell_test.cc | 5 +- shell/common/shell_unittests.cc | 53 ++++++++------- shell/common/variable_refresh_rate_display.cc | 11 +++- shell/common/variable_refresh_rate_display.h | 5 +- ...variable_refresh_rate_display_unittests.cc | 12 ++-- .../android/android_context_gl_unittests.cc | 3 + shell/platform/android/android_display.cc | 19 +++++- shell/platform/android/android_display.h | 11 +++- .../platform/android/android_shell_holder.cc | 15 ++--- shell/platform/android/android_shell_holder.h | 2 + .../android/android_shell_holder_unittests.cc | 3 + .../embedding/android/FlutterView.java | 2 + .../embedding/engine/FlutterEngine.java | 10 ++- .../flutter/embedding/engine/FlutterJNI.java | 16 +++++ .../android/io/flutter/util/ViewUtils.java | 24 +++++++ shell/platform/android/jni/jni_mock.h | 3 + .../android/jni/platform_view_android_jni.h | 6 ++ .../android/platform_view_android_jni_impl.cc | 66 +++++++++++++++++++ .../android/platform_view_android_jni_impl.h | 6 ++ .../ios/framework/Source/FlutterEngine.mm | 5 +- shell/platform/embedder/embedder.cc | 12 ++-- 36 files changed, 355 insertions(+), 81 deletions(-) diff --git a/lib/ui/hooks.dart b/lib/ui/hooks.dart index e6d5bf5b0ed1f..c22255be587fb 100644 --- a/lib/ui/hooks.dart +++ b/lib/ui/hooks.dart @@ -7,17 +7,22 @@ part of dart.ui; @pragma('vm:entry-point') void _updateDisplays( List ids, - List devicePixelRatios, List sizes, + List devicePixelRatios, + List refreshRates, ) { final List displays = []; - for (int i = 0; i < ids.length; i += 1) { + int sizeIndex = 0; + for (int index = 0; index < ids.length; index += 1) { + final int displayId = ids[index]; displays.add(Display._( - id: ids[i], - devicePixelRatio: devicePixelRatios[i], - size: Size(sizes[i * 2], sizes[i * 2 + 1]), + id: displayId, + size: Size(sizes[sizeIndex++], sizes[sizeIndex++]), + devicePixelRatio: devicePixelRatios[index], + refreshRate: refreshRates[index], )); } + PlatformDispatcher.instance._updateDisplays(displays); } diff --git a/lib/ui/window.dart b/lib/ui/window.dart index 3f4c772688f16..5a8018de778e9 100644 --- a/lib/ui/window.dart +++ b/lib/ui/window.dart @@ -11,6 +11,7 @@ class Display { required this.id, required this.devicePixelRatio, required this.size, + required this.refreshRate, }); /// A unique identifier for this display. @@ -26,10 +27,11 @@ class Display { /// The physical size of this display. final Size size; - // TODO(dnfield): Implement refresh rate here. This would have to be a native - // getter to avoid trying to send updates to the display array every time - // the refresh rate changes, particularly on platforms that dynamically adjust - // the refresh rate during scrolling. + /// The refresh rate in FPS of this display. + final double refreshRate; + + @override + String toString() => 'Display(id: $id, size: $size, devicePixelRatio: $devicePixelRatio, refreshRate: $refreshRate)'; } /// A view into which a Flutter [Scene] is drawn. @@ -96,8 +98,11 @@ class FlutterView { return platformDispatcher._viewConfigurations[viewId]!; } - /// - Display get display => _viewConfiguration.display; + /// The [Display] this view is drawn in. + Display get display { + assert(platformDispatcher._displays.containsKey(_viewConfiguration.displayId)); + return platformDispatcher._displays[_viewConfiguration.displayId]!; + } /// The number of device pixels for each logical pixel for the screen this /// view is displayed on. diff --git a/lib/ui/window/platform_configuration.cc b/lib/ui/window/platform_configuration.cc index 24491fc3ce281..e10903a14305c 100644 --- a/lib/ui/window/platform_configuration.cc +++ b/lib/ui/window/platform_configuration.cc @@ -81,18 +81,35 @@ void PlatformConfiguration::DidCreateIsolate() { // See: https://github.com/flutter/flutter/issues/120306 windows_.emplace(kImplicitViewId, std::make_unique( - kImplicitViewId, ViewportMetrics{1.0, 0.0, 0.0, -1})); + kImplicitViewId, ViewportMetrics{1.0, 0.0, 0.0, -1, 0})); } -void PlatformConfiguration::UpdateDisplays( - const std::vector displays) { +void PlatformConfiguration::UpdateDisplays(std::vector displays) { std::vector ids; std::vector sizes; std::vector device_pixel_ratios; - for (const auto display : displays) { + std::vector refresh_rates; + for (const auto& display : displays) { ids.push_back(display.id); - refresh_rates.push_back(display.GetRefreshRate()); + sizes.push_back(display.width); + sizes.push_back(display.height); + device_pixel_ratios.push_back(display.pixel_ratio); + refresh_rates.push_back(display.refresh_rate); } + std::shared_ptr dart_state = + update_displays_.dart_state().lock(); + if (!dart_state) { + return; + } + tonic::DartState::Scope scope(dart_state); + tonic::CheckAndHandleError(tonic::DartInvoke( + update_displays_.Get(), + { + tonic::ToDart>(ids), + tonic::ToDart>(sizes), + tonic::ToDart>(device_pixel_ratios), + tonic::ToDart>(refresh_rates), + })); } void PlatformConfiguration::UpdateLocales( diff --git a/lib/ui/window/platform_configuration.h b/lib/ui/window/platform_configuration.h index 592aa71b718b2..63367d75da28e 100644 --- a/lib/ui/window/platform_configuration.h +++ b/lib/ui/window/platform_configuration.h @@ -274,7 +274,7 @@ class PlatformConfiguration final { /// @param[in] locale_data The locale data. This should consist of groups of /// 4 strings, each group representing a single locale. /// - void UpdateDisplays(const std::vector& displays); + void UpdateDisplays(std::vector displays); //---------------------------------------------------------------------------- /// @brief Update the specified locale data in the framework. diff --git a/lib/ui/window/platform_configuration_unittests.cc b/lib/ui/window/platform_configuration_unittests.cc index 9b971947f5e84..e89a5cc7d381c 100644 --- a/lib/ui/window/platform_configuration_unittests.cc +++ b/lib/ui/window/platform_configuration_unittests.cc @@ -73,7 +73,7 @@ TEST_F(ShellTest, PlatformConfigurationWindowMetricsUpdate) { ASSERT_NE(configuration->get_window(0), nullptr); configuration->get_window(0)->UpdateWindowMetrics( - ViewportMetrics{2.0, 10.0, 20.0, 22}); + ViewportMetrics{2.0, 10.0, 20.0, 22, 0}); ASSERT_EQ( configuration->get_window(0)->viewport_metrics().device_pixel_ratio, 2.0); diff --git a/runtime/BUILD.gn b/runtime/BUILD.gn index 48ef5882eca4b..70e9172d51dd3 100644 --- a/runtime/BUILD.gn +++ b/runtime/BUILD.gn @@ -104,6 +104,7 @@ source_set("runtime") { "//flutter/flow", "//flutter/fml", "//flutter/lib/io", + "//flutter/shell/common:display", "//flutter/third_party/tonic", "//flutter/third_party/txt", "//third_party/dart/runtime:dart_api", diff --git a/runtime/platform_data.h b/runtime/platform_data.h index 8b11b34ef6585..b6d4c65f94d19 100644 --- a/runtime/platform_data.h +++ b/runtime/platform_data.h @@ -10,6 +10,7 @@ #include #include "flutter/lib/ui/window/viewport_metrics.h" +#include "flutter/shell/common/display.h" namespace flutter { @@ -42,6 +43,7 @@ struct PlatformData { bool semantics_enabled = false; bool assistive_technology_enabled = false; int32_t accessibility_feature_flags_ = 0; + std::vector displays; }; } // namespace flutter diff --git a/runtime/runtime_controller.cc b/runtime/runtime_controller.cc index 66ffd8c76ac1b..0f6207aad901c 100644 --- a/runtime/runtime_controller.cc +++ b/runtime/runtime_controller.cc @@ -119,7 +119,8 @@ bool RuntimeController::FlushRuntimeStateToIsolate() { SetAccessibilityFeatures( platform_data_.accessibility_feature_flags_) && SetUserSettingsData(platform_data_.user_settings_data) && - SetInitialLifecycleState(platform_data_.lifecycle_state); + SetInitialLifecycleState(platform_data_.lifecycle_state) && + SetDisplays(platform_data_.displays); } bool RuntimeController::SetViewportMetrics(const ViewportMetrics& metrics) { @@ -499,6 +500,17 @@ void RuntimeController::RequestDartDeferredLibrary(intptr_t loading_unit_id) { return client_.RequestDartDeferredLibrary(loading_unit_id); } +bool RuntimeController::SetDisplays(std::vector displays) { + TRACE_EVENT0("flutter", "SetDisplays"); + platform_data_.displays = displays; + + if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) { + platform_configuration->UpdateDisplays(std::move(displays)); + return true; + } + return false; +} + RuntimeController::Locale::Locale(std::string language_code_, std::string country_code_, std::string script_code_, diff --git a/runtime/runtime_controller.h b/runtime/runtime_controller.h index b3fc828f8264c..810936e8320fd 100644 --- a/runtime/runtime_controller.h +++ b/runtime/runtime_controller.h @@ -174,6 +174,14 @@ class RuntimeController : public PlatformConfigurationClient { /// bool SetViewportMetrics(const ViewportMetrics& metrics); + //---------------------------------------------------------------------------- + /// @brief Forward the specified display metrics to the running isolate. + /// If the isolate is not running, these metrics will be saved and + /// flushed to the isolate when it starts. + /// + /// @param[in] displays The available displays. + bool SetDisplays(std::vector displays); + //---------------------------------------------------------------------------- /// @brief Forward the specified locale data to the running isolate. If /// the isolate is not running, this data will be saved and diff --git a/shell/common/BUILD.gn b/shell/common/BUILD.gn index 2400b93c21109..19009938162fc 100644 --- a/shell/common/BUILD.gn +++ b/shell/common/BUILD.gn @@ -69,6 +69,9 @@ source_set("display") { sources = [ "display.cc", "display.h", + "variable_refresh_rate_display.cc", + "variable_refresh_rate_display.h", + "variable_refresh_rate_reporter.h", ] public_configs = [ "//flutter:config" ] deps = [ "//flutter/fml:fml" ] @@ -117,9 +120,6 @@ source_set("common") { "switches.h", "thread_host.cc", "thread_host.h", - "variable_refresh_rate_display.cc", - "variable_refresh_rate_display.h", - "variable_refresh_rate_reporter.h", "vsync_waiter.cc", "vsync_waiter.h", "vsync_waiter_fallback.cc", diff --git a/shell/common/display.h b/shell/common/display.h index 41b17916338f3..361e45bfc1207 100644 --- a/shell/common/display.h +++ b/shell/common/display.h @@ -19,6 +19,16 @@ typedef size_t DisplayId; /// To be used when the display refresh rate is unknown. static constexpr double kUnknownDisplayRefreshRate = 0; +/// The POD of a |Display|. This data is for a point in time and suitable +/// for copying. +struct DisplayData { + DisplayId id; + double width; + double height; + double pixel_ratio; + double refresh_rate; +}; + /// Display refers to a graphics hardware system consisting of a framebuffer, /// typically a monitor or a screen. This class holds the various display /// settings. @@ -48,13 +58,23 @@ class Display { DisplayId GetDisplayId() const { return display_id_; } /// The width of the display in physical pixels. - double GetWidth() const { return width_; } + virtual double GetWidth() const { return width_; } /// The height of the display in physical pixels. - double GetHeight() const { return height_; } + virtual double GetHeight() const { return height_; } /// The device pixel ratio of the display. - double GetDevicePixelRatio() const { return device_pixel_ratio_; } + virtual double GetDevicePixelRatio() const { return device_pixel_ratio_; } + + DisplayData GetDisplayData() { + return DisplayData{ + .id = GetDisplayId(), + .width = GetWidth(), + .height = GetHeight(), + .pixel_ratio = GetDevicePixelRatio(), + .refresh_rate = GetRefreshRate(), + }; + } private: DisplayId display_id_; diff --git a/shell/common/display_manager.cc b/shell/common/display_manager.cc index ad575970339c8..8b4c53f4b2b90 100644 --- a/shell/common/display_manager.cc +++ b/shell/common/display_manager.cc @@ -29,7 +29,6 @@ void DisplayManager::HandleDisplayUpdates( FML_CHECK(!displays.empty()); switch (update_type) { case DisplayUpdateType::kStartup: - FML_CHECK(displays_.empty()); displays_ = std::move(displays); return; default: diff --git a/shell/common/engine.cc b/shell/common/engine.cc index 522ee89a52a7b..57604ec18c853 100644 --- a/shell/common/engine.cc +++ b/shell/common/engine.cc @@ -583,4 +583,9 @@ const std::weak_ptr Engine::GetVsyncWaiter() const { return animator_->GetVsyncWaiter(); } +void Engine::SetDisplays(std::vector displays) { + runtime_controller_->SetDisplays(std::move(displays)); + ScheduleFrame(); +} + } // namespace flutter diff --git a/shell/common/engine.h b/shell/common/engine.h index c6ff37eae37a5..63706ffe64a47 100644 --- a/shell/common/engine.h +++ b/shell/common/engine.h @@ -685,6 +685,14 @@ class Engine final : public RuntimeDelegate, PointerDataDispatcher::Delegate { /// void SetViewportMetrics(const ViewportMetrics& metrics); + //---------------------------------------------------------------------------- + /// @brief Updates the display metrics for the currently running Flutter + /// application. + /// + /// @param[in] displays A complete list of displays + /// + void SetDisplays(std::vector displays); + //---------------------------------------------------------------------------- /// @brief Notifies the engine that the embedder has sent it a message. /// This call originates in the platform view and has been diff --git a/shell/common/shell.cc b/shell/common/shell.cc index 214b3b384569c..9f87d5e93def4 100644 --- a/shell/common/shell.cc +++ b/shell/common/shell.cc @@ -2073,6 +2073,19 @@ void Shell::SetGpuAvailability(GpuAvailability availability) { void Shell::OnDisplayUpdates(DisplayUpdateType update_type, std::vector> displays) { + FML_DCHECK(is_setup_); + std::vector display_data; + for (const auto& display : displays) { + display_data.push_back(display->GetDisplayData()); + } + task_runners_.GetUITaskRunner()->PostTask( + [engine = engine_->GetWeakPtr(), + display_data = std::move(display_data)]() { + if (engine) { + engine->SetDisplays(std::move(display_data)); + } + }); + display_manager_->HandleDisplayUpdates(update_type, std::move(displays)); } diff --git a/shell/common/shell_test.cc b/shell/common/shell_test.cc index a799e6bcb4811..892892734af4f 100644 --- a/shell/common/shell_test.cc +++ b/shell/common/shell_test.cc @@ -129,7 +129,8 @@ void ShellTest::SetViewportMetrics(Shell* shell, double width, double height) { 22, // physical touch slop std::vector(), // display features bounds std::vector(), // display features type - std::vector() // display features state + std::vector(), // display features state + 0 // Display ID }; // Set viewport to nonempty, and call Animator::BeginFrame to make the layer // tree pipeline nonempty. Without either of this, the layer tree below @@ -168,7 +169,7 @@ void ShellTest::PumpOneFrame(Shell* shell, double width, double height, LayerTreeBuilder builder) { - PumpOneFrame(shell, {1.0, width, height, 22}, std::move(builder)); + PumpOneFrame(shell, {1.0, width, height, 22, 0}, std::move(builder)); } void ShellTest::PumpOneFrame(Shell* shell, diff --git a/shell/common/shell_unittests.cc b/shell/common/shell_unittests.cc index d85750e70d612..71b4e1f57a16b 100644 --- a/shell/common/shell_unittests.cc +++ b/shell/common/shell_unittests.cc @@ -1450,7 +1450,7 @@ TEST_F(ShellTest, WaitForFirstFrameZeroSizeFrame) { configuration.SetEntrypoint("emptyMain"); RunEngine(shell.get(), std::move(configuration)); - PumpOneFrame(shell.get(), {1.0, 0.0, 0.0, 22}); + PumpOneFrame(shell.get(), {1.0, 0.0, 0.0, 22, 0}); fml::Status result = shell->WaitForFirstFrame(fml::TimeDelta::Zero()); ASSERT_FALSE(result.ok()); ASSERT_EQ(result.code(), fml::StatusCode::kDeadlineExceeded); @@ -1584,7 +1584,7 @@ TEST_F(ShellTest, MultipleFluttersSetResourceCacheBytes) { RunEngine(shell.get(), std::move(configuration)); PostSync(shell->GetTaskRunners().GetPlatformTaskRunner(), [&shell]() { - shell->GetPlatformView()->SetViewportMetrics({1.0, 100, 100, 22}); + shell->GetPlatformView()->SetViewportMetrics({1.0, 100, 100, 22, 0}); }); // first cache bytes @@ -1613,7 +1613,7 @@ TEST_F(ShellTest, MultipleFluttersSetResourceCacheBytes) { PostSync(second_shell->GetTaskRunners().GetPlatformTaskRunner(), [&second_shell]() { second_shell->GetPlatformView()->SetViewportMetrics( - {1.0, 100, 100, 22}); + {1.0, 100, 100, 22, 0}); }); // first cache bytes + second cache bytes EXPECT_EQ(GetRasterizerResourceCacheBytesSync(*shell), @@ -1622,7 +1622,7 @@ TEST_F(ShellTest, MultipleFluttersSetResourceCacheBytes) { PostSync(second_shell->GetTaskRunners().GetPlatformTaskRunner(), [&second_shell]() { second_shell->GetPlatformView()->SetViewportMetrics( - {1.0, 100, 300, 22}); + {1.0, 100, 300, 22, 0}); }); // first cache bytes + second cache bytes EXPECT_EQ(GetRasterizerResourceCacheBytesSync(*shell), @@ -1630,18 +1630,20 @@ TEST_F(ShellTest, MultipleFluttersSetResourceCacheBytes) { std::unique_ptr third_shell = shell_spawn_callback(); PlatformViewNotifyCreated(third_shell.get()); - PostSync( - third_shell->GetTaskRunners().GetPlatformTaskRunner(), [&third_shell]() { - third_shell->GetPlatformView()->SetViewportMetrics({1.0, 400, 100, 22}); - }); + PostSync(third_shell->GetTaskRunners().GetPlatformTaskRunner(), + [&third_shell]() { + third_shell->GetPlatformView()->SetViewportMetrics( + {1.0, 400, 100, 22, 0}); + }); // first cache bytes + second cache bytes + third cache bytes EXPECT_EQ(GetRasterizerResourceCacheBytesSync(*shell), static_cast(3840000U)); - PostSync( - third_shell->GetTaskRunners().GetPlatformTaskRunner(), [&third_shell]() { - third_shell->GetPlatformView()->SetViewportMetrics({1.0, 800, 100, 22}); - }); + PostSync(third_shell->GetTaskRunners().GetPlatformTaskRunner(), + [&third_shell]() { + third_shell->GetPlatformView()->SetViewportMetrics( + {1.0, 800, 100, 22, 0}); + }); // max bytes threshold EXPECT_EQ(GetRasterizerResourceCacheBytesSync(*shell), static_cast(4000000U)); @@ -1653,7 +1655,7 @@ TEST_F(ShellTest, MultipleFluttersSetResourceCacheBytes) { PostSync(second_shell->GetTaskRunners().GetPlatformTaskRunner(), [&second_shell]() { second_shell->GetPlatformView()->SetViewportMetrics( - {1.0, 100, 100, 22}); + {1.0, 100, 100, 22, 0}); }); // first cache bytes + second cache bytes EXPECT_EQ(GetRasterizerResourceCacheBytesSync(*shell), @@ -1697,7 +1699,7 @@ TEST_F(ShellTest, SetResourceCacheSize) { fml::TaskRunner::RunNowOrPostTask( shell->GetTaskRunners().GetPlatformTaskRunner(), [&shell]() { - shell->GetPlatformView()->SetViewportMetrics({1.0, 400, 200, 22}); + shell->GetPlatformView()->SetViewportMetrics({1.0, 400, 200, 22, 0}); }); PumpOneFrame(shell.get()); @@ -1717,7 +1719,7 @@ TEST_F(ShellTest, SetResourceCacheSize) { fml::TaskRunner::RunNowOrPostTask( shell->GetTaskRunners().GetPlatformTaskRunner(), [&shell]() { - shell->GetPlatformView()->SetViewportMetrics({1.0, 800, 400, 22}); + shell->GetPlatformView()->SetViewportMetrics({1.0, 800, 400, 22, 0}); }); PumpOneFrame(shell.get()); @@ -1734,7 +1736,7 @@ TEST_F(ShellTest, SetResourceCacheSizeEarly) { fml::TaskRunner::RunNowOrPostTask( shell->GetTaskRunners().GetPlatformTaskRunner(), [&shell]() { - shell->GetPlatformView()->SetViewportMetrics({1.0, 400, 200, 22}); + shell->GetPlatformView()->SetViewportMetrics({1.0, 400, 200, 22, 0}); }); PumpOneFrame(shell.get()); @@ -1761,7 +1763,7 @@ TEST_F(ShellTest, SetResourceCacheSizeNotifiesDart) { fml::TaskRunner::RunNowOrPostTask( shell->GetTaskRunners().GetPlatformTaskRunner(), [&shell]() { - shell->GetPlatformView()->SetViewportMetrics({1.0, 400, 200, 22}); + shell->GetPlatformView()->SetViewportMetrics({1.0, 400, 200, 22, 0}); }); PumpOneFrame(shell.get()); @@ -2627,7 +2629,7 @@ TEST_F(ShellTest, DISABLED_DiscardLayerTreeOnResize) { [&shell, &expected_size]() { shell->GetPlatformView()->SetViewportMetrics( {1.0, static_cast(expected_size.width()), - static_cast(expected_size.height()), 22}); + static_cast(expected_size.height()), 22, 0}); }); auto configuration = RunConfiguration::InferFromSettings(settings); @@ -2700,7 +2702,7 @@ TEST_F(ShellTest, DISABLED_DiscardResubmittedLayerTreeOnResize) { [&shell, &origin_size]() { shell->GetPlatformView()->SetViewportMetrics( {1.0, static_cast(origin_size.width()), - static_cast(origin_size.height()), 22}); + static_cast(origin_size.height()), 22, 0}); }); auto configuration = RunConfiguration::InferFromSettings(settings); @@ -2719,7 +2721,7 @@ TEST_F(ShellTest, DISABLED_DiscardResubmittedLayerTreeOnResize) { [&shell, &new_size, &resize_latch]() { shell->GetPlatformView()->SetViewportMetrics( {1.0, static_cast(new_size.width()), - static_cast(new_size.height()), 22}); + static_cast(new_size.height()), 22, 0}); resize_latch.Signal(); }); @@ -2782,13 +2784,14 @@ TEST_F(ShellTest, IgnoresInvalidMetrics) { RunEngine(shell.get(), std::move(configuration)); task_runner->PostTask([&]() { - shell->GetPlatformView()->SetViewportMetrics({0.0, 400, 200, 22}); + shell->GetPlatformView()->SetViewportMetrics({0.0, 400, 200, 22, 0}); task_runner->PostTask([&]() { - shell->GetPlatformView()->SetViewportMetrics({0.8, 0.0, 200, 22}); + shell->GetPlatformView()->SetViewportMetrics({0.8, 0.0, 200, 22, 0}); task_runner->PostTask([&]() { - shell->GetPlatformView()->SetViewportMetrics({0.8, 400, 0.0, 22}); + shell->GetPlatformView()->SetViewportMetrics({0.8, 400, 0.0, 22, 0}); task_runner->PostTask([&]() { - shell->GetPlatformView()->SetViewportMetrics({0.8, 400, 200.0, 22}); + shell->GetPlatformView()->SetViewportMetrics( + {0.8, 400, 200.0, 22, 0}); }); }); }); @@ -2800,7 +2803,7 @@ TEST_F(ShellTest, IgnoresInvalidMetrics) { latch.Reset(); task_runner->PostTask([&]() { - shell->GetPlatformView()->SetViewportMetrics({1.2, 600, 300, 22}); + shell->GetPlatformView()->SetViewportMetrics({1.2, 600, 300, 22, 0}); }); latch.Wait(); ASSERT_EQ(last_device_pixel_ratio, 1.2); diff --git a/shell/common/variable_refresh_rate_display.cc b/shell/common/variable_refresh_rate_display.cc index e53777eaacdba..138fc0edb6ad5 100644 --- a/shell/common/variable_refresh_rate_display.cc +++ b/shell/common/variable_refresh_rate_display.cc @@ -18,8 +18,15 @@ namespace flutter { VariableRefreshRateDisplay::VariableRefreshRateDisplay( DisplayId display_id, - const std::weak_ptr& refresh_rate_reporter) - : Display(display_id, GetInitialRefreshRate(refresh_rate_reporter)), + const std::weak_ptr& refresh_rate_reporter, + double width, + double height, + double device_pixel_ratio) + : Display(display_id, + GetInitialRefreshRate(refresh_rate_reporter), + width, + height, + device_pixel_ratio), refresh_rate_reporter_(refresh_rate_reporter) {} double VariableRefreshRateDisplay::GetRefreshRate() const { diff --git a/shell/common/variable_refresh_rate_display.h b/shell/common/variable_refresh_rate_display.h index 475c0d3ea1c77..e0dcd681bf571 100644 --- a/shell/common/variable_refresh_rate_display.h +++ b/shell/common/variable_refresh_rate_display.h @@ -18,7 +18,10 @@ class VariableRefreshRateDisplay : public Display { public: explicit VariableRefreshRateDisplay( DisplayId display_id, - const std::weak_ptr& refresh_rate_reporter); + const std::weak_ptr& refresh_rate_reporter, + double width, + double height, + double device_pixel_ratio); ~VariableRefreshRateDisplay() = default; // |Display| diff --git a/shell/common/variable_refresh_rate_display_unittests.cc b/shell/common/variable_refresh_rate_display_unittests.cc index 3d160b34c1d7e..d9725cf815daf 100644 --- a/shell/common/variable_refresh_rate_display_unittests.cc +++ b/shell/common/variable_refresh_rate_display_unittests.cc @@ -13,14 +13,16 @@ namespace testing { TEST(VariableRefreshRateDisplayTest, ReportCorrectInitialRefreshRate) { auto refresh_rate_reporter = std::make_shared(60); auto display = flutter::VariableRefreshRateDisplay( - 0, std::weak_ptr(refresh_rate_reporter)); + 0, std::weak_ptr(refresh_rate_reporter), 600, + 800, 60); ASSERT_EQ(display.GetRefreshRate(), 60); } TEST(VariableRefreshRateDisplayTest, ReportCorrectRefreshRateWhenUpdated) { auto refresh_rate_reporter = std::make_shared(60); auto display = flutter::VariableRefreshRateDisplay( - 0, std::weak_ptr(refresh_rate_reporter)); + 0, std::weak_ptr(refresh_rate_reporter), 600, + 800, 60); refresh_rate_reporter->UpdateRefreshRate(30); ASSERT_EQ(display.GetRefreshRate(), 30); } @@ -29,7 +31,8 @@ TEST(VariableRefreshRateDisplayTest, Report0IfReporterSharedPointerIsDestroyedAfterDisplayCreation) { auto refresh_rate_reporter = std::make_shared(60); auto display = flutter::VariableRefreshRateDisplay( - 0, std::weak_ptr(refresh_rate_reporter)); + 0, std::weak_ptr(refresh_rate_reporter), 600, + 800, 60); refresh_rate_reporter.reset(); ASSERT_EQ(display.GetRefreshRate(), 0); } @@ -39,7 +42,8 @@ TEST(VariableRefreshRateDisplayTest, auto refresh_rate_reporter = std::make_shared(60); refresh_rate_reporter.reset(); auto display = flutter::VariableRefreshRateDisplay( - 0, std::weak_ptr(refresh_rate_reporter)); + 0, std::weak_ptr(refresh_rate_reporter), 600, + 800, 60); ASSERT_EQ(display.GetRefreshRate(), 0); } diff --git a/shell/platform/android/android_context_gl_unittests.cc b/shell/platform/android/android_context_gl_unittests.cc index bf1c7a78407ec..200b7eb8ff6a5 100644 --- a/shell/platform/android/android_context_gl_unittests.cc +++ b/shell/platform/android/android_context_gl_unittests.cc @@ -58,6 +58,9 @@ class MockPlatformViewAndroidJNI : public PlatformViewAndroidJNI { std::unique_ptr>( std::vector supported_locales_data)); MOCK_METHOD0(GetDisplayRefreshRate, double()); + MOCK_METHOD0(GetDisplayWidth, double()); + MOCK_METHOD0(GetDisplayHeight, double()); + MOCK_METHOD0(GetDisplayDensity, double()); MOCK_METHOD1(RequestDartDeferredLibrary, bool(int loading_unit_id)); }; diff --git a/shell/platform/android/android_display.cc b/shell/platform/android/android_display.cc index edd378bff15d6..9547341957b67 100644 --- a/shell/platform/android/android_display.cc +++ b/shell/platform/android/android_display.cc @@ -3,17 +3,32 @@ // found in the LICENSE file. #include "flutter/shell/platform/android/android_display.h" -#include "android_display.h" namespace flutter { AndroidDisplay::AndroidDisplay( std::shared_ptr jni_facade) - : Display(jni_facade->GetDisplayRefreshRate()), + : Display(0, + jni_facade->GetDisplayRefreshRate(), + jni_facade->GetDisplayWidth(), + jni_facade->GetDisplayHeight(), + jni_facade->GetDisplayDensity()), jni_facade_(std::move(jni_facade)) {} double AndroidDisplay::GetRefreshRate() const { return jni_facade_->GetDisplayRefreshRate(); } +double AndroidDisplay::GetWidth() const { + return jni_facade_->GetDisplayWidth(); +} + +double AndroidDisplay::GetHeight() const { + return jni_facade_->GetDisplayHeight(); +} + +double AndroidDisplay::GetDevicePixelRatio() const { + return jni_facade_->GetDisplayDensity(); +} + } // namespace flutter diff --git a/shell/platform/android/android_display.h b/shell/platform/android/android_display.h index 524779af2f067..495077b1b19bf 100644 --- a/shell/platform/android/android_display.h +++ b/shell/platform/android/android_display.h @@ -16,12 +16,21 @@ namespace flutter { /// A |Display| that listens to refresh rate changes. class AndroidDisplay : public Display { public: - explicit AndroidDisplay(std::shared_ptr jni_facade); + AndroidDisplay(std::shared_ptr jni_facade); ~AndroidDisplay() = default; // |Display| double GetRefreshRate() const override; + // |Display| + virtual double GetWidth() const override; + + // |Display| + virtual double GetHeight() const override; + + // |Display| + virtual double GetDevicePixelRatio() const override; + private: std::shared_ptr jni_facade_; diff --git a/shell/platform/android/android_shell_holder.cc b/shell/platform/android/android_shell_holder.cc index 9a11a97c4513b..eb0733dec62a0 100644 --- a/shell/platform/android/android_shell_holder.cc +++ b/shell/platform/android/android_shell_holder.cc @@ -117,10 +117,6 @@ AndroidShellHolder::AndroidShellHolder( shell.GetSettings().msaa_samples // msaa sample count ); weak_platform_view = platform_view_android->GetWeakPtr(); - std::vector> displays; - displays.push_back(std::make_unique(jni_facade)); - shell.OnDisplayUpdates(DisplayUpdateType::kStartup, - std::move(displays)); return platform_view_android; }; @@ -248,10 +244,6 @@ std::unique_ptr AndroidShellHolder::Spawn( android_context // Android context ); weak_platform_view = platform_view_android->GetWeakPtr(); - std::vector> displays; - displays.push_back(std::make_unique(jni_facade)); - shell.OnDisplayUpdates(DisplayUpdateType::kStartup, - std::move(displays)); return platform_view_android; }; @@ -291,6 +283,7 @@ void AndroidShellHolder::Launch( if (!config) { return; } + UpdateDisplayMetrics(); shell_->RunEngine(std::move(config.value())); } @@ -348,4 +341,10 @@ std::optional AndroidShellHolder::BuildRunConfiguration( return config; } +void AndroidShellHolder::UpdateDisplayMetrics() { + std::vector> displays; + displays.push_back(std::make_unique(jni_facade_)); + shell_->OnDisplayUpdates(DisplayUpdateType::kStartup, std::move(displays)); +} + } // namespace flutter diff --git a/shell/platform/android/android_shell_holder.h b/shell/platform/android/android_shell_holder.h index 06866862f6bf5..30530a896204b 100644 --- a/shell/platform/android/android_shell_holder.h +++ b/shell/platform/android/android_shell_holder.h @@ -103,6 +103,8 @@ class AndroidShellHolder { return shell_->GetPlatformMessageHandler(); } + void UpdateDisplayMetrics(); + private: const flutter::Settings settings_; const std::shared_ptr jni_facade_; diff --git a/shell/platform/android/android_shell_holder_unittests.cc b/shell/platform/android/android_shell_holder_unittests.cc index 85cb352e005f9..fa138c920371b 100644 --- a/shell/platform/android/android_shell_holder_unittests.cc +++ b/shell/platform/android/android_shell_holder_unittests.cc @@ -50,6 +50,9 @@ class MockPlatformViewAndroidJNI : public PlatformViewAndroidJNI { std::unique_ptr>( std::vector supported_locales_data)); MOCK_METHOD0(GetDisplayRefreshRate, double()); + MOCK_METHOD0(GetDisplayWidth, double()); + MOCK_METHOD0(GetDisplayHeight, double()); + MOCK_METHOD0(GetDisplayDensity, double()); MOCK_METHOD1(RequestDartDeferredLibrary, bool(int loading_unit_id)); }; diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterView.java b/shell/platform/android/io/flutter/embedding/android/FlutterView.java index 9bd0022fe356f..45fae9f96456c 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterView.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterView.java @@ -451,6 +451,8 @@ protected void onConfigurationChanged(@NonNull Configuration newConfig) { Log.v(TAG, "Configuration changed. Sending locales and user settings to Flutter."); localizationPlugin.sendLocalesToFlutter(newConfig); sendUserSettingsToFlutter(); + + ViewUtils.calculateMaximumDisplayMetrics(getContext(), flutterEngine); } } diff --git a/shell/platform/android/io/flutter/embedding/engine/FlutterEngine.java b/shell/platform/android/io/flutter/embedding/engine/FlutterEngine.java index bc2902c0281a9..a3a463be04553 100644 --- a/shell/platform/android/io/flutter/embedding/engine/FlutterEngine.java +++ b/shell/platform/android/io/flutter/embedding/engine/FlutterEngine.java @@ -38,6 +38,7 @@ import io.flutter.embedding.engine.systemchannels.TextInputChannel; import io.flutter.plugin.localization.LocalizationPlugin; import io.flutter.plugin.platform.PlatformViewsController; +import io.flutter.util.ViewUtils; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -76,7 +77,7 @@ * {@link DartExecutor} is run. Each Isolate is a self-contained Dart environment and cannot * communicate with each other except via Isolate ports. */ -public class FlutterEngine { +public class FlutterEngine implements ViewUtils.DisplayUpdater { private static final String TAG = "FlutterEngine"; @NonNull private final FlutterJNI flutterJNI; @@ -379,6 +380,8 @@ public FlutterEngine( if (automaticallyRegisterPlugins && flutterLoader.automaticallyRegisterPlugins()) { GeneratedPluginRegister.registerGeneratedPlugins(this); } + + ViewUtils.calculateMaximumDisplayMetrics(context, this); } private void attachToJni() { @@ -645,4 +648,9 @@ public interface EngineLifecycleListener { */ void onEngineWillDestroy(); } + + @Override + public void updateDisplayMetrics(float width, float height, float density) { + flutterJNI.updateDisplayMetrics(0 /* display ID */, width, height, density); + } } diff --git a/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java b/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java index 3a20807bdf1f0..4471d73f0f098 100644 --- a/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java +++ b/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java @@ -214,6 +214,10 @@ public void init( */ private static float refreshRateFPS = 60.0f; + private static float displayWidth = -1.0f; + private static float displayHeight = -1.0f; + private static float displayDensity = -1.0f; + // This is set from native code via JNI. @Nullable private static String vmServiceUri; @@ -274,6 +278,18 @@ public void setRefreshRateFPS(float refreshRateFPS) { updateRefreshRate(); } + public void updateDisplayMetrics(int displayId, float width, float height, float density) { + FlutterJNI.displayWidth = width; + FlutterJNI.displayHeight = height; + FlutterJNI.displayDensity = density; + if (!FlutterJNI.loadLibraryCalled) { + return; + } + nativeUpdateDisplayMetrics(nativeShellHolderId); + } + + private native void nativeUpdateDisplayMetrics(long nativeShellHolderId); + public void updateRefreshRate() { if (!FlutterJNI.loadLibraryCalled) { return; diff --git a/shell/platform/android/io/flutter/util/ViewUtils.java b/shell/platform/android/io/flutter/util/ViewUtils.java index 5baaca2ba549d..7915f28ff427d 100644 --- a/shell/platform/android/io/flutter/util/ViewUtils.java +++ b/shell/platform/android/io/flutter/util/ViewUtils.java @@ -12,8 +12,32 @@ import android.view.ViewGroup; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.window.layout.WindowMetrics; +import androidx.window.layout.WindowMetricsCalculator; public final class ViewUtils { + public interface DisplayUpdater { + /** Publishes display metrics to Dart code in Flutter. */ + public void updateDisplayMetrics(float width, float height, float density); + } + + /** + * Calculates the maximum display metrics for the given context, and pushes the metric data to the + * updater. + */ + public static void calculateMaximumDisplayMetrics( + @Nullable Context context, @NonNull DisplayUpdater updater) { + Activity activity = getActivity(context); + if (activity != null) { + WindowMetrics metrics = + WindowMetricsCalculator.getOrCreate().computeMaximumWindowMetrics(activity); + float width = metrics.getBounds().width(); + float height = metrics.getBounds().height(); + float density = context.getResources().getDisplayMetrics().density; + updater.updateDisplayMetrics(width, height, density); + } + } + /** * Retrieves the {@link Activity} from a given {@link Context}. * diff --git a/shell/platform/android/jni/jni_mock.h b/shell/platform/android/jni/jni_mock.h index aaa52b80d7bd4..b2966e6e67156 100644 --- a/shell/platform/android/jni/jni_mock.h +++ b/shell/platform/android/jni/jni_mock.h @@ -98,6 +98,9 @@ class JNIMock final : public PlatformViewAndroidJNI { (override)); MOCK_METHOD(double, GetDisplayRefreshRate, (), (override)); + MOCK_METHOD(double, GetDisplayWidth, (), (override)); + MOCK_METHOD(double, GetDisplayHeight, (), (override)); + MOCK_METHOD(double, GetDisplayDensity, (), (override)); MOCK_METHOD(bool, RequestDartDeferredLibrary, diff --git a/shell/platform/android/jni/platform_view_android_jni.h b/shell/platform/android/jni/platform_view_android_jni.h index 8e38a385fe771..35e949f0bc9dd 100644 --- a/shell/platform/android/jni/platform_view_android_jni.h +++ b/shell/platform/android/jni/platform_view_android_jni.h @@ -195,6 +195,12 @@ class PlatformViewAndroidJNI { virtual double GetDisplayRefreshRate() = 0; + virtual double GetDisplayWidth() = 0; + + virtual double GetDisplayHeight() = 0; + + virtual double GetDisplayDensity() = 0; + virtual bool RequestDartDeferredLibrary(int loading_unit_id) = 0; }; diff --git a/shell/platform/android/platform_view_android_jni_impl.cc b/shell/platform/android/platform_view_android_jni_impl.cc index 031ec1057eb22..c4580bc0562d7 100644 --- a/shell/platform/android/platform_view_android_jni_impl.cc +++ b/shell/platform/android/platform_view_android_jni_impl.cc @@ -335,11 +335,18 @@ static void SetViewportMetrics(JNIEnv* env, displayFeaturesBounds, displayFeaturesType, displayFeaturesState, + 0, // Display ID }; ANDROID_SHELL_HOLDER->GetPlatformView()->SetViewportMetrics(metrics); } +static void UpdateDisplayMetrics(JNIEnv* env, + jobject jcaller, + jlong shell_holder) { + ANDROID_SHELL_HOLDER->UpdateDisplayMetrics(); +} + static jobject GetBitmap(JNIEnv* env, jobject jcaller, jlong shell_holder) { auto screenshot = ANDROID_SHELL_HOLDER->Screenshot( Rasterizer::ScreenshotType::UncompressedImage, false); @@ -795,6 +802,11 @@ bool RegisterApi(JNIEnv* env) { .signature = "(ILjava/lang/String;Z)V", .fnPtr = reinterpret_cast(&DeferredComponentInstallFailure), }, + { + .name = "nativeUpdateDisplayMetrics", + .signature = "(J)V", + .fnPtr = reinterpret_cast(&UpdateDisplayMetrics), + }, }; if (env->RegisterNatives(g_flutter_jni_class->obj(), flutter_jni_methods, @@ -1622,6 +1634,60 @@ double PlatformViewAndroidJNIImpl::GetDisplayRefreshRate() { return static_cast(env->GetStaticFloatField(clazz.obj(), fid)); } +double PlatformViewAndroidJNIImpl::GetDisplayWidth() { + JNIEnv* env = fml::jni::AttachCurrentThread(); + + auto java_object = java_object_.get(env); + if (java_object.is_null()) { + return -1; + } + + fml::jni::ScopedJavaLocalRef clazz( + env, env->GetObjectClass(java_object.obj())); + if (clazz.is_null()) { + return -1; + } + + jfieldID fid = env->GetStaticFieldID(clazz.obj(), "displayWidth", "F"); + return static_cast(env->GetStaticFloatField(clazz.obj(), fid)); +} + +double PlatformViewAndroidJNIImpl::GetDisplayHeight() { + JNIEnv* env = fml::jni::AttachCurrentThread(); + + auto java_object = java_object_.get(env); + if (java_object.is_null()) { + return -1; + } + + fml::jni::ScopedJavaLocalRef clazz( + env, env->GetObjectClass(java_object.obj())); + if (clazz.is_null()) { + return -1; + } + + jfieldID fid = env->GetStaticFieldID(clazz.obj(), "displayHeight", "F"); + return static_cast(env->GetStaticFloatField(clazz.obj(), fid)); +} + +double PlatformViewAndroidJNIImpl::GetDisplayDensity() { + JNIEnv* env = fml::jni::AttachCurrentThread(); + + auto java_object = java_object_.get(env); + if (java_object.is_null()) { + return -1; + } + + fml::jni::ScopedJavaLocalRef clazz( + env, env->GetObjectClass(java_object.obj())); + if (clazz.is_null()) { + return -1; + } + + jfieldID fid = env->GetStaticFieldID(clazz.obj(), "displayDensity", "F"); + return static_cast(env->GetStaticFloatField(clazz.obj(), fid)); +} + bool PlatformViewAndroidJNIImpl::RequestDartDeferredLibrary( int loading_unit_id) { JNIEnv* env = fml::jni::AttachCurrentThread(); diff --git a/shell/platform/android/platform_view_android_jni_impl.h b/shell/platform/android/platform_view_android_jni_impl.h index b3df5358291fa..6b1e283e812d0 100644 --- a/shell/platform/android/platform_view_android_jni_impl.h +++ b/shell/platform/android/platform_view_android_jni_impl.h @@ -82,6 +82,12 @@ class PlatformViewAndroidJNIImpl final : public PlatformViewAndroidJNI { double GetDisplayRefreshRate() override; + double GetDisplayWidth() override; + + double GetDisplayHeight() override; + + double GetDisplayDensity() override; + bool RequestDartDeferredLibrary(int loading_unit_id) override; private: diff --git a/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm b/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm index 68400d8ccd00f..6913d89cdf8b8 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm @@ -878,7 +878,10 @@ - (void)updateDisplays { auto vsync_waiter = std::shared_ptr(_shell->GetVsyncWaiter().lock()); auto vsync_waiter_ios = std::static_pointer_cast(vsync_waiter); std::vector> displays; - displays.push_back(std::make_unique(0, vsync_waiter_ios)); + auto screen_size = UIScreen.mainScreen.nativeBounds.size; + auto scale = UIScreen.mainScreen.scale; + displays.push_back(std::make_unique( + 0, vsync_waiter_ios, screen_size.width, screen_size.height, scale)); _shell->OnDisplayUpdates(flutter::DisplayUpdateType::kStartup, std::move(displays)); } diff --git a/shell/platform/embedder/embedder.cc b/shell/platform/embedder/embedder.cc index 6e59644216064..1970530e375a8 100644 --- a/shell/platform/embedder/embedder.cc +++ b/shell/platform/embedder/embedder.cc @@ -2998,14 +2998,10 @@ FlutterEngineResult FlutterEngineNotifyDisplayUpdate( case kFlutterEngineDisplaysUpdateTypeStartup: { std::vector> displays; for (size_t i = 0; i < display_count; i++) { - if (embedder_displays[i].single_display) { - displays.push_back(std::make_unique( - embedder_displays[i].refresh_rate)); - } else { - displays.push_back(std::make_unique( - embedder_displays[i].display_id, - embedder_displays[i].refresh_rate)); - } + displays.push_back(std::make_unique( + embedder_displays[i].display_id, embedder_displays[i].refresh_rate, + // TODO(dnfield): Supply real values. + -1, -1, -1)); } engine->GetShell().OnDisplayUpdates(flutter::DisplayUpdateType::kStartup, std::move(displays)); From 7b9f6817d8701e1458ad07939562e19efbaaea30 Mon Sep 17 00:00:00 2001 From: Dan Field Date: Tue, 2 May 2023 21:06:40 -0700 Subject: [PATCH 03/19] web --- lib/web_ui/lib/platform_dispatcher.dart | 2 ++ .../lib/src/engine/platform_dispatcher.dart | 3 ++ lib/web_ui/lib/src/engine/window.dart | 28 +++++++++++++++++++ lib/web_ui/lib/window.dart | 8 ++++++ 4 files changed, 41 insertions(+) diff --git a/lib/web_ui/lib/platform_dispatcher.dart b/lib/web_ui/lib/platform_dispatcher.dart index 75bc01ab38b61..2546404fbacce 100644 --- a/lib/web_ui/lib/platform_dispatcher.dart +++ b/lib/web_ui/lib/platform_dispatcher.dart @@ -29,6 +29,8 @@ abstract class PlatformDispatcher { VoidCallback? get onPlatformConfigurationChanged; set onPlatformConfigurationChanged(VoidCallback? callback); + Iterable get displays; + Iterable get views; FlutterView? get implicitView; diff --git a/lib/web_ui/lib/src/engine/platform_dispatcher.dart b/lib/web_ui/lib/src/engine/platform_dispatcher.dart index ad127afb6c184..b377363d4ac6b 100644 --- a/lib/web_ui/lib/src/engine/platform_dispatcher.dart +++ b/lib/web_ui/lib/src/engine/platform_dispatcher.dart @@ -134,6 +134,9 @@ class EnginePlatformDispatcher extends ui.PlatformDispatcher { _onPlatformConfigurationChanged, _onPlatformConfigurationChangedZone); } + @override + Iterable get displays => []; + /// The current list of windows. @override Iterable get views => viewData.values; diff --git a/lib/web_ui/lib/src/engine/window.dart b/lib/web_ui/lib/src/engine/window.dart index 218ddfea88077..2c163ccdd6334 100644 --- a/lib/web_ui/lib/src/engine/window.dart +++ b/lib/web_ui/lib/src/engine/window.dart @@ -45,6 +45,24 @@ set customUrlStrategy(ui_web.UrlStrategy? strategy) { _customUrlStrategy = strategy; } +class EngineFlutterDisplay extends ui.Display { + const EngineFlutterDisplay({ + required this.id, + required this.devicePixelRatio, + required this.size, + required this.refreshRate, + }); + + @override + final int id; + @override + final double devicePixelRatio; + @override + final ui.Size size; + @override + final double refreshRate; +} + /// The Web implementation of [ui.SingletonFlutterWindow]. class EngineFlutterWindow extends ui.SingletonFlutterWindow { EngineFlutterWindow(this.viewId, this.platformDispatcher) { @@ -62,6 +80,16 @@ class EngineFlutterWindow extends ui.SingletonFlutterWindow { }); } + @override + ui.Display get display { + return EngineFlutterDisplay( + id: 0, + size: ui.Size(domWindow.screen?.width ?? 0, domWindow.screen?.height ?? 0), + devicePixelRatio: domWindow.devicePixelRatio, + refreshRate: 60, + ); + } + @override final Object viewId; diff --git a/lib/web_ui/lib/window.dart b/lib/web_ui/lib/window.dart index b53592964dd99..2cb8750205711 100644 --- a/lib/web_ui/lib/window.dart +++ b/lib/web_ui/lib/window.dart @@ -4,6 +4,13 @@ part of ui; +abstract class Display { + int get id; + double get devicePixelRatio; + Size get size; + double get refreshRate; +} + abstract class FlutterView { PlatformDispatcher get platformDispatcher; Object get viewId; @@ -16,6 +23,7 @@ abstract class FlutterView { ViewPadding get padding; GestureSettings get gestureSettings; List get displayFeatures; + Display get display; void render(Scene scene) => platformDispatcher.render(scene, this); void updateSemantics(SemanticsUpdate update) => platformDispatcher.updateSemantics(update); } From 878dcfbdc48559ff6f18cf164f7d8b7eca58313d Mon Sep 17 00:00:00 2001 From: Dan Field Date: Wed, 3 May 2023 11:42:06 -0700 Subject: [PATCH 04/19] Cleanup, tests for Android/Host/Hooks --- lib/ui/fixtures/ui_test.dart | 43 ++++++++++++++++--- shell/common/display_manager.cc | 11 +---- shell/common/display_manager.h | 14 +----- shell/common/shell.cc | 5 +-- shell/common/shell.h | 3 +- .../platform/android/android_shell_holder.cc | 2 +- .../embedding/engine/FlutterEngine.java | 1 + .../embedding/android/FlutterViewTest.java | 14 ++++++ .../embedding/engine/FlutterEngineTest.java | 18 ++++++++ .../ios/framework/Source/FlutterEngine.mm | 2 +- shell/platform/embedder/embedder.cc | 3 +- shell/testing/tester_main.cc | 16 +++++-- testing/dart/window_test.dart | 10 +++++ 13 files changed, 101 insertions(+), 41 deletions(-) diff --git a/lib/ui/fixtures/ui_test.dart b/lib/ui/fixtures/ui_test.dart index 36f09bf397811..ffb1939a67d09 100644 --- a/lib/ui/fixtures/ui_test.dart +++ b/lib/ui/fixtures/ui_test.dart @@ -6,7 +6,7 @@ import 'dart:async'; import 'dart:typed_data'; import 'dart:ui'; import 'dart:isolate'; -import 'dart:ffi'; +import 'dart:ffi' hide Size; void main() {} @@ -444,7 +444,7 @@ void hooksTests() async { window.onMetricsChanged!(); _callHook( '_updateWindowMetrics', - 20, + 21, 0, // window Id 0.1234, // device pixel ratio 0.0, // width @@ -465,6 +465,7 @@ void hooksTests() async { [], // display features bounds [], // display features types [], // display features states + 0, // Display ID ); expectIdentical(originalZone, callbackZone); @@ -540,7 +541,7 @@ void hooksTests() async { await test('View padding/insets/viewPadding/systemGestureInsets', () { _callHook( '_updateWindowMetrics', - 20, + 21, 0, // window Id 1.0, // devicePixelRatio 800.0, // width @@ -561,6 +562,7 @@ void hooksTests() async { [], // display features bounds [], // display features types [], // display features states + 0, // Display ID ); expectEquals(window.viewInsets.bottom, 0.0); @@ -570,7 +572,7 @@ void hooksTests() async { _callHook( '_updateWindowMetrics', - 20, + 21, 0, // window Id 1.0, // devicePixelRatio 800.0, // width @@ -591,6 +593,7 @@ void hooksTests() async { [], // display features bounds [], // display features types [], // display features states + 0, // Display ID ); expectEquals(window.viewInsets.bottom, 400.0); @@ -602,7 +605,7 @@ void hooksTests() async { await test('Window physical touch slop', () { _callHook( '_updateWindowMetrics', - 20, + 21, 0, // window Id 1.0, // devicePixelRatio 800.0, // width @@ -623,6 +626,7 @@ void hooksTests() async { [], // display features bounds [], // display features types [], // display features states + 0, // Display ID ); expectEquals(window.gestureSettings, @@ -630,7 +634,7 @@ void hooksTests() async { _callHook( '_updateWindowMetrics', - 20, + 21, 0, // window Id 1.0, // devicePixelRatio 800.0, // width @@ -651,6 +655,7 @@ void hooksTests() async { [], // display features bounds [], // display features types [], // display features states + 0, // Display ID ); expectEquals(window.gestureSettings, @@ -658,7 +663,7 @@ void hooksTests() async { _callHook( '_updateWindowMetrics', - 20, + 21, 0, // window Id 1.0, // devicePixelRatio 800.0, // width @@ -679,6 +684,7 @@ void hooksTests() async { [], // display features bounds [], // display features types [], // display features states + 0, // Display ID ); expectEquals(window.gestureSettings, @@ -881,6 +887,28 @@ void hooksTests() async { expectEquals(frameNumber, 2); }); + await test('_updateDisplays preserves callback zone', () { + late Zone innerZone; + late Zone runZone; + late Display display; + + runZoned(() { + innerZone = Zone.current; + window.onMetricsChanged = () { + runZone = Zone.current; + display = PlatformDispatcher.instance.displays.first; + }; + }); + + _callHook('_updateDisplays', 4, [0], [800, 600], [1.5], [65]); + expectNotEquals(runZone, null); + expectIdentical(runZone, innerZone); + expectEquals(display.id, 0); + expectEquals(display.size, const Size(800, 600)); + expectEquals(display.devicePixelRatio, 1.5); + expectEquals(display.refreshRate, 65); + }); + await test('_futureize handles callbacker sync error', () async { String? callbacker(void Function(Object? arg) cb) { return 'failure'; @@ -1043,4 +1071,5 @@ external void _callHook( Object? arg18, Object? arg19, Object? arg20, + Object? arg21, ]); diff --git a/shell/common/display_manager.cc b/shell/common/display_manager.cc index 8b4c53f4b2b90..e9382028dc626 100644 --- a/shell/common/display_manager.cc +++ b/shell/common/display_manager.cc @@ -23,17 +23,10 @@ double DisplayManager::GetMainDisplayRefreshRate() const { } void DisplayManager::HandleDisplayUpdates( - DisplayUpdateType update_type, std::vector> displays) { + FML_DCHECK(!displays.empty()); std::scoped_lock lock(displays_mutex_); - FML_CHECK(!displays.empty()); - switch (update_type) { - case DisplayUpdateType::kStartup: - displays_ = std::move(displays); - return; - default: - FML_CHECK(false) << "Unknown DisplayUpdateType."; - } + displays_ = std::move(displays); } } // namespace flutter diff --git a/shell/common/display_manager.h b/shell/common/display_manager.h index 126b318b50f64..ae3e9d0a5607e 100644 --- a/shell/common/display_manager.h +++ b/shell/common/display_manager.h @@ -12,17 +12,6 @@ namespace flutter { -/// The update type parameter that is passed to -/// `DisplayManager::HandleDisplayUpdates`. -enum class DisplayUpdateType { - /// `flutter::Display`s that were active during start-up. A display is - /// considered active if: - /// 1. The frame buffer hardware is connected. - /// 2. The display is drawable, e.g. it isn't being mirrored from another - /// connected display or sleeping. - kStartup -}; - /// Manages lifecycle of the connected displays. This class is thread-safe. class DisplayManager { public: @@ -39,8 +28,7 @@ class DisplayManager { double GetMainDisplayRefreshRate() const; /// Handles the display updates. - void HandleDisplayUpdates(DisplayUpdateType update_type, - std::vector> displays); + void HandleDisplayUpdates(std::vector> displays); private: /// Guards `displays_` vector. diff --git a/shell/common/shell.cc b/shell/common/shell.cc index 9f87d5e93def4..f69382826c0eb 100644 --- a/shell/common/shell.cc +++ b/shell/common/shell.cc @@ -2071,8 +2071,7 @@ void Shell::SetGpuAvailability(GpuAvailability availability) { } } -void Shell::OnDisplayUpdates(DisplayUpdateType update_type, - std::vector> displays) { +void Shell::OnDisplayUpdates(std::vector> displays) { FML_DCHECK(is_setup_); std::vector display_data; for (const auto& display : displays) { @@ -2086,7 +2085,7 @@ void Shell::OnDisplayUpdates(DisplayUpdateType update_type, } }); - display_manager_->HandleDisplayUpdates(update_type, std::move(displays)); + display_manager_->HandleDisplayUpdates(std::move(displays)); } fml::TimePoint Shell::GetCurrentTimePoint() { diff --git a/shell/common/shell.h b/shell/common/shell.h index 2ecf71dac6559..b0c474c722281 100644 --- a/shell/common/shell.h +++ b/shell/common/shell.h @@ -374,8 +374,7 @@ class Shell final : public PlatformView::Delegate, //---------------------------------------------------------------------------- /// @brief Notifies the display manager of the updates. /// - void OnDisplayUpdates(DisplayUpdateType update_type, - std::vector> displays); + void OnDisplayUpdates(std::vector> displays); //---------------------------------------------------------------------------- /// @brief Queries the `DisplayManager` for the main display refresh rate. diff --git a/shell/platform/android/android_shell_holder.cc b/shell/platform/android/android_shell_holder.cc index eb0733dec62a0..becc6861a6060 100644 --- a/shell/platform/android/android_shell_holder.cc +++ b/shell/platform/android/android_shell_holder.cc @@ -344,7 +344,7 @@ std::optional AndroidShellHolder::BuildRunConfiguration( void AndroidShellHolder::UpdateDisplayMetrics() { std::vector> displays; displays.push_back(std::make_unique(jni_facade_)); - shell_->OnDisplayUpdates(DisplayUpdateType::kStartup, std::move(displays)); + shell_->OnDisplayUpdates(std::move(displays)); } } // namespace flutter diff --git a/shell/platform/android/io/flutter/embedding/engine/FlutterEngine.java b/shell/platform/android/io/flutter/embedding/engine/FlutterEngine.java index a3a463be04553..265181a234b29 100644 --- a/shell/platform/android/io/flutter/embedding/engine/FlutterEngine.java +++ b/shell/platform/android/io/flutter/embedding/engine/FlutterEngine.java @@ -651,6 +651,7 @@ public interface EngineLifecycleListener { @Override public void updateDisplayMetrics(float width, float height, float density) { + System.out.writeln("HERE"); flutterJNI.updateDisplayMetrics(0 /* display ID */, width, height, density); } } diff --git a/shell/platform/android/test/io/flutter/embedding/android/FlutterViewTest.java b/shell/platform/android/test/io/flutter/embedding/android/FlutterViewTest.java index 41337f0c30b3d..5371e05b58bbf 100644 --- a/shell/platform/android/test/io/flutter/embedding/android/FlutterViewTest.java +++ b/shell/platform/android/test/io/flutter/embedding/android/FlutterViewTest.java @@ -227,6 +227,20 @@ public void onConfigurationChanged_fizzlesWhenNullEngine() { verify(flutterEngine, times(2)).getSettingsChannel(); } + @Test + public void onConfigurationChanged_notifiesEngineOfDisplaySize() { + FlutterView flutterView = new FlutterView(Robolectric.setupActivity(Activity.class)); + FlutterEngine flutterEngine = spy(new FlutterEngine(ctx, mockFlutterLoader, mockFlutterJni)); + + Configuration configuration = ctx.getResources().getConfiguration(); + + flutterView.attachToFlutterEngine(flutterEngine); + flutterView.onConfigurationChanged(configuration); + + verify(flutterEngine, times(1)) + .updateDisplayMetrics(any(Float.class), any(Float.class), any(Float.class)); + } + // TODO(mattcarroll): turn this into an e2e test. GitHub #42990 @Test public void itSendsLightPlatformBrightnessToFlutter() { diff --git a/shell/platform/android/test/io/flutter/embedding/engine/FlutterEngineTest.java b/shell/platform/android/test/io/flutter/embedding/engine/FlutterEngineTest.java index cc7a8e5fee999..c1b049b89ecd5 100644 --- a/shell/platform/android/test/io/flutter/embedding/engine/FlutterEngineTest.java +++ b/shell/platform/android/test/io/flutter/embedding/engine/FlutterEngineTest.java @@ -15,6 +15,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.app.Activity; import android.content.Context; import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Configuration; @@ -42,6 +43,8 @@ import org.mockito.MockitoAnnotations; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; +import org.robolectric.Robolectric; +import org.robolectric.android.controller.ActivityController; import org.robolectric.annotation.Config; import org.robolectric.shadows.ShadowLog; @@ -98,6 +101,21 @@ public void itAutomaticallyRegistersPluginsByDefault() { assertEquals(flutterEngine, registeredEngines.get(0)); } + @Test + public void itUpdatesDisplayMetricsOnConstructionWithActivityContext() { + // Needs an activity. ApplicationContext won't work for this. + ActivityController activityController = Robolectric.buildActivity(Activity.class); + FlutterJNI mockFlutterJNI = mock(FlutterJNI.class); + when(mockFlutterJNI.isAttached()).thenReturn(true); + + FlutterLoader mockFlutterLoader = mock(FlutterLoader.class); + FlutterEngine flutterEngine = + new FlutterEngine(activityController.get(), mockFlutterLoader, mockFlutterJNI); + + verify(mockFlutterJNI, times(1)) + .updateDisplayMetrics(eq(0), any(Float.class), any(Float.class), any(Float.class)); + } + @Test public void itSendLocalesOnEngineInit() { FlutterJNI mockFlutterJNI = mock(FlutterJNI.class); diff --git a/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm b/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm index 6913d89cdf8b8..991944f33a6d3 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm @@ -882,7 +882,7 @@ - (void)updateDisplays { auto scale = UIScreen.mainScreen.scale; displays.push_back(std::make_unique( 0, vsync_waiter_ios, screen_size.width, screen_size.height, scale)); - _shell->OnDisplayUpdates(flutter::DisplayUpdateType::kStartup, std::move(displays)); + _shell->OnDisplayUpdates(std::move(displays)); } - (BOOL)run { diff --git a/shell/platform/embedder/embedder.cc b/shell/platform/embedder/embedder.cc index 1970530e375a8..94c436be23bd4 100644 --- a/shell/platform/embedder/embedder.cc +++ b/shell/platform/embedder/embedder.cc @@ -3003,8 +3003,7 @@ FlutterEngineResult FlutterEngineNotifyDisplayUpdate( // TODO(dnfield): Supply real values. -1, -1, -1)); } - engine->GetShell().OnDisplayUpdates(flutter::DisplayUpdateType::kStartup, - std::move(displays)); + engine->GetShell().OnDisplayUpdates(std::move(displays)); return kSuccess; } default: diff --git a/shell/testing/tester_main.cc b/shell/testing/tester_main.cc index 7fb8fa1d523d3..c1058543b068e 100644 --- a/shell/testing/tester_main.cc +++ b/shell/testing/tester_main.cc @@ -339,10 +339,20 @@ int RunTester(const flutter::Settings& settings, } }); + auto device_pixel_ratio = 3.0; + auto physical_width = 2400.0; // 800 at 3x resolution. + auto physical_height = 1800.0; // 600 at 3x resolution. + + std::vector> displays; + displays.push_back(std::make_unique( + 0, 60, physical_width, physical_height, device_pixel_ratio)); + shell->OnDisplayUpdates(std::move(displays)); + flutter::ViewportMetrics metrics{}; - metrics.device_pixel_ratio = 3.0; - metrics.physical_width = 2400.0; // 800 at 3x resolution. - metrics.physical_height = 1800.0; // 600 at 3x resolution. + metrics.device_pixel_ratio = device_pixel_ratio; + metrics.physical_width = physical_width; + metrics.physical_height = physical_height; + metrics.display_id = 0; shell->GetPlatformView()->SetViewportMetrics(metrics); // Run the message loop and wait for the script to do its thing. diff --git a/testing/dart/window_test.dart b/testing/dart/window_test.dart index 018c72a575154..f51c6501cf29c 100644 --- a/testing/dart/window_test.dart +++ b/testing/dart/window_test.dart @@ -79,4 +79,14 @@ void main() { final Locale? result = PlatformDispatcher.instance.computePlatformResolvedLocale(supportedLocales); expect(result, null); }); + + test('Display is configured for the implicitView', () { + final FlutterView implicitView = PlatformDispatcher.instance.implicitView!; + final Display display = implicitView.display; + + expect(display.id, 0); + expect(display.devicePixelRatio, implicitView.devicePixelRatio); + expect(display.refreshRate, 60); + expect(display.size, implicitView.physicalSize); + }); } From 6f1a0bb94736fe69975705d57413d9fdc8624fb0 Mon Sep 17 00:00:00 2001 From: Dan Field Date: Wed, 3 May 2023 11:44:14 -0700 Subject: [PATCH 05/19] scenario app --- testing/scenario_app/lib/main.dart | 3 +++ 1 file changed, 3 insertions(+) diff --git a/testing/scenario_app/lib/main.dart b/testing/scenario_app/lib/main.dart index d45760c62d9c9..22a6466297639 100644 --- a/testing/scenario_app/lib/main.dart +++ b/testing/scenario_app/lib/main.dart @@ -24,6 +24,9 @@ void main() { ..onPointerDataPacket = _onPointerDataPacket ..scheduleFrame(); + final FlutterView view = PlatformDispatcher.instance.implicitView!; + assert(view.display.size == view.physicalSize); + final ByteData data = ByteData(1); data.setUint8(0, 1); PlatformDispatcher.instance.sendPlatformMessage('waiting_for_status', data, null); From 123deaf1fe86863f6a65e9f28f54e8bc2e33da7e Mon Sep 17 00:00:00 2001 From: Dan Field Date: Wed, 3 May 2023 11:50:08 -0700 Subject: [PATCH 06/19] oops --- .../android/io/flutter/embedding/engine/FlutterEngine.java | 1 - 1 file changed, 1 deletion(-) diff --git a/shell/platform/android/io/flutter/embedding/engine/FlutterEngine.java b/shell/platform/android/io/flutter/embedding/engine/FlutterEngine.java index 265181a234b29..a3a463be04553 100644 --- a/shell/platform/android/io/flutter/embedding/engine/FlutterEngine.java +++ b/shell/platform/android/io/flutter/embedding/engine/FlutterEngine.java @@ -651,7 +651,6 @@ public interface EngineLifecycleListener { @Override public void updateDisplayMetrics(float width, float height, float density) { - System.out.writeln("HERE"); flutterJNI.updateDisplayMetrics(0 /* display ID */, width, height, density); } } From d0224c98d435952208cc5c1fd06796b8872d636d Mon Sep 17 00:00:00 2001 From: Dan Field Date: Wed, 3 May 2023 13:57:16 -0700 Subject: [PATCH 07/19] One more DCHECK --- shell/common/shell.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/shell/common/shell.cc b/shell/common/shell.cc index f69382826c0eb..47ce821e8973d 100644 --- a/shell/common/shell.cc +++ b/shell/common/shell.cc @@ -2073,6 +2073,8 @@ void Shell::SetGpuAvailability(GpuAvailability availability) { void Shell::OnDisplayUpdates(std::vector> displays) { FML_DCHECK(is_setup_); + FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread()); + std::vector display_data; for (const auto& display : displays) { display_data.push_back(display->GetDisplayData()); From 67958edf8acb3f0ee5bfad97c18ae3d3f11074ef Mon Sep 17 00:00:00 2001 From: Dan Field Date: Wed, 3 May 2023 14:11:56 -0700 Subject: [PATCH 08/19] web, fucshia build failures --- lib/web_ui/lib/src/engine/window.dart | 2 +- shell/platform/fuchsia/flutter/flatland_platform_view.cc | 1 + shell/platform/fuchsia/flutter/gfx_platform_view.cc | 1 + .../flutter/tests/flatland_platform_view_unittest.cc | 6 ++++-- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/web_ui/lib/src/engine/window.dart b/lib/web_ui/lib/src/engine/window.dart index 2c163ccdd6334..903f6135a458e 100644 --- a/lib/web_ui/lib/src/engine/window.dart +++ b/lib/web_ui/lib/src/engine/window.dart @@ -46,7 +46,7 @@ set customUrlStrategy(ui_web.UrlStrategy? strategy) { } class EngineFlutterDisplay extends ui.Display { - const EngineFlutterDisplay({ + EngineFlutterDisplay({ required this.id, required this.devicePixelRatio, required this.size, diff --git a/shell/platform/fuchsia/flutter/flatland_platform_view.cc b/shell/platform/fuchsia/flutter/flatland_platform_view.cc index e6cd12805bf1d..946ec867d5e52 100644 --- a/shell/platform/fuchsia/flutter/flatland_platform_view.cc +++ b/shell/platform/fuchsia/flutter/flatland_platform_view.cc @@ -105,6 +105,7 @@ void FlatlandPlatformView::OnGetLayout( {}, // p_physical_display_features_bounds {}, // p_physical_display_features_type {}, // p_physical_display_features_state + 0, // p_display_id }); parent_viewport_watcher_->GetLayout( diff --git a/shell/platform/fuchsia/flutter/gfx_platform_view.cc b/shell/platform/fuchsia/flutter/gfx_platform_view.cc index ed9eeece151a0..fc96059c2a5e1 100644 --- a/shell/platform/fuchsia/flutter/gfx_platform_view.cc +++ b/shell/platform/fuchsia/flutter/gfx_platform_view.cc @@ -231,6 +231,7 @@ void GfxPlatformView::OnScenicEvent( {}, // p_physical_display_features_bounds {}, // p_physical_display_features_type {}, // p_physical_display_features_state + 0, // pdisplay_id }); } } diff --git a/shell/platform/fuchsia/flutter/tests/flatland_platform_view_unittest.cc b/shell/platform/fuchsia/flutter/tests/flatland_platform_view_unittest.cc index c1ffbcd96ab66..6faeeaab5cca6 100644 --- a/shell/platform/fuchsia/flutter/tests/flatland_platform_view_unittest.cc +++ b/shell/platform/fuchsia/flutter/tests/flatland_platform_view_unittest.cc @@ -660,7 +660,8 @@ TEST_F(FlatlandPlatformViewTests, SetViewportMetrics) { RunLoopUntilIdle(); EXPECT_EQ(delegate.metrics(), flutter::ViewportMetrics(kDPR, std::round(width * kDPR), - std::round(height * kDPR), -1.0)); + std::round(height * kDPR), -1.0), + 0); } // This test makes sure that the PlatformView correctly registers semantics @@ -1496,7 +1497,8 @@ TEST_F(FlatlandPlatformViewTests, TouchSourceLogicalToPhysicalConversion) { viewport_watcher.SetLayout(width, height); RunLoopUntilIdle(); - EXPECT_EQ(delegate.metrics(), flutter::ViewportMetrics(1, width, height, -1)); + EXPECT_EQ(delegate.metrics(), + flutter::ViewportMetrics(1, width, height, -1, 0)); // Inject std::vector events = From 3e87708fc4fb1843dbdb172d71649f4b27d0908f Mon Sep 17 00:00:00 2001 From: Dan Field Date: Wed, 3 May 2023 14:28:30 -0700 Subject: [PATCH 09/19] one more spot for Fuchsia --- DEPS | 2 +- shell/platform/fuchsia/flutter/platform_view_unittest.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index b476d0cdf6820..526c28a75c08f 100644 --- a/DEPS +++ b/DEPS @@ -28,7 +28,7 @@ vars = { # This prevents us from downloading the Emscripten toolchain for builds # which do not build for the web. This toolchain is needed to build CanvasKit # for the web engine. - 'download_emsdk': False, + 'download_emsdk': True, # For experimental features some dependencies may only be avaialable in the master/main # channels. This variable is being set when CI is checking out the repository. diff --git a/shell/platform/fuchsia/flutter/platform_view_unittest.cc b/shell/platform/fuchsia/flutter/platform_view_unittest.cc index 624ad33b51699..35ba5805d80e8 100644 --- a/shell/platform/fuchsia/flutter/platform_view_unittest.cc +++ b/shell/platform/fuchsia/flutter/platform_view_unittest.cc @@ -636,7 +636,7 @@ TEST_F(PlatformViewTests, SetViewportMetrics) { delegate.metrics(), flutter::ViewportMetrics( valid_pixel_ratio, std::round(valid_pixel_ratio * valid_max_bound), - std::round(valid_pixel_ratio * valid_max_bound), -1.0)); + std::round(valid_pixel_ratio * valid_max_bound), -1.0, 0)); } // This test makes sure that the PlatformView correctly registers semantics From 806a4aebac21e91c5d507f2355c55d23c441319b Mon Sep 17 00:00:00 2001 From: Dan Field Date: Wed, 3 May 2023 14:29:23 -0700 Subject: [PATCH 10/19] lint --- shell/common/shell.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shell/common/shell.cc b/shell/common/shell.cc index 47ce821e8973d..00f97e187dc9e 100644 --- a/shell/common/shell.cc +++ b/shell/common/shell.cc @@ -2083,7 +2083,7 @@ void Shell::OnDisplayUpdates(std::vector> displays) { [engine = engine_->GetWeakPtr(), display_data = std::move(display_data)]() { if (engine) { - engine->SetDisplays(std::move(display_data)); + engine->SetDisplays(display_data); } }); From 5f2e0c12a74edf95e4f4a5bc16466c8a47622b8a Mon Sep 17 00:00:00 2001 From: Dan Field Date: Wed, 3 May 2023 14:30:32 -0700 Subject: [PATCH 11/19] accidental change --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 526c28a75c08f..b476d0cdf6820 100644 --- a/DEPS +++ b/DEPS @@ -28,7 +28,7 @@ vars = { # This prevents us from downloading the Emscripten toolchain for builds # which do not build for the web. This toolchain is needed to build CanvasKit # for the web engine. - 'download_emsdk': True, + 'download_emsdk': False, # For experimental features some dependencies may only be avaialable in the master/main # channels. This variable is being set when CI is checking out the repository. From be4731db985bd1eaada557abbbb7173809ccc3ec Mon Sep 17 00:00:00 2001 From: Dan Field Date: Wed, 3 May 2023 14:52:32 -0700 Subject: [PATCH 12/19] Once more, with feeling --- lib/web_ui/lib/src/engine/dom.dart | 3 +++ .../fuchsia/flutter/tests/flatland_platform_view_unittest.cc | 3 +-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/web_ui/lib/src/engine/dom.dart b/lib/web_ui/lib/src/engine/dom.dart index ca7056d05672b..90de2bda8d364 100644 --- a/lib/web_ui/lib/src/engine/dom.dart +++ b/lib/web_ui/lib/src/engine/dom.dart @@ -2822,6 +2822,9 @@ class DomScreen {} extension DomScreenExtension on DomScreen { external DomScreenOrientation? get orientation; + + external double get width; + external double get height; } @JS() diff --git a/shell/platform/fuchsia/flutter/tests/flatland_platform_view_unittest.cc b/shell/platform/fuchsia/flutter/tests/flatland_platform_view_unittest.cc index 6faeeaab5cca6..a7ef860f95b66 100644 --- a/shell/platform/fuchsia/flutter/tests/flatland_platform_view_unittest.cc +++ b/shell/platform/fuchsia/flutter/tests/flatland_platform_view_unittest.cc @@ -660,8 +660,7 @@ TEST_F(FlatlandPlatformViewTests, SetViewportMetrics) { RunLoopUntilIdle(); EXPECT_EQ(delegate.metrics(), flutter::ViewportMetrics(kDPR, std::round(width * kDPR), - std::round(height * kDPR), -1.0), - 0); + std::round(height * kDPR), -1.0, 0)); } // This test makes sure that the PlatformView correctly registers semantics From 200f0919995dcca51634c0d7eaf86a40db69d2d8 Mon Sep 17 00:00:00 2001 From: Dan Field Date: Wed, 3 May 2023 15:34:35 -0700 Subject: [PATCH 13/19] Tidying, last Fuchsia test compilation issue --- lib/ui/window/platform_configuration.cc | 3 ++- lib/ui/window/platform_configuration.h | 2 +- runtime/runtime_controller.cc | 4 ++-- runtime/runtime_controller.h | 2 +- shell/common/engine.cc | 4 ++-- shell/common/engine.h | 2 +- shell/platform/fuchsia/flutter/platform_view_unittest.cc | 3 ++- 7 files changed, 11 insertions(+), 9 deletions(-) diff --git a/lib/ui/window/platform_configuration.cc b/lib/ui/window/platform_configuration.cc index e10903a14305c..83291020a6d94 100644 --- a/lib/ui/window/platform_configuration.cc +++ b/lib/ui/window/platform_configuration.cc @@ -84,7 +84,8 @@ void PlatformConfiguration::DidCreateIsolate() { kImplicitViewId, ViewportMetrics{1.0, 0.0, 0.0, -1, 0})); } -void PlatformConfiguration::UpdateDisplays(std::vector displays) { +void PlatformConfiguration::UpdateDisplays( + const std::vector& displays) { std::vector ids; std::vector sizes; std::vector device_pixel_ratios; diff --git a/lib/ui/window/platform_configuration.h b/lib/ui/window/platform_configuration.h index 63367d75da28e..23e13acdfa18d 100644 --- a/lib/ui/window/platform_configuration.h +++ b/lib/ui/window/platform_configuration.h @@ -274,7 +274,7 @@ class PlatformConfiguration final { /// @param[in] locale_data The locale data. This should consist of groups of /// 4 strings, each group representing a single locale. /// - void UpdateDisplays(std::vector displays); + void UpdateDisplays(const std::vector& displays); //---------------------------------------------------------------------------- /// @brief Update the specified locale data in the framework. diff --git a/runtime/runtime_controller.cc b/runtime/runtime_controller.cc index 0f6207aad901c..5f5fb87c0bc40 100644 --- a/runtime/runtime_controller.cc +++ b/runtime/runtime_controller.cc @@ -500,12 +500,12 @@ void RuntimeController::RequestDartDeferredLibrary(intptr_t loading_unit_id) { return client_.RequestDartDeferredLibrary(loading_unit_id); } -bool RuntimeController::SetDisplays(std::vector displays) { +bool RuntimeController::SetDisplays(const std::vector& displays) { TRACE_EVENT0("flutter", "SetDisplays"); platform_data_.displays = displays; if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) { - platform_configuration->UpdateDisplays(std::move(displays)); + platform_configuration->UpdateDisplays(displays); return true; } return false; diff --git a/runtime/runtime_controller.h b/runtime/runtime_controller.h index 810936e8320fd..1df085262f605 100644 --- a/runtime/runtime_controller.h +++ b/runtime/runtime_controller.h @@ -180,7 +180,7 @@ class RuntimeController : public PlatformConfigurationClient { /// flushed to the isolate when it starts. /// /// @param[in] displays The available displays. - bool SetDisplays(std::vector displays); + bool SetDisplays(const std::vector& displays); //---------------------------------------------------------------------------- /// @brief Forward the specified locale data to the running isolate. If diff --git a/shell/common/engine.cc b/shell/common/engine.cc index 57604ec18c853..d87598baef8fd 100644 --- a/shell/common/engine.cc +++ b/shell/common/engine.cc @@ -583,8 +583,8 @@ const std::weak_ptr Engine::GetVsyncWaiter() const { return animator_->GetVsyncWaiter(); } -void Engine::SetDisplays(std::vector displays) { - runtime_controller_->SetDisplays(std::move(displays)); +void Engine::SetDisplays(const std::vector& displays) { + runtime_controller_->SetDisplays(displays); ScheduleFrame(); } diff --git a/shell/common/engine.h b/shell/common/engine.h index 63706ffe64a47..1013b5e8e3db4 100644 --- a/shell/common/engine.h +++ b/shell/common/engine.h @@ -691,7 +691,7 @@ class Engine final : public RuntimeDelegate, PointerDataDispatcher::Delegate { /// /// @param[in] displays A complete list of displays /// - void SetDisplays(std::vector displays); + void SetDisplays(const std::vector& displays); //---------------------------------------------------------------------------- /// @brief Notifies the engine that the embedder has sent it a message. diff --git a/shell/platform/fuchsia/flutter/platform_view_unittest.cc b/shell/platform/fuchsia/flutter/platform_view_unittest.cc index 35ba5805d80e8..fc883b5c8b22c 100644 --- a/shell/platform/fuchsia/flutter/platform_view_unittest.cc +++ b/shell/platform/fuchsia/flutter/platform_view_unittest.cc @@ -1447,7 +1447,8 @@ TEST_F(PlatformViewTests, TouchSourceLogicalToPhysicalConversion) { }))); session_listener->OnScenicEvent(std::move(scenic_events)); RunLoopUntilIdle(); - EXPECT_EQ(delegate.metrics(), flutter::ViewportMetrics(2.f, 40.f, 40.f, -1)); + EXPECT_EQ(delegate.metrics(), + flutter::ViewportMetrics(2.f, 40.f, 40.f, -1, 0)); // Inject std::vector events = From ea76da6415bf1bb18190bc079e3f0cd38ad64978 Mon Sep 17 00:00:00 2001 From: Dan Field Date: Wed, 3 May 2023 16:17:48 -0700 Subject: [PATCH 14/19] Loic review --- lib/ui/fixtures/ui_test.dart | 2 +- lib/ui/hooks.dart | 10 +++++++--- lib/ui/window/platform_configuration.cc | 10 ++++++---- lib/ui/window/platform_configuration.h | 3 +-- shell/platform/embedder/embedder.cc | 3 ++- 5 files changed, 17 insertions(+), 11 deletions(-) diff --git a/lib/ui/fixtures/ui_test.dart b/lib/ui/fixtures/ui_test.dart index ffb1939a67d09..6658948e422f2 100644 --- a/lib/ui/fixtures/ui_test.dart +++ b/lib/ui/fixtures/ui_test.dart @@ -900,7 +900,7 @@ void hooksTests() async { }; }); - _callHook('_updateDisplays', 4, [0], [800, 600], [1.5], [65]); + _callHook('_updateDisplays', 5, [0], [800], [600], [1.5], [65]); expectNotEquals(runZone, null); expectIdentical(runZone, innerZone); expectEquals(display.id, 0); diff --git a/lib/ui/hooks.dart b/lib/ui/hooks.dart index c22255be587fb..5d5f129021412 100644 --- a/lib/ui/hooks.dart +++ b/lib/ui/hooks.dart @@ -7,17 +7,21 @@ part of dart.ui; @pragma('vm:entry-point') void _updateDisplays( List ids, - List sizes, + List widths, + List heights, List devicePixelRatios, List refreshRates, ) { + assert(ids.length == widths.length); + assert(ids.length == heights.length); + assert(ids.length == devicePixelRatios.length); + assert(ids.length == refreshRates.length); final List displays = []; - int sizeIndex = 0; for (int index = 0; index < ids.length; index += 1) { final int displayId = ids[index]; displays.add(Display._( id: displayId, - size: Size(sizes[sizeIndex++], sizes[sizeIndex++]), + size: Size(widths[index], heights[index]), devicePixelRatio: devicePixelRatios[index], refreshRate: refreshRates[index], )); diff --git a/lib/ui/window/platform_configuration.cc b/lib/ui/window/platform_configuration.cc index 83291020a6d94..b1cd11fad30e7 100644 --- a/lib/ui/window/platform_configuration.cc +++ b/lib/ui/window/platform_configuration.cc @@ -87,13 +87,14 @@ void PlatformConfiguration::DidCreateIsolate() { void PlatformConfiguration::UpdateDisplays( const std::vector& displays) { std::vector ids; - std::vector sizes; + std::vector widths; + std::vector heights; std::vector device_pixel_ratios; std::vector refresh_rates; for (const auto& display : displays) { ids.push_back(display.id); - sizes.push_back(display.width); - sizes.push_back(display.height); + widths.push_back(display.width); + heights.push_back(display.height); device_pixel_ratios.push_back(display.pixel_ratio); refresh_rates.push_back(display.refresh_rate); } @@ -107,7 +108,8 @@ void PlatformConfiguration::UpdateDisplays( update_displays_.Get(), { tonic::ToDart>(ids), - tonic::ToDart>(sizes), + tonic::ToDart>(widths), + tonic::ToDart>(heights), tonic::ToDart>(device_pixel_ratios), tonic::ToDart>(refresh_rates), })); diff --git a/lib/ui/window/platform_configuration.h b/lib/ui/window/platform_configuration.h index 23e13acdfa18d..c03f38194bf50 100644 --- a/lib/ui/window/platform_configuration.h +++ b/lib/ui/window/platform_configuration.h @@ -271,8 +271,7 @@ class PlatformConfiguration final { //---------------------------------------------------------------------------- /// @brief Update the specified display data in the framework. /// - /// @param[in] locale_data The locale data. This should consist of groups of - /// 4 strings, each group representing a single locale. + /// @param[in] displays The display data to send to Dart. /// void UpdateDisplays(const std::vector& displays); diff --git a/shell/platform/embedder/embedder.cc b/shell/platform/embedder/embedder.cc index 94c436be23bd4..876e8f3529351 100644 --- a/shell/platform/embedder/embedder.cc +++ b/shell/platform/embedder/embedder.cc @@ -3000,7 +3000,8 @@ FlutterEngineResult FlutterEngineNotifyDisplayUpdate( for (size_t i = 0; i < display_count; i++) { displays.push_back(std::make_unique( embedder_displays[i].display_id, embedder_displays[i].refresh_rate, - // TODO(dnfield): Supply real values. + // TODO(dnfield): Supply real values + // https://github.com/flutter/flutter/issues/125939 -1, -1, -1)); } engine->GetShell().OnDisplayUpdates(std::move(displays)); From fc3b8f4ab27fbd3ea34cbd13258dd52ae944da95 Mon Sep 17 00:00:00 2001 From: Dan Field Date: Wed, 3 May 2023 17:16:11 -0700 Subject: [PATCH 15/19] Fix failing test, add unit test for FlutterEngine.mm --- shell/common/shell.cc | 3 +++ .../darwin/ios/framework/Source/FlutterEngine.mm | 6 +++++- .../darwin/ios/framework/Source/FlutterEngineTest.mm | 10 ++++++++++ .../darwin/ios/framework/Source/FlutterEngine_Test.h | 1 + 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/shell/common/shell.cc b/shell/common/shell.cc index 00f97e187dc9e..3fb24ae421a8b 100644 --- a/shell/common/shell.cc +++ b/shell/common/shell.cc @@ -2100,6 +2100,9 @@ Shell::GetPlatformMessageHandler() const { } const std::weak_ptr Shell::GetVsyncWaiter() const { + if (!engine_) { + return {}; + } return engine_->GetVsyncWaiter(); } diff --git a/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm b/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm index 991944f33a6d3..a124d2b0296a4 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm @@ -875,7 +875,11 @@ - (BOOL)createShell:(NSString*)entrypoint } - (void)updateDisplays { - auto vsync_waiter = std::shared_ptr(_shell->GetVsyncWaiter().lock()); + if (!_shell) { + // Tests may do this. + return; + } + auto vsync_waiter = _shell->GetVsyncWaiter().lock(); auto vsync_waiter_ios = std::static_pointer_cast(vsync_waiter); std::vector> displays; auto screen_size = UIScreen.mainScreen.nativeBounds.size; diff --git a/shell/platform/darwin/ios/framework/Source/FlutterEngineTest.mm b/shell/platform/darwin/ios/framework/Source/FlutterEngineTest.mm index b4dfb9502f511..2d55b14826692 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterEngineTest.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterEngineTest.mm @@ -331,4 +331,14 @@ - (void)testFlutterTextInputViewDidResignFirstResponderWillCallTextInputClientCo OCMVerify([mockBinaryMessenger sendOnChannel:@"flutter/textinput" message:encodedMethodCall]); } +- (void)testFlutterEngineUpdatesDisplays { + FlutterEngine* engine = [[FlutterEngine alloc] init]; + id mockEngine = OCMPartialMock(engine); + + [engine run]; + OCMVerify(times(1), [mockEngine updateDisplays]); + engine.viewController = nil; + OCMVerify(times(2), [mockEngine updateDisplays]); +} + @end diff --git a/shell/platform/darwin/ios/framework/Source/FlutterEngine_Test.h b/shell/platform/darwin/ios/framework/Source/FlutterEngine_Test.h index 1346c9aed6d99..7e4ebc62ae885 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterEngine_Test.h +++ b/shell/platform/darwin/ios/framework/Source/FlutterEngine_Test.h @@ -30,4 +30,5 @@ class ThreadHost; initialRoute:(/*nullable*/ NSString*)initialRoute entrypointArgs:(/*nullable*/ NSArray*)entrypointArgs; - (const flutter::ThreadHost&)threadHost; +- (void)updateDisplays; @end From 8f625071d9326d80c3c4c4b38e6fddb699c1fd9f Mon Sep 17 00:00:00 2001 From: Dan Field Date: Wed, 3 May 2023 21:33:38 -0700 Subject: [PATCH 16/19] try to find test failure --- testing/scenario_app/lib/main.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/scenario_app/lib/main.dart b/testing/scenario_app/lib/main.dart index 22a6466297639..6f09a27157fd1 100644 --- a/testing/scenario_app/lib/main.dart +++ b/testing/scenario_app/lib/main.dart @@ -25,7 +25,7 @@ void main() { ..scheduleFrame(); final FlutterView view = PlatformDispatcher.instance.implicitView!; - assert(view.display.size == view.physicalSize); + assert(view.display.size == view.physicalSize, 'Expected view size ${view.physicalSize} to match the size in ${view.display}'); final ByteData data = ByteData(1); data.setUint8(0, 1); From ad25b20369c4a13fade2664fa8af0c4fcc0d9456 Mon Sep 17 00:00:00 2001 From: Dan Field Date: Wed, 3 May 2023 21:58:32 -0700 Subject: [PATCH 17/19] fix test --- testing/scenario_app/lib/main.dart | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/testing/scenario_app/lib/main.dart b/testing/scenario_app/lib/main.dart index 6f09a27157fd1..06567dba20894 100644 --- a/testing/scenario_app/lib/main.dart +++ b/testing/scenario_app/lib/main.dart @@ -25,7 +25,13 @@ void main() { ..scheduleFrame(); final FlutterView view = PlatformDispatcher.instance.implicitView!; - assert(view.display.size == view.physicalSize, 'Expected view size ${view.physicalSize} to match the size in ${view.display}'); + // Asserting that this is greater than zero since this app runs on different + // platforms with different sizes. If it is greater than zero, it has been + // initialized to some meaningful value at least. + assert( + view.display.size > Offset.zero, + 'Expected ${view.display} to be initialized.', + ); final ByteData data = ByteData(1); data.setUint8(0, 1); From a7602b4749699996f56ea6bcf9df4d5391194034 Mon Sep 17 00:00:00 2001 From: Dan Field Date: Thu, 4 May 2023 07:13:28 -0700 Subject: [PATCH 18/19] docs --- lib/ui/platform_dispatcher.dart | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lib/ui/platform_dispatcher.dart b/lib/ui/platform_dispatcher.dart index f629a63a51b00..4bfdd52288f10 100644 --- a/lib/ui/platform_dispatcher.dart +++ b/lib/ui/platform_dispatcher.dart @@ -154,6 +154,18 @@ class PlatformDispatcher { /// If any of their configurations change, [onMetricsChanged] will be called. /// /// To get the display for a [FlutterView], use [FlutterView.display]. + /// + /// Platforms may limit what information is available to the application with + /// regard to secondary displays and/or displays that do not have an active + /// application window. + /// + /// Presently, on Android and Web this collection will only contain the + /// display that the current window is on. On iOS, it will only contains the + /// main display on the phone or tablet. On Desktop, it will contain only + /// a main display with a valid refresh rate but invalid size and device + /// pixel ratio values. + // TODO(dnfield): Update these docs when https://github.com/flutter/flutter/issues/125939 + // and https://github.com/flutter/flutter/issues/125938 are resolved. Iterable get displays => _displays.values; final Map _displays = {}; From 400b50a4a098e7678a4a2c38ec40f7522a67a5ad Mon Sep 17 00:00:00 2001 From: Dan Field Date: Sat, 6 May 2023 10:48:39 -0700 Subject: [PATCH 19/19] docs --- lib/ui/window.dart | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/ui/window.dart b/lib/ui/window.dart index 5a8018de778e9..c3c107c7683da 100644 --- a/lib/ui/window.dart +++ b/lib/ui/window.dart @@ -22,6 +22,9 @@ class Display { final int id; /// The device pixel ratio of this display. + /// + /// This value is the same as the value of [FlutterView.devicePixelRatio] for + /// all view objects attached to this display. final double devicePixelRatio; /// The physical size of this display. @@ -129,6 +132,8 @@ class FlutterView { /// /// * [WidgetsBindingObserver], for a mechanism at the widgets layer to /// observe when this value changes. + /// * [Display.devicePixelRatio], which reports the DPR of the display. + /// The value here is equal to the value on the [display.devicePixelRatio]. double get devicePixelRatio => _viewConfiguration.devicePixelRatio; /// The dimensions and location of the rectangle into which the scene rendered