| Flutter Windows Embedder |

flutter_windows_unittests.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "flutter/shell/platform/windows/public/flutter_windows.h"
6
7 #include <dxgi.h>
8 #include <wrl/client.h>
9 #include <thread>
10
11 #include "flutter/fml/synchronization/count_down_latch.h"
12 #include "flutter/fml/synchronization/waitable_event.h"
13 #include "flutter/shell/platform/common/app_lifecycle_state.h"
14 #include "flutter/shell/platform/embedder/test_utils/proc_table_replacement.h"
15 #include "flutter/shell/platform/windows/egl/manager.h"
16 #include "flutter/shell/platform/windows/testing/engine_modifier.h"
17 #include "flutter/shell/platform/windows/testing/windows_test.h"
18 #include "flutter/shell/platform/windows/testing/windows_test_config_builder.h"
19 #include "flutter/shell/platform/windows/testing/windows_test_context.h"
20 #include "flutter/shell/platform/windows/windows_lifecycle_manager.h"
21 #include "flutter/testing/stream_capture.h"
22 #include "gmock/gmock.h"
23 #include "gtest/gtest.h"
24 #include "third_party/tonic/converter/dart_converter.h"
25
26 namespace flutter {
27 namespace testing {
28
29 namespace {
30
31 // An EGL manager that initializes EGL but fails to create surfaces.
32 class HalfBrokenEGLManager : public egl::Manager {
33 public:
34 HalfBrokenEGLManager() : egl::Manager() {}
35
36 std::unique_ptr<egl::WindowSurface>
37 CreateWindowSurface(HWND hwnd, size_t width, size_t height) override {
38 return nullptr;
39 }
40 };
41
42 class MockWindowsLifecycleManager : public WindowsLifecycleManager {
43 public:
44 MockWindowsLifecycleManager(FlutterWindowsEngine* engine)
45 : WindowsLifecycleManager(engine) {}
46
47 MOCK_METHOD(void, SetLifecycleState, (AppLifecycleState), (override));
48 };
49
50 // Process the next win32 message if there is one. This can be used to
51 // pump the Windows platform thread task runner.
52 void PumpMessage() {
53 ::MSG msg;
54 if (::GetMessage(&msg, nullptr, 0, 0)) {
55 ::TranslateMessage(&msg);
56 ::DispatchMessage(&msg);
57 }
58 }
59
60 } // namespace
61
62 // Verify that we can fetch a texture registrar.
63 // Prevent regression: https://github.com/flutter/flutter/issues/86617
64 TEST(WindowsNoFixtureTest, GetTextureRegistrar) {
65 FlutterDesktopEngineProperties properties = {};
66 properties.assets_path = L"";
67 properties.icu_data_path = L"icudtl.dat";
68 auto engine = FlutterDesktopEngineCreate(&properties);
69 ASSERT_NE(engine, nullptr);
70 auto texture_registrar = FlutterDesktopEngineGetTextureRegistrar(engine);
71 EXPECT_NE(texture_registrar, nullptr);
72 FlutterDesktopEngineDestroy(engine);
73 }
74
75 // Verify we can successfully launch main().
76 TEST_F(WindowsTest, LaunchMain) {
77 auto& context = GetContext();
78 WindowsConfigBuilder builder(context);
79 ViewControllerPtr controller{builder.Run()};
80 ASSERT_NE(controller, nullptr);
81 }
82
83 // Verify there is no unexpected output from launching main.
84 TEST_F(WindowsTest, LaunchMainHasNoOutput) {
85 // Replace stdout & stderr stream buffers with our own.
86 StreamCapture stdout_capture(&std::cout);
87 StreamCapture stderr_capture(&std::cerr);
88
89 auto& context = GetContext();
90 WindowsConfigBuilder builder(context);
91 ViewControllerPtr controller{builder.Run()};
92 ASSERT_NE(controller, nullptr);
93
94 stdout_capture.Stop();
95 stderr_capture.Stop();
96
97 // Verify stdout & stderr have no output.
98 EXPECT_TRUE(stdout_capture.GetOutput().empty());
99 EXPECT_TRUE(stderr_capture.GetOutput().empty());
100 }
101
102 // Verify we can successfully launch a custom entry point.
103 TEST_F(WindowsTest, LaunchCustomEntrypoint) {
104 auto& context = GetContext();
105 WindowsConfigBuilder builder(context);
106 builder.SetDartEntrypoint("customEntrypoint");
107 ViewControllerPtr controller{builder.Run()};
108 ASSERT_NE(controller, nullptr);
109 }
110
111 // Verify that engine launches with the custom entrypoint specified in the
112 // FlutterDesktopEngineRun parameter when no entrypoint is specified in
113 // FlutterDesktopEngineProperties.dart_entrypoint.
114 //
115 // TODO(cbracken): https://github.com/flutter/flutter/issues/109285
116 TEST_F(WindowsTest, LaunchCustomEntrypointInEngineRunInvocation) {
117 auto& context = GetContext();
118 WindowsConfigBuilder builder(context);
119 EnginePtr engine{builder.InitializeEngine()};
120 ASSERT_NE(engine, nullptr);
121
122 ASSERT_TRUE(FlutterDesktopEngineRun(engine.get(), "customEntrypoint"));
123 }
124
125 // Verify that the engine can launch in headless mode.
126 TEST_F(WindowsTest, LaunchHeadlessEngine) {
127 auto& context = GetContext();
128 WindowsConfigBuilder builder(context);
129 builder.SetDartEntrypoint("signalViewIds");
130 EnginePtr engine{builder.RunHeadless()};
131 ASSERT_NE(engine, nullptr);
132
133 std::string view_ids;
134 fml::AutoResetWaitableEvent latch;
135 context.AddNativeFunction(
136 "SignalStringValue", CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
137 auto handle = Dart_GetNativeArgument(args, 0);
138 ASSERT_FALSE(Dart_IsError(handle));
139 view_ids = tonic::DartConverter<std::string>::FromDart(handle);
140 latch.Signal();
141 }));
142
143 ViewControllerPtr controller{builder.Run()};
144 ASSERT_NE(controller, nullptr);
145
146 // Verify a headless app has the implicit view.
147 latch.Wait();
148 EXPECT_EQ(view_ids, "View IDs: [0]");
149 }
150
151 // Verify that the engine can return to headless mode.
152 TEST_F(WindowsTest, EngineCanTransitionToHeadless) {
153 auto& context = GetContext();
154 WindowsConfigBuilder builder(context);
155 EnginePtr engine{builder.RunHeadless()};
156 ASSERT_NE(engine, nullptr);
157
158 // Create and then destroy a view controller that does not own its engine.
159 // This causes the engine to transition back to headless mode.
160 {
161 FlutterDesktopViewControllerProperties properties = {};
162 ViewControllerPtr controller{
163 FlutterDesktopEngineCreateViewController(engine.get(), &properties)};
164
165 ASSERT_NE(controller, nullptr);
166 }
167
168 // The engine is back in headless mode now.
169 ASSERT_NE(engine, nullptr);
170
171 auto engine_ptr = reinterpret_cast<FlutterWindowsEngine*>(engine.get());
172 ASSERT_TRUE(engine_ptr->running());
173 }
174
175 // Verify that accessibility features are initialized when a view is created.
176 TEST_F(WindowsTest, LaunchRefreshesAccessibility) {
177 auto& context = GetContext();
178 WindowsConfigBuilder builder(context);
179 EnginePtr engine{builder.InitializeEngine()};
180 EngineModifier modifier{
181 reinterpret_cast<FlutterWindowsEngine*>(engine.get())};
182
183 auto called = false;
184 modifier.embedder_api().UpdateAccessibilityFeatures = MOCK_ENGINE_PROC(
185 UpdateAccessibilityFeatures, ([&called](auto engine, auto flags) {
186 called = true;
187 return kSuccess;
188 }));
189
190 ViewControllerPtr controller{
191 FlutterDesktopViewControllerCreate(0, 0, engine.release())};
192
193 ASSERT_TRUE(called);
194 }
195
196 // Verify that engine fails to launch when a conflicting entrypoint in
197 // FlutterDesktopEngineProperties.dart_entrypoint and the
198 // FlutterDesktopEngineRun parameter.
199 //
200 // TODO(cbracken): https://github.com/flutter/flutter/issues/109285
201 TEST_F(WindowsTest, LaunchConflictingCustomEntrypoints) {
202 auto& context = GetContext();
203 WindowsConfigBuilder builder(context);
204 builder.SetDartEntrypoint("customEntrypoint");
205 EnginePtr engine{builder.InitializeEngine()};
206 ASSERT_NE(engine, nullptr);
207
208 ASSERT_FALSE(FlutterDesktopEngineRun(engine.get(), "conflictingEntrypoint"));
209 }
210
211 // Verify that native functions can be registered and resolved.
212 TEST_F(WindowsTest, VerifyNativeFunction) {
213 auto& context = GetContext();
214 WindowsConfigBuilder builder(context);
215 builder.SetDartEntrypoint("verifyNativeFunction");
216
217 fml::AutoResetWaitableEvent latch;
218 auto native_entry =
219 CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { latch.Signal(); });
220 context.AddNativeFunction("Signal", native_entry);
221
222 ViewControllerPtr controller{builder.Run()};
223 ASSERT_NE(controller, nullptr);
224
225 // Wait until signal has been called.
226 latch.Wait();
227 }
228
229 // Verify that native functions that pass parameters can be registered and
230 // resolved.
231 TEST_F(WindowsTest, VerifyNativeFunctionWithParameters) {
232 auto& context = GetContext();
233 WindowsConfigBuilder builder(context);
234 builder.SetDartEntrypoint("verifyNativeFunctionWithParameters");
235
236 bool bool_value = false;
237 fml::AutoResetWaitableEvent latch;
238 auto native_entry = CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
239 auto handle = Dart_GetNativeBooleanArgument(args, 0, &bool_value);
240 ASSERT_FALSE(Dart_IsError(handle));
241 latch.Signal();
242 });
243 context.AddNativeFunction("SignalBoolValue", native_entry);
244
245 ViewControllerPtr controller{builder.Run()};
246 ASSERT_NE(controller, nullptr);
247
248 // Wait until signalBoolValue has been called.
249 latch.Wait();
250 EXPECT_TRUE(bool_value);
251 }
252
253 // Verify that Platform.executable returns the executable name.
254 TEST_F(WindowsTest, PlatformExecutable) {
255 auto& context = GetContext();
256 WindowsConfigBuilder builder(context);
257 builder.SetDartEntrypoint("readPlatformExecutable");
258
259 std::string executable_name;
260 fml::AutoResetWaitableEvent latch;
261 auto native_entry = CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
262 auto handle = Dart_GetNativeArgument(args, 0);
263 ASSERT_FALSE(Dart_IsError(handle));
264 executable_name = tonic::DartConverter<std::string>::FromDart(handle);
265 latch.Signal();
266 });
267 context.AddNativeFunction("SignalStringValue", native_entry);
268
269 ViewControllerPtr controller{builder.Run()};
270 ASSERT_NE(controller, nullptr);
271
272 // Wait until signalStringValue has been called.
273 latch.Wait();
274 EXPECT_EQ(executable_name, "flutter_windows_unittests.exe");
275 }
276
277 // Verify that native functions that return values can be registered and
278 // resolved.
279 TEST_F(WindowsTest, VerifyNativeFunctionWithReturn) {
280 auto& context = GetContext();
281 WindowsConfigBuilder builder(context);
282 builder.SetDartEntrypoint("verifyNativeFunctionWithReturn");
283
284 bool bool_value_to_return = true;
285 fml::CountDownLatch latch(2);
286 auto bool_return_entry = CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
287 Dart_SetBooleanReturnValue(args, bool_value_to_return);
288 latch.CountDown();
289 });
290 context.AddNativeFunction("SignalBoolReturn", bool_return_entry);
291
292 bool bool_value_passed = false;
293 auto bool_pass_entry = CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
294 auto handle = Dart_GetNativeBooleanArgument(args, 0, &bool_value_passed);
295 ASSERT_FALSE(Dart_IsError(handle));
296 latch.CountDown();
297 });
298 context.AddNativeFunction("SignalBoolValue", bool_pass_entry);
299
300 ViewControllerPtr controller{builder.Run()};
301 ASSERT_NE(controller, nullptr);
302
303 // Wait until signalBoolReturn and signalBoolValue have been called.
304 latch.Wait();
305 EXPECT_TRUE(bool_value_passed);
306 }
307
308 // Verify the next frame callback is executed.
309 TEST_F(WindowsTest, NextFrameCallback) {
310 struct Captures {
311 fml::AutoResetWaitableEvent frame_scheduled_latch;
312 fml::AutoResetWaitableEvent frame_drawn_latch;
313 std::thread::id thread_id;
314 bool done = false;
315 };
316 Captures captures;
317
318 CreateNewThread("test_platform_thread")->PostTask([&]() {
319 captures.thread_id = std::this_thread::get_id();
320
321 auto& context = GetContext();
322 WindowsConfigBuilder builder(context);
323 builder.SetDartEntrypoint("drawHelloWorld");
324
325 auto native_entry = CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
326 ASSERT_FALSE(captures.frame_drawn_latch.IsSignaledForTest());
327 captures.frame_scheduled_latch.Signal();
328 });
329 context.AddNativeFunction("NotifyFirstFrameScheduled", native_entry);
330
331 ViewControllerPtr controller{builder.Run()};
332 ASSERT_NE(controller, nullptr);
333
334 auto engine = FlutterDesktopViewControllerGetEngine(controller.get());
335
336 FlutterDesktopEngineSetNextFrameCallback(
337 engine,
338 [](void* user_data) {
339 auto captures = static_cast<Captures*>(user_data);
340
341 ASSERT_TRUE(captures->frame_scheduled_latch.IsSignaledForTest());
342
343 // Callback should execute on platform thread.
344 ASSERT_EQ(std::this_thread::get_id(), captures->thread_id);
345
346 // Signal the test passed and end the Windows message loop.
347 captures->done = true;
348 captures->frame_drawn_latch.Signal();
349 },
350 &captures);
351
352 // Pump messages for the Windows platform task runner.
353 while (!captures.done) {
354 PumpMessage();
355 }
356 });
357
358 captures.frame_drawn_latch.Wait();
359 }
360
361 // Verify the embedder ignores presents to the implicit view when there is no
362 // implicit view.
363 TEST_F(WindowsTest, PresentHeadless) {
364 auto& context = GetContext();
365 WindowsConfigBuilder builder(context);
366 builder.SetDartEntrypoint("renderImplicitView");
367
368 EnginePtr engine{builder.RunHeadless()};
369 ASSERT_NE(engine, nullptr);
370
371 bool done = false;
372 FlutterDesktopEngineSetNextFrameCallback(
373 engine.get(),
374 [](void* user_data) {
375 // This executes on the platform thread.
376 auto done = reinterpret_cast<std::atomic<bool>*>(user_data);
377 *done = true;
378 },
379 &done);
380
381 // This app is in headless mode, however, the engine assumes the implicit
382 // view always exists. Send window metrics for the implicit view, causing
383 // the engine to present to the implicit view. The embedder must not crash.
384 auto engine_ptr = reinterpret_cast<FlutterWindowsEngine*>(engine.get());
385 FlutterWindowMetricsEvent metrics = {};
386 metrics.struct_size = sizeof(FlutterWindowMetricsEvent);
387 metrics.width = 100;
388 metrics.height = 100;
389 metrics.pixel_ratio = 1.0;
390 metrics.view_id = kImplicitViewId;
391 engine_ptr->SendWindowMetricsEvent(metrics);
392
393 // Pump messages for the Windows platform task runner.
394 while (!done) {
395 PumpMessage();
396 }
397 }
398
399 // Implicit view has the implicit view ID.
400 TEST_F(WindowsTest, GetViewId) {
401 auto& context = GetContext();
402 WindowsConfigBuilder builder(context);
403 ViewControllerPtr controller{builder.Run()};
404 ASSERT_NE(controller, nullptr);
405 FlutterDesktopViewId view_id =
406 FlutterDesktopViewControllerGetViewId(controller.get());
407
408 ASSERT_EQ(view_id, static_cast<FlutterDesktopViewId>(kImplicitViewId));
409 }
410
411 TEST_F(WindowsTest, GetGraphicsAdapter) {
412 auto& context = GetContext();
413 WindowsConfigBuilder builder(context);
414 ViewControllerPtr controller{builder.Run()};
415 ASSERT_NE(controller, nullptr);
416 auto view = FlutterDesktopViewControllerGetView(controller.get());
417
418 Microsoft::WRL::ComPtr<IDXGIAdapter> dxgi_adapter;
419 dxgi_adapter = FlutterDesktopViewGetGraphicsAdapter(view);
420 ASSERT_NE(dxgi_adapter, nullptr);
421 DXGI_ADAPTER_DESC desc{};
422 ASSERT_TRUE(SUCCEEDED(dxgi_adapter->GetDesc(&desc)));
423 }
424
425 // Implicit view has the implicit view ID.
426 TEST_F(WindowsTest, PluginRegistrarGetImplicitView) {
427 auto& context = GetContext();
428 WindowsConfigBuilder builder(context);
429 ViewControllerPtr controller{builder.Run()};
430 ASSERT_NE(controller, nullptr);
431
432 FlutterDesktopEngineRef engine =
433 FlutterDesktopViewControllerGetEngine(controller.get());
434 FlutterDesktopPluginRegistrarRef registrar =
435 FlutterDesktopEngineGetPluginRegistrar(engine, "foo_bar");
436 FlutterDesktopViewRef implicit_view =
437 FlutterDesktopPluginRegistrarGetView(registrar);
438
439 ASSERT_NE(implicit_view, nullptr);
440 }
441
442 TEST_F(WindowsTest, PluginRegistrarGetView) {
443 auto& context = GetContext();
444 WindowsConfigBuilder builder(context);
445 ViewControllerPtr controller{builder.Run()};
446 ASSERT_NE(controller, nullptr);
447
448 FlutterDesktopEngineRef engine =
449 FlutterDesktopViewControllerGetEngine(controller.get());
450 FlutterDesktopPluginRegistrarRef registrar =
451 FlutterDesktopEngineGetPluginRegistrar(engine, "foo_bar");
452
453 FlutterDesktopViewId view_id =
454 FlutterDesktopViewControllerGetViewId(controller.get());
455 FlutterDesktopViewRef view =
456 FlutterDesktopPluginRegistrarGetViewById(registrar, view_id);
457
458 FlutterDesktopViewRef view_123 = FlutterDesktopPluginRegistrarGetViewById(
459 registrar, static_cast<FlutterDesktopViewId>(123));
460
461 ASSERT_NE(view, nullptr);
462 ASSERT_EQ(view_123, nullptr);
463 }
464
465 TEST_F(WindowsTest, PluginRegistrarGetViewHeadless) {
466 auto& context = GetContext();
467 WindowsConfigBuilder builder(context);
468 EnginePtr engine{builder.RunHeadless()};
469 ASSERT_NE(engine, nullptr);
470
471 FlutterDesktopPluginRegistrarRef registrar =
472 FlutterDesktopEngineGetPluginRegistrar(engine.get(), "foo_bar");
473
474 FlutterDesktopViewRef implicit_view =
475 FlutterDesktopPluginRegistrarGetView(registrar);
476 FlutterDesktopViewRef view_123 = FlutterDesktopPluginRegistrarGetViewById(
477 registrar, static_cast<FlutterDesktopViewId>(123));
478
479 ASSERT_EQ(implicit_view, nullptr);
480 ASSERT_EQ(view_123, nullptr);
481 }
482
483 // Verify the app does not crash if EGL initializes successfully but
484 // the rendering surface cannot be created.
485 TEST_F(WindowsTest, SurfaceOptional) {
486 auto& context = GetContext();
487 WindowsConfigBuilder builder(context);
488 EnginePtr engine{builder.InitializeEngine()};
489 EngineModifier modifier{
490 reinterpret_cast<FlutterWindowsEngine*>(engine.get())};
491
492 auto egl_manager = std::make_unique<HalfBrokenEGLManager>();
493 ASSERT_TRUE(egl_manager->IsValid());
494 modifier.SetEGLManager(std::move(egl_manager));
495
496 ViewControllerPtr controller{
497 FlutterDesktopViewControllerCreate(0, 0, engine.release())};
498
499 ASSERT_NE(controller, nullptr);
500 }
501
502 // Verify the app produces the expected lifecycle events.
503 TEST_F(WindowsTest, Lifecycle) {
504 auto& context = GetContext();
505 WindowsConfigBuilder builder(context);
506 EnginePtr engine{builder.InitializeEngine()};
507 auto windows_engine = reinterpret_cast<FlutterWindowsEngine*>(engine.get());
508 EngineModifier modifier{windows_engine};
509
510 auto lifecycle_manager =
511 std::make_unique<MockWindowsLifecycleManager>(windows_engine);
512 auto lifecycle_manager_ptr = lifecycle_manager.get();
513 modifier.SetLifecycleManager(std::move(lifecycle_manager));
514
515 EXPECT_CALL(*lifecycle_manager_ptr,
516 SetLifecycleState(AppLifecycleState::kResumed))
517 .WillOnce([lifecycle_manager_ptr](AppLifecycleState state) {
518 lifecycle_manager_ptr->WindowsLifecycleManager::SetLifecycleState(
519 state);
520 });
521
522 EXPECT_CALL(*lifecycle_manager_ptr,
523 SetLifecycleState(AppLifecycleState::kHidden))
524 .WillOnce([lifecycle_manager_ptr](AppLifecycleState state) {
525 lifecycle_manager_ptr->WindowsLifecycleManager::SetLifecycleState(
526 state);
527 });
528
529 // Create a controller. This launches the engine and sets the app lifecycle
530 // to the "resumed" state.
531 ViewControllerPtr controller{
532 FlutterDesktopViewControllerCreate(0, 0, engine.release())};
533
534 FlutterDesktopViewRef view =
535 FlutterDesktopViewControllerGetView(controller.get());
536 ASSERT_NE(view, nullptr);
537
538 HWND hwnd = FlutterDesktopViewGetHWND(view);
539 ASSERT_NE(hwnd, nullptr);
540
541 // Give the window a non-zero size to show it. This does not change the app
542 // lifecycle directly. However, destroying the view will now result in a
543 // "hidden" app lifecycle event.
544 ::MoveWindow(hwnd, /* X */ 0, /* Y */ 0, /* nWidth*/ 100, /* nHeight*/ 100,
545 /* bRepaint*/ false);
546 }
547
548 TEST_F(WindowsTest, GetKeyboardStateHeadless) {
549 auto& context = GetContext();
550 WindowsConfigBuilder builder(context);
551 builder.SetDartEntrypoint("sendGetKeyboardState");
552
553 std::atomic<bool> done = false;
554 context.AddNativeFunction(
555 "SignalStringValue", CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
556 auto handle = Dart_GetNativeArgument(args, 0);
557 ASSERT_FALSE(Dart_IsError(handle));
558 auto value = tonic::DartConverter<std::string>::FromDart(handle);
559 EXPECT_EQ(value, "Success");
560 done = true;
561 }));
562
563 ViewControllerPtr controller{builder.Run()};
564 ASSERT_NE(controller, nullptr);
565
566 // Pump messages for the Windows platform task runner.
567 ::MSG msg;
568 while (!done) {
569 PumpMessage();
570 }
571 }
572
573 // Verify the embedder can add and remove views.
574 TEST_F(WindowsTest, AddRemoveView) {
575 std::mutex mutex;
576 std::string view_ids;
577
578 auto& context = GetContext();
579 WindowsConfigBuilder builder(context);
580 builder.SetDartEntrypoint("onMetricsChangedSignalViewIds");
581
582 fml::AutoResetWaitableEvent ready_latch;
583 context.AddNativeFunction(
584 "Signal", CREATE_NATIVE_ENTRY(
585 [&](Dart_NativeArguments args) { ready_latch.Signal(); }));
586
587 context.AddNativeFunction(
588 "SignalStringValue", CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
589 auto handle = Dart_GetNativeArgument(args, 0);
590 ASSERT_FALSE(Dart_IsError(handle));
591
592 std::scoped_lock lock{mutex};
593 view_ids = tonic::DartConverter<std::string>::FromDart(handle);
594 }));
595
596 // Create the implicit view.
597 ViewControllerPtr first_controller{builder.Run()};
598 ASSERT_NE(first_controller, nullptr);
599
600 ready_latch.Wait();
601
602 // Create a second view.
603 FlutterDesktopEngineRef engine =
604 FlutterDesktopViewControllerGetEngine(first_controller.get());
605 FlutterDesktopViewControllerProperties properties = {};
606 properties.width = 100;
607 properties.height = 100;
608 ViewControllerPtr second_controller{
609 FlutterDesktopEngineCreateViewController(engine, &properties)};
610 ASSERT_NE(second_controller, nullptr);
611
612 // Pump messages for the Windows platform task runner until the view is added.
613 while (true) {
614 PumpMessage();
615 std::scoped_lock lock{mutex};
616 if (view_ids == "View IDs: [0, 1]") {
617 break;
618 }
619 }
620
621 // Delete the second view and pump messages for the Windows platform task
622 // runner until the view is removed.
623 second_controller.reset();
624 while (true) {
625 PumpMessage();
626 std::scoped_lock lock{mutex};
627 if (view_ids == "View IDs: [0]") {
628 break;
629 }
630 }
631 }
632
633 } // namespace testing
634 } // namespace flutter
FlutterDesktopViewControllerProperties::height
int height
Definition: flutter_windows_internal.h:23
flutter::kImplicitViewId
constexpr FlutterViewId kImplicitViewId
Definition: flutter_windows_engine.h:55
FlutterDesktopViewGetHWND
HWND FlutterDesktopViewGetHWND(FlutterDesktopViewRef view)
Definition: flutter_windows.cc:246
flutter::AppLifecycleState::kHidden
@ kHidden
FlutterDesktopViewControllerGetView
FlutterDesktopViewRef FlutterDesktopViewControllerGetView(FlutterDesktopViewControllerRef ref)
Definition: flutter_windows.cc:153
FlutterDesktopEngineGetTextureRegistrar
FlutterDesktopTextureRegistrarRef FlutterDesktopEngineGetTextureRegistrar(FlutterDesktopEngineRef engine)
Definition: flutter_windows.cc:233
FlutterDesktopPluginRegistrarGetView
FlutterDesktopViewRef FlutterDesktopPluginRegistrarGetView(FlutterDesktopPluginRegistrarRef registrar)
Definition: flutter_windows.cc:290
FlutterDesktopEngineProperties
Definition: flutter_windows.h:39
windows_lifecycle_manager.h
FlutterDesktopViewId
int64_t FlutterDesktopViewId
Definition: flutter_windows.h:36
user_data
void * user_data
Definition: flutter_windows_view_unittests.cc:53
flutter::FlutterWindowsEngine
Definition: flutter_windows_engine.h:90
FlutterDesktopViewControllerProperties
Definition: flutter_windows_internal.h:18
FlutterDesktopEngineProperties::icu_data_path
const wchar_t * icu_data_path
Definition: flutter_windows.h:48
FlutterDesktopEngineGetPluginRegistrar
FlutterDesktopPluginRegistrarRef FlutterDesktopEngineGetPluginRegistrar(FlutterDesktopEngineRef engine, const char *plugin_name)
Definition: flutter_windows.cc:218
flutter::FlutterWindowsEngine::UpdateAccessibilityFeatures
void UpdateAccessibilityFeatures()
Definition: flutter_windows_engine.cc:917
FlutterDesktopViewControllerGetViewId
FlutterDesktopViewId FlutterDesktopViewControllerGetViewId(FlutterDesktopViewControllerRef ref)
Definition: flutter_windows.cc:141
flutter::testing::MockWindowsLifecycleManager::MockWindowsLifecycleManager
MockWindowsLifecycleManager(FlutterWindowsEngine *engine)
Definition: flutter_windows_engine_unittests.cc:751
app_lifecycle_state.h
FlutterDesktopViewRef
struct FlutterDesktopView * FlutterDesktopViewRef
Definition: flutter_windows.h:29
FlutterDesktopEngineRef
struct FlutterDesktopEngine * FlutterDesktopEngineRef
Definition: flutter_windows.h:33
flutter::WindowsLifecycleManager::SetLifecycleState
virtual void SetLifecycleState(AppLifecycleState state)
Definition: windows_lifecycle_manager.cc:195
flutter::WindowsLifecycleManager::WindowsLifecycleManager
WindowsLifecycleManager(FlutterWindowsEngine *engine)
Definition: windows_lifecycle_manager.cc:16
flutter
Definition: accessibility_bridge_windows.cc:11
FlutterDesktopViewControllerCreate
FlutterDesktopViewControllerRef FlutterDesktopViewControllerCreate(int width, int height, FlutterDesktopEngineRef engine)
Definition: flutter_windows.cc:121
FlutterDesktopEngineDestroy
bool FlutterDesktopEngineDestroy(FlutterDesktopEngineRef engine_ref)
Definition: flutter_windows.cc:190
manager.h
FlutterDesktopEngineCreate
FlutterDesktopEngineRef FlutterDesktopEngineCreate(const FlutterDesktopEngineProperties *engine_properties)
Definition: flutter_windows.cc:183
FlutterDesktopViewControllerGetEngine
FlutterDesktopEngineRef FlutterDesktopViewControllerGetEngine(FlutterDesktopViewControllerRef ref)
Definition: flutter_windows.cc:147
flutter::AppLifecycleState::kResumed
@ kResumed
flutter_windows.h
flutter::testing::TEST
TEST(AccessibilityBridgeWindows, GetParent)
Definition: accessibility_bridge_windows_unittests.cc:237
flutter::AppLifecycleState
AppLifecycleState
Definition: app_lifecycle_state.h:32
FlutterDesktopEngineSetNextFrameCallback
void FlutterDesktopEngineSetNextFrameCallback(FlutterDesktopEngineRef engine, VoidCallback callback, void *user_data)
Definition: flutter_windows.cc:239
FlutterDesktopEngineCreateViewController
FlutterDesktopViewControllerRef FlutterDesktopEngineCreateViewController(FlutterDesktopEngineRef engine, const FlutterDesktopViewControllerProperties *properties)
Definition: flutter_windows.cc:128
FlutterDesktopViewControllerProperties::width
int width
Definition: flutter_windows_internal.h:20
flutter::testing::MockWindowsLifecycleManager::MOCK_METHOD
MOCK_METHOD(void, Quit,(std::optional< HWND >, std::optional< WPARAM >, std::optional< LPARAM >, UINT),(override))
flutter::testing::TEST_F
TEST_F(CompositorOpenGLTest, CreateBackingStore)
Definition: compositor_opengl_unittests.cc:125
FlutterDesktopViewGetGraphicsAdapter
IDXGIAdapter * FlutterDesktopViewGetGraphicsAdapter(FlutterDesktopViewRef view)
Definition: flutter_windows.cc:250
FlutterDesktopEngineProperties::assets_path
const wchar_t * assets_path
Definition: flutter_windows.h:43
FlutterDesktopPluginRegistrar
Definition: window_state.h:23
FlutterDesktopEngineRun
bool FlutterDesktopEngineRun(FlutterDesktopEngineRef engine, const char *entry_point)
Definition: flutter_windows.cc:200
FlutterDesktopPluginRegistrarGetViewById
FlutterDesktopViewRef FlutterDesktopPluginRegistrarGetViewById(FlutterDesktopPluginRegistrarRef registrar, FlutterDesktopViewId view_id)
Definition: flutter_windows.cc:295