[dart:ui] Introduce PlatformDispatcher.implicitView
(flutter/engine#39553)
This introduces `PlatformDispatcher.implicitView`, a low-level primitive for the framework's bootstrapping. Most code, including the framework after bootstrapping, will use `View.of(context)` instead of this new API. This new primitive will let us deprecate the `window` global. Goals: 1. **Enable multi-window**. The `PlatformDispatcher.implicitView` is nullable. If `null`, the app must create a window to get a view it can draw into. 2. **Backwards compatibility**. For "single window" apps, `PlatformDispatcher.instance.implicitView` should behave as similar to `window` as possible. 1. The `PlatformDispatcher.instance.implicitView.viewId` should be `0`. 1. The `PlatformDispatcher.instance.implicitView` must be available synchronously at root isolate startup. This allows the framework to determine if it can make single window assumptions at startup. 2. The `PlatformDispatcher.instance.implicitView` reference must not change after startup: if it is null at startup, it must always be null; if it is non-null at startup, it must always be non-null. If "single window" app enters headless mode, the implicit view must remain non-null. In the future, the embedder will control whether an implicit view is created: mobile & legacy desktop apps will have an implicit view, multi-window desktop apps won't have an implicit view. This requires updating the engine's embedder API and is out-of-scope for this change. For now, all apps will have an implicit view. Part of https://github.com/flutter/flutter/issues/120306
This commit is contained in:
parent
0a6f4a106e
commit
a9e12287f6
@ -95,6 +95,7 @@ typedef CanvasPath Path;
|
|||||||
V(IsolateNameServerNatives::RemovePortNameMapping, 1) \
|
V(IsolateNameServerNatives::RemovePortNameMapping, 1) \
|
||||||
V(NativeStringAttribute::initLocaleStringAttribute, 4) \
|
V(NativeStringAttribute::initLocaleStringAttribute, 4) \
|
||||||
V(NativeStringAttribute::initSpellOutStringAttribute, 3) \
|
V(NativeStringAttribute::initSpellOutStringAttribute, 3) \
|
||||||
|
V(PlatformConfigurationNativeApi::ImplicitViewEnabled, 0) \
|
||||||
V(PlatformConfigurationNativeApi::DefaultRouteName, 0) \
|
V(PlatformConfigurationNativeApi::DefaultRouteName, 0) \
|
||||||
V(PlatformConfigurationNativeApi::ScheduleFrame, 0) \
|
V(PlatformConfigurationNativeApi::ScheduleFrame, 0) \
|
||||||
V(PlatformConfigurationNativeApi::Render, 1) \
|
V(PlatformConfigurationNativeApi::Render, 1) \
|
||||||
|
@ -168,6 +168,36 @@ class PlatformDispatcher {
|
|||||||
// A map of opaque platform view identifiers to view configurations.
|
// A map of opaque platform view identifiers to view configurations.
|
||||||
final Map<Object, ViewConfiguration> _viewConfigurations = <Object, ViewConfiguration>{};
|
final Map<Object, ViewConfiguration> _viewConfigurations = <Object, ViewConfiguration>{};
|
||||||
|
|
||||||
|
/// The [FlutterView] provided by the engine if the platform is unable to
|
||||||
|
/// create windows, or, for backwards compatibility.
|
||||||
|
///
|
||||||
|
/// If the platform provides an implicit view, it can be used to bootstrap
|
||||||
|
/// the framework. This is common for platforms designed for single-view
|
||||||
|
/// applications like mobile devices with a single display.
|
||||||
|
///
|
||||||
|
/// Applications and libraries must not rely on this property being set
|
||||||
|
/// as it may be null depending on the engine's configuration. Instead,
|
||||||
|
/// consider using [View.of] to lookup the [FlutterView] the current
|
||||||
|
/// [BuildContext] is drawing into.
|
||||||
|
///
|
||||||
|
/// While the properties on the referenced [FlutterView] may change,
|
||||||
|
/// the reference itself is guaranteed to never change over the lifetime
|
||||||
|
/// of the application: if this property is null at startup, it will remain
|
||||||
|
/// so throughout the entire lifetime of the application. If it points to a
|
||||||
|
/// specific [FlutterView], it will continue to point to the same view until
|
||||||
|
/// the application is shut down (although the engine may replace or remove
|
||||||
|
/// the underlying backing surface of the view at its discretion).
|
||||||
|
///
|
||||||
|
/// See also:
|
||||||
|
///
|
||||||
|
/// * [View.of], for accessing the current view.
|
||||||
|
/// * [PlatformDisptacher.views] for a list of all [FlutterView]s provided
|
||||||
|
/// by the platform.
|
||||||
|
FlutterView? get implicitView => _implicitViewEnabled() ? _views[0] : null;
|
||||||
|
|
||||||
|
@Native<Handle Function()>(symbol: 'PlatformConfigurationNativeApi::ImplicitViewEnabled')
|
||||||
|
external static bool _implicitViewEnabled();
|
||||||
|
|
||||||
/// A callback that is invoked whenever the [ViewConfiguration] of any of the
|
/// A callback that is invoked whenever the [ViewConfiguration] of any of the
|
||||||
/// [views] changes.
|
/// [views] changes.
|
||||||
///
|
///
|
||||||
|
@ -896,6 +896,7 @@ enum Brightness {
|
|||||||
/// * [PlatformDispatcher.views], contains the current list of Flutter windows
|
/// * [PlatformDispatcher.views], contains the current list of Flutter windows
|
||||||
/// belonging to the application, including top level application windows like
|
/// belonging to the application, including top level application windows like
|
||||||
/// this one.
|
/// this one.
|
||||||
|
/// * [PlatformDispatcher.implicitView], this window's view.
|
||||||
final SingletonFlutterWindow window = SingletonFlutterWindow._(0, PlatformDispatcher.instance);
|
final SingletonFlutterWindow window = SingletonFlutterWindow._(0, PlatformDispatcher.instance);
|
||||||
|
|
||||||
/// Additional data available on each flutter frame.
|
/// Additional data available on each flutter frame.
|
||||||
|
@ -22,6 +22,8 @@
|
|||||||
namespace flutter {
|
namespace flutter {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
constexpr int kImplicitViewId = 0;
|
||||||
|
|
||||||
Dart_Handle ToByteData(const fml::Mapping& buffer) {
|
Dart_Handle ToByteData(const fml::Mapping& buffer) {
|
||||||
return tonic::DartByteData::Create(buffer.GetMapping(), buffer.GetSize());
|
return tonic::DartByteData::Create(buffer.GetMapping(), buffer.GetSize());
|
||||||
}
|
}
|
||||||
@ -67,8 +69,13 @@ void PlatformConfiguration::DidCreateIsolate() {
|
|||||||
Dart_GetField(library, tonic::ToDart("_drawFrame")));
|
Dart_GetField(library, tonic::ToDart("_drawFrame")));
|
||||||
report_timings_.Set(tonic::DartState::Current(),
|
report_timings_.Set(tonic::DartState::Current(),
|
||||||
Dart_GetField(library, tonic::ToDart("_reportTimings")));
|
Dart_GetField(library, tonic::ToDart("_reportTimings")));
|
||||||
windows_.insert(std::make_pair(
|
|
||||||
0, std::make_unique<Window>(0, ViewportMetrics{1.0, 0.0, 0.0, -1})));
|
// TODO(loicsharma): This should only be created if the embedder enables the
|
||||||
|
// implicit view.
|
||||||
|
// See: https://github.com/flutter/flutter/issues/120306
|
||||||
|
windows_.emplace(kImplicitViewId,
|
||||||
|
std::make_unique<Window>(
|
||||||
|
kImplicitViewId, ViewportMetrics{1.0, 0.0, 0.0, -1}));
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlatformConfiguration::UpdateLocales(
|
void PlatformConfiguration::UpdateLocales(
|
||||||
@ -427,6 +434,16 @@ Dart_Handle PlatformConfigurationNativeApi::ComputePlatformResolvedLocale(
|
|||||||
return tonic::DartConverter<std::vector<std::string>>::ToDart(results);
|
return tonic::DartConverter<std::vector<std::string>>::ToDart(results);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Dart_Handle PlatformConfigurationNativeApi::ImplicitViewEnabled() {
|
||||||
|
UIDartState::ThrowIfUIOperationsProhibited();
|
||||||
|
bool enabled = UIDartState::Current()
|
||||||
|
->platform_configuration()
|
||||||
|
->client()
|
||||||
|
->ImplicitViewEnabled();
|
||||||
|
|
||||||
|
return Dart_NewBoolean(enabled);
|
||||||
|
}
|
||||||
|
|
||||||
std::string PlatformConfigurationNativeApi::DefaultRouteName() {
|
std::string PlatformConfigurationNativeApi::DefaultRouteName() {
|
||||||
UIDartState::ThrowIfUIOperationsProhibited();
|
UIDartState::ThrowIfUIOperationsProhibited();
|
||||||
return UIDartState::Current()
|
return UIDartState::Current()
|
||||||
|
@ -49,6 +49,16 @@ enum class AccessibilityFeatureFlag : int32_t {
|
|||||||
///
|
///
|
||||||
class PlatformConfigurationClient {
|
class PlatformConfigurationClient {
|
||||||
public:
|
public:
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
/// @brief Whether the platform provides an implicit view. If true,
|
||||||
|
/// the Framework may assume that it can always render into
|
||||||
|
/// the view with ID 0.
|
||||||
|
///
|
||||||
|
/// This value must not change for the lifetime of the
|
||||||
|
/// application.
|
||||||
|
///
|
||||||
|
virtual bool ImplicitViewEnabled() = 0;
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
/// @brief The route or path that the embedder requested when the
|
/// @brief The route or path that the embedder requested when the
|
||||||
/// application was launched.
|
/// application was launched.
|
||||||
@ -71,7 +81,7 @@ class PlatformConfigurationClient {
|
|||||||
virtual void Render(Scene* scene) = 0;
|
virtual void Render(Scene* scene) = 0;
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
/// @brief Receives a updated semantics tree from the Framework.
|
/// @brief Receives an updated semantics tree from the Framework.
|
||||||
///
|
///
|
||||||
/// @param[in] update The updated semantic tree to apply.
|
/// @param[in] update The updated semantic tree to apply.
|
||||||
///
|
///
|
||||||
@ -469,6 +479,8 @@ class PlatformMessageHandlerStorage {
|
|||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
class PlatformConfigurationNativeApi {
|
class PlatformConfigurationNativeApi {
|
||||||
public:
|
public:
|
||||||
|
static Dart_Handle ImplicitViewEnabled();
|
||||||
|
|
||||||
static std::string DefaultRouteName();
|
static std::string DefaultRouteName();
|
||||||
|
|
||||||
static void ScheduleFrame();
|
static void ScheduleFrame();
|
||||||
|
@ -33,6 +33,8 @@ abstract class PlatformDispatcher {
|
|||||||
|
|
||||||
Iterable<FlutterView> get views;
|
Iterable<FlutterView> get views;
|
||||||
|
|
||||||
|
FlutterView? get implicitView;
|
||||||
|
|
||||||
VoidCallback? get onMetricsChanged;
|
VoidCallback? get onMetricsChanged;
|
||||||
set onMetricsChanged(VoidCallback? callback);
|
set onMetricsChanged(VoidCallback? callback);
|
||||||
|
|
||||||
|
@ -148,6 +148,34 @@ class EnginePlatformDispatcher extends ui.PlatformDispatcher {
|
|||||||
final Map<Object, ui.ViewConfiguration> _windowConfigurations =
|
final Map<Object, ui.ViewConfiguration> _windowConfigurations =
|
||||||
<Object, ui.ViewConfiguration>{};
|
<Object, ui.ViewConfiguration>{};
|
||||||
|
|
||||||
|
/// The [FlutterView] provided by the engine if the platform is unable to
|
||||||
|
/// create windows, or, for backwards compatibility.
|
||||||
|
///
|
||||||
|
/// If the platform provides an implicit view, it can be used to bootstrap
|
||||||
|
/// the framework. This is common for platforms designed for single-view
|
||||||
|
/// applications like mobile devices with a single display.
|
||||||
|
///
|
||||||
|
/// Applications and libraries must not rely on this property being set
|
||||||
|
/// as it may be null depending on the engine's configuration. Instead,
|
||||||
|
/// consider using [View.of] to lookup the [FlutterView] the current
|
||||||
|
/// [BuildContext] is drawing into.
|
||||||
|
///
|
||||||
|
/// While the properties on the referenced [FlutterView] may change,
|
||||||
|
/// the reference itself is guaranteed to never change over the lifetime
|
||||||
|
/// of the application: if this property is null at startup, it will remain
|
||||||
|
/// so throughout the entire lifetime of the application. If it points to a
|
||||||
|
/// specific [FlutterView], it will continue to point to the same view until
|
||||||
|
/// the application is shut down (although the engine may replace or remove
|
||||||
|
/// the underlying backing surface of the view at its discretion).
|
||||||
|
///
|
||||||
|
/// See also:
|
||||||
|
///
|
||||||
|
/// * [View.of], for accessing the current view.
|
||||||
|
/// * [PlatformDisptacher.views] for a list of all [FlutterView]s provided
|
||||||
|
/// by the platform.
|
||||||
|
@override
|
||||||
|
ui.FlutterView? get implicitView => viewData[kImplicitViewId];
|
||||||
|
|
||||||
/// A callback that is invoked whenever the platform's [devicePixelRatio],
|
/// A callback that is invoked whenever the platform's [devicePixelRatio],
|
||||||
/// [physicalSize], [padding], [viewInsets], or [systemGestureInsets]
|
/// [physicalSize], [padding], [viewInsets], or [systemGestureInsets]
|
||||||
/// values change, for example when the device is rotated or when the
|
/// values change, for example when the device is rotated or when the
|
||||||
@ -474,7 +502,7 @@ class EnginePlatformDispatcher extends ui.PlatformDispatcher {
|
|||||||
// TODO(a-wallen): As multi-window support expands, the pop call
|
// TODO(a-wallen): As multi-window support expands, the pop call
|
||||||
// will need to include the view ID. Right now only one view is
|
// will need to include the view ID. Right now only one view is
|
||||||
// supported.
|
// supported.
|
||||||
(viewData[kSingletonViewId]! as EngineFlutterWindow)
|
(viewData[kImplicitViewId]! as EngineFlutterWindow)
|
||||||
.browserHistory
|
.browserHistory
|
||||||
.exit()
|
.exit()
|
||||||
.then((_) {
|
.then((_) {
|
||||||
@ -579,7 +607,7 @@ class EnginePlatformDispatcher extends ui.PlatformDispatcher {
|
|||||||
// TODO(a-wallen): As multi-window support expands, the navigation call
|
// TODO(a-wallen): As multi-window support expands, the navigation call
|
||||||
// will need to include the view ID. Right now only one view is
|
// will need to include the view ID. Right now only one view is
|
||||||
// supported.
|
// supported.
|
||||||
(viewData[kSingletonViewId]! as EngineFlutterWindow)
|
(viewData[kImplicitViewId]! as EngineFlutterWindow)
|
||||||
.handleNavigationMessage(data)
|
.handleNavigationMessage(data)
|
||||||
.then((bool handled) {
|
.then((bool handled) {
|
||||||
if (handled) {
|
if (handled) {
|
||||||
@ -1179,7 +1207,7 @@ class EnginePlatformDispatcher extends ui.PlatformDispatcher {
|
|||||||
@override
|
@override
|
||||||
String get defaultRouteName {
|
String get defaultRouteName {
|
||||||
return _defaultRouteName ??=
|
return _defaultRouteName ??=
|
||||||
(viewData[kSingletonViewId]! as EngineFlutterWindow).browserHistory.currentPath;
|
(viewData[kImplicitViewId]! as EngineFlutterWindow).browserHistory.currentPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Lazily initialized when the `defaultRouteName` getter is invoked.
|
/// Lazily initialized when the `defaultRouteName` getter is invoked.
|
||||||
|
@ -27,8 +27,8 @@ typedef _HandleMessageCallBack = Future<bool> Function();
|
|||||||
/// When set to true, all platform messages will be printed to the console.
|
/// When set to true, all platform messages will be printed to the console.
|
||||||
const bool debugPrintPlatformMessages = false;
|
const bool debugPrintPlatformMessages = false;
|
||||||
|
|
||||||
/// The view ID for a singleton flutter window.
|
/// The view ID for the implicit flutter view provided by the platform.
|
||||||
const int kSingletonViewId = 0;
|
const int kImplicitViewId = 0;
|
||||||
|
|
||||||
/// Whether [_customUrlStrategy] has been set or not.
|
/// Whether [_customUrlStrategy] has been set or not.
|
||||||
///
|
///
|
||||||
@ -349,7 +349,7 @@ class EngineSingletonFlutterWindow extends EngineFlutterWindow {
|
|||||||
/// API surface, providing Web-specific functionality that the standard
|
/// API surface, providing Web-specific functionality that the standard
|
||||||
/// `dart:ui` version does not.
|
/// `dart:ui` version does not.
|
||||||
final EngineSingletonFlutterWindow window =
|
final EngineSingletonFlutterWindow window =
|
||||||
EngineSingletonFlutterWindow(kSingletonViewId, EnginePlatformDispatcher.instance);
|
EngineSingletonFlutterWindow(kImplicitViewId, EnginePlatformDispatcher.instance);
|
||||||
|
|
||||||
/// The Web implementation of [ui.WindowPadding].
|
/// The Web implementation of [ui.WindowPadding].
|
||||||
class WindowPadding implements ui.WindowPadding {
|
class WindowPadding implements ui.WindowPadding {
|
||||||
|
@ -41,6 +41,13 @@ void testMain() {
|
|||||||
await window.resetHistory();
|
await window.resetHistory();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// For now, web always has an implicit view provided by the web engine.
|
||||||
|
test('EnginePlatformDispatcher.instance.implicitView should be non-null', () async {
|
||||||
|
expect(EnginePlatformDispatcher.instance.implicitView, isNotNull);
|
||||||
|
expect(EnginePlatformDispatcher.instance.implicitView?.viewId, 0);
|
||||||
|
expect(window.viewId, 0);
|
||||||
|
});
|
||||||
|
|
||||||
test('window.defaultRouteName should work with JsUrlStrategy', () async {
|
test('window.defaultRouteName should work with JsUrlStrategy', () async {
|
||||||
dynamic state = <dynamic, dynamic>{};
|
dynamic state = <dynamic, dynamic>{};
|
||||||
final JsUrlStrategy jsUrlStrategy = JsUrlStrategy(
|
final JsUrlStrategy jsUrlStrategy = JsUrlStrategy(
|
||||||
|
@ -298,6 +298,11 @@ RuntimeController::GetPlatformConfigurationIfAvailable() {
|
|||||||
return root_isolate ? root_isolate->platform_configuration() : nullptr;
|
return root_isolate ? root_isolate->platform_configuration() : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// |PlatformConfigurationClient|
|
||||||
|
bool RuntimeController::ImplicitViewEnabled() {
|
||||||
|
return client_.ImplicitViewEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
// |PlatformConfigurationClient|
|
// |PlatformConfigurationClient|
|
||||||
std::string RuntimeController::DefaultRouteName() {
|
std::string RuntimeController::DefaultRouteName() {
|
||||||
return client_.DefaultRouteName();
|
return client_.DefaultRouteName();
|
||||||
|
@ -610,6 +610,9 @@ class RuntimeController : public PlatformConfigurationClient {
|
|||||||
|
|
||||||
bool FlushRuntimeStateToIsolate();
|
bool FlushRuntimeStateToIsolate();
|
||||||
|
|
||||||
|
// |PlatformConfigurationClient|
|
||||||
|
bool ImplicitViewEnabled() override;
|
||||||
|
|
||||||
// |PlatformConfigurationClient|
|
// |PlatformConfigurationClient|
|
||||||
std::string DefaultRouteName() override;
|
std::string DefaultRouteName() override;
|
||||||
|
|
||||||
|
@ -21,6 +21,8 @@ namespace flutter {
|
|||||||
|
|
||||||
class RuntimeDelegate {
|
class RuntimeDelegate {
|
||||||
public:
|
public:
|
||||||
|
virtual bool ImplicitViewEnabled() = 0;
|
||||||
|
|
||||||
virtual std::string DefaultRouteName() = 0;
|
virtual std::string DefaultRouteName() = 0;
|
||||||
|
|
||||||
virtual void ScheduleFrame(bool regenerate_layer_tree = true) = 0;
|
virtual void ScheduleFrame(bool regenerate_layer_tree = true) = 0;
|
||||||
|
@ -431,6 +431,14 @@ void Engine::SetAccessibilityFeatures(int32_t flags) {
|
|||||||
runtime_controller_->SetAccessibilityFeatures(flags);
|
runtime_controller_->SetAccessibilityFeatures(flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Engine::ImplicitViewEnabled() {
|
||||||
|
// TODO(loicsharma): This value should be provided by the embedder
|
||||||
|
// when it launches the engine. For now, assume the embedder always creates a
|
||||||
|
// view.
|
||||||
|
// See: https://github.com/flutter/flutter/issues/120306
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
std::string Engine::DefaultRouteName() {
|
std::string Engine::DefaultRouteName() {
|
||||||
if (!initial_route_.empty()) {
|
if (!initial_route_.empty()) {
|
||||||
return initial_route_;
|
return initial_route_;
|
||||||
|
@ -888,6 +888,9 @@ class Engine final : public RuntimeDelegate, PointerDataDispatcher::Delegate {
|
|||||||
const std::weak_ptr<VsyncWaiter> GetVsyncWaiter() const;
|
const std::weak_ptr<VsyncWaiter> GetVsyncWaiter() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// |RuntimeDelegate|
|
||||||
|
bool ImplicitViewEnabled() override;
|
||||||
|
|
||||||
// |RuntimeDelegate|
|
// |RuntimeDelegate|
|
||||||
std::string DefaultRouteName() override;
|
std::string DefaultRouteName() override;
|
||||||
|
|
||||||
|
@ -48,6 +48,7 @@ class MockResponse : public PlatformMessageResponse {
|
|||||||
|
|
||||||
class MockRuntimeDelegate : public RuntimeDelegate {
|
class MockRuntimeDelegate : public RuntimeDelegate {
|
||||||
public:
|
public:
|
||||||
|
MOCK_METHOD0(ImplicitViewEnabled, bool());
|
||||||
MOCK_METHOD0(DefaultRouteName, std::string());
|
MOCK_METHOD0(DefaultRouteName, std::string());
|
||||||
MOCK_METHOD1(ScheduleFrame, void(bool));
|
MOCK_METHOD1(ScheduleFrame, void(bool));
|
||||||
MOCK_METHOD1(Render, void(std::shared_ptr<flutter::LayerTree>));
|
MOCK_METHOD1(Render, void(std::shared_ptr<flutter::LayerTree>));
|
||||||
|
@ -45,8 +45,15 @@ void executableNameNotNull() {
|
|||||||
notifyStringValue(Platform.executable);
|
notifyStringValue(Platform.executable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@pragma('vm:entry-point')
|
||||||
|
void implicitViewNotNull() {
|
||||||
|
notifyBoolValue(PlatformDispatcher.instance.implicitView != null);
|
||||||
|
}
|
||||||
|
|
||||||
@pragma('vm:external-name', 'NotifyStringValue')
|
@pragma('vm:external-name', 'NotifyStringValue')
|
||||||
external void notifyStringValue(String value);
|
external void notifyStringValue(String value);
|
||||||
|
@pragma('vm:external-name', 'NotifyBoolValue')
|
||||||
|
external void notifyBoolValue(bool value);
|
||||||
|
|
||||||
@pragma('vm:entry-point')
|
@pragma('vm:entry-point')
|
||||||
void invokePlatformTaskRunner() {
|
void invokePlatformTaskRunner() {
|
||||||
|
@ -174,6 +174,30 @@ TEST_F(EmbedderTest, ExecutableNameNotNull) {
|
|||||||
latch.Wait();
|
latch.Wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(EmbedderTest, ImplicitViewNotNull) {
|
||||||
|
// TODO(loicsharma): Update this test when embedders can opt-out
|
||||||
|
// of the implicit view.
|
||||||
|
// See: https://github.com/flutter/flutter/issues/120306
|
||||||
|
auto& context = GetEmbedderContext(EmbedderTestContextType::kSoftwareContext);
|
||||||
|
|
||||||
|
bool implicitViewNotNull = false;
|
||||||
|
fml::AutoResetWaitableEvent latch;
|
||||||
|
context.AddNativeCallback(
|
||||||
|
"NotifyBoolValue", CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
|
||||||
|
implicitViewNotNull = tonic::DartConverter<bool>::FromDart(
|
||||||
|
Dart_GetNativeArgument(args, 0));
|
||||||
|
latch.Signal();
|
||||||
|
}));
|
||||||
|
|
||||||
|
EmbedderConfigBuilder builder(context);
|
||||||
|
builder.SetSoftwareRendererConfig();
|
||||||
|
builder.SetDartEntrypoint("implicitViewNotNull");
|
||||||
|
auto engine = builder.LaunchEngine();
|
||||||
|
latch.Wait();
|
||||||
|
|
||||||
|
EXPECT_TRUE(implicitViewNotNull);
|
||||||
|
}
|
||||||
|
|
||||||
std::atomic_size_t EmbedderTestTaskRunner::sEmbedderTaskRunnerIdentifiers = {};
|
std::atomic_size_t EmbedderTestTaskRunner::sEmbedderTaskRunnerIdentifiers = {};
|
||||||
|
|
||||||
TEST_F(EmbedderTest, CanSpecifyCustomPlatformTaskRunner) {
|
TEST_F(EmbedderTest, CanSpecifyCustomPlatformTaskRunner) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user