| Flutter Windows Embedder |

flutter_windows_engine_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/flutter_windows_engine.h"
6
7 #include "flutter/fml/macros.h"
8 #include "flutter/shell/platform/embedder/embedder.h"
9 #include "flutter/shell/platform/embedder/test_utils/proc_table_replacement.h"
10 #include "flutter/shell/platform/windows/flutter_windows_view.h"
11 #include "flutter/shell/platform/windows/public/flutter_windows.h"
12 #include "flutter/shell/platform/windows/testing/engine_modifier.h"
13 #include "flutter/shell/platform/windows/testing/flutter_windows_engine_builder.h"
14 #include "flutter/shell/platform/windows/testing/mock_window_binding_handler.h"
15 #include "flutter/shell/platform/windows/testing/test_keyboard.h"
16 #include "flutter/shell/platform/windows/testing/windows_test.h"
17 #include "flutter/third_party/accessibility/ax/platform/ax_platform_node_win.h"
18 #include "fml/synchronization/waitable_event.h"
19 #include "gmock/gmock.h"
20 #include "gtest/gtest.h"
21
22 // winbase.h defines GetCurrentTime as a macro.
23 #undef GetCurrentTime
24
25 namespace flutter {
26 namespace testing {
27
28 class FlutterWindowsEngineTest : public WindowsTest {};
29
30 TEST_F(FlutterWindowsEngineTest, RunDoesExpectedInitialization) {
31 FlutterWindowsEngineBuilder builder{GetContext()};
32 builder.AddDartEntrypointArgument("arg1");
33 builder.AddDartEntrypointArgument("arg2");
34
35 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
36 EngineModifier modifier(engine.get());
37
38 // The engine should be run with expected configuration values.
39 bool run_called = false;
40 modifier.embedder_api().Run = MOCK_ENGINE_PROC(
41 Run, ([&run_called, engine_instance = engine.get()](
42 size_t version, const FlutterRendererConfig* config,
43 const FlutterProjectArgs* args, void* user_data,
44 FLUTTER_API_SYMBOL(FlutterEngine) * engine_out) {
45 run_called = true;
46 *engine_out = reinterpret_cast<FLUTTER_API_SYMBOL(FlutterEngine)>(1);
47
48 EXPECT_EQ(version, FLUTTER_ENGINE_VERSION);
49 EXPECT_NE(config, nullptr);
50 // We have an AngleSurfaceManager, so this should be using OpenGL.
51 EXPECT_EQ(config->type, kOpenGL);
52 EXPECT_EQ(user_data, engine_instance);
53 // Spot-check arguments.
54 EXPECT_NE(args->assets_path, nullptr);
55 EXPECT_NE(args->icu_data_path, nullptr);
56 EXPECT_EQ(args->dart_entrypoint_argc, 2U);
57 EXPECT_EQ(strcmp(args->dart_entrypoint_argv[0], "arg1"), 0);
58 EXPECT_EQ(strcmp(args->dart_entrypoint_argv[1], "arg2"), 0);
59 EXPECT_NE(args->platform_message_callback, nullptr);
60 EXPECT_NE(args->custom_task_runners, nullptr);
61 EXPECT_NE(args->custom_task_runners->thread_priority_setter, nullptr);
62 EXPECT_EQ(args->custom_dart_entrypoint, nullptr);
63 EXPECT_NE(args->vsync_callback, nullptr);
64 EXPECT_EQ(args->update_semantics_callback, nullptr);
65 EXPECT_NE(args->update_semantics_callback2, nullptr);
66 EXPECT_EQ(args->update_semantics_node_callback, nullptr);
67 EXPECT_EQ(args->update_semantics_custom_action_callback, nullptr);
68
69 args->custom_task_runners->thread_priority_setter(
70 FlutterThreadPriority::kRaster);
71 EXPECT_EQ(GetThreadPriority(GetCurrentThread()),
72 THREAD_PRIORITY_ABOVE_NORMAL);
73 return kSuccess;
74 }));
75 // Accessibility updates must do nothing when the embedder engine is mocked
76 modifier.embedder_api().UpdateAccessibilityFeatures = MOCK_ENGINE_PROC(
77 UpdateAccessibilityFeatures,
78 [](FLUTTER_API_SYMBOL(FlutterEngine) engine,
79 FlutterAccessibilityFeature flags) { return kSuccess; });
80
81 // It should send locale info.
82 bool update_locales_called = false;
83 modifier.embedder_api().UpdateLocales = MOCK_ENGINE_PROC(
84 UpdateLocales,
85 ([&update_locales_called](auto engine, const FlutterLocale** locales,
86 size_t locales_count) {
87 update_locales_called = true;
88
89 EXPECT_GT(locales_count, 0);
90 EXPECT_NE(locales, nullptr);
91
92 return kSuccess;
93 }));
94
95 // And it should send initial settings info.
96 bool settings_message_sent = false;
97 modifier.embedder_api().SendPlatformMessage = MOCK_ENGINE_PROC(
98 SendPlatformMessage,
99 ([&settings_message_sent](auto engine, auto message) {
100 if (std::string(message->channel) == std::string("flutter/settings")) {
101 settings_message_sent = true;
102 }
103
104 return kSuccess;
105 }));
106
107 // And it should send display info.
108 bool notify_display_update_called = false;
109 modifier.SetFrameInterval(16600000); // 60 fps.
110 modifier.embedder_api().NotifyDisplayUpdate = MOCK_ENGINE_PROC(
111 NotifyDisplayUpdate,
112 ([&notify_display_update_called, engine_instance = engine.get()](
113 FLUTTER_API_SYMBOL(FlutterEngine) raw_engine,
114 const FlutterEngineDisplaysUpdateType update_type,
115 const FlutterEngineDisplay* embedder_displays,
116 size_t display_count) {
117 EXPECT_EQ(update_type, kFlutterEngineDisplaysUpdateTypeStartup);
118 EXPECT_EQ(display_count, 1);
119
120 FlutterEngineDisplay display = embedder_displays[0];
121
122 EXPECT_EQ(display.display_id, 0);
123 EXPECT_EQ(display.single_display, true);
124 EXPECT_EQ(std::floor(display.refresh_rate), 60.0);
125
126 notify_display_update_called = true;
127 return kSuccess;
128 }));
129
130 // Set the AngleSurfaceManager to !nullptr to test ANGLE rendering.
131 modifier.SetSurfaceManager(reinterpret_cast<AngleSurfaceManager*>(1));
132
133 engine->Run();
134
135 EXPECT_TRUE(run_called);
136 EXPECT_TRUE(update_locales_called);
137 EXPECT_TRUE(settings_message_sent);
138 EXPECT_TRUE(notify_display_update_called);
139
140 // Ensure that deallocation doesn't call the actual Shutdown with the bogus
141 // engine pointer that the overridden Run returned.
142 modifier.embedder_api().Shutdown = [](auto engine) { return kSuccess; };
143 modifier.ReleaseSurfaceManager();
144 }
145
146 TEST_F(FlutterWindowsEngineTest, ConfiguresFrameVsync) {
147 FlutterWindowsEngineBuilder builder{GetContext()};
148 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
149 EngineModifier modifier(engine.get());
150 bool on_vsync_called = false;
151
152 modifier.embedder_api().GetCurrentTime =
153 MOCK_ENGINE_PROC(GetCurrentTime, ([]() -> uint64_t { return 1; }));
154 modifier.embedder_api().OnVsync = MOCK_ENGINE_PROC(
155 OnVsync,
156 ([&on_vsync_called, engine_instance = engine.get()](
157 FLUTTER_API_SYMBOL(FlutterEngine) engine, intptr_t baton,
158 uint64_t frame_start_time_nanos, uint64_t frame_target_time_nanos) {
159 EXPECT_EQ(baton, 1);
160 EXPECT_EQ(frame_start_time_nanos, 16600000);
161 EXPECT_EQ(frame_target_time_nanos, 33200000);
162 on_vsync_called = true;
163 return kSuccess;
164 }));
165 modifier.SetStartTime(0);
166 modifier.SetFrameInterval(16600000);
167
168 engine->OnVsync(1);
169
170 EXPECT_TRUE(on_vsync_called);
171 }
172
173 TEST_F(FlutterWindowsEngineTest, RunWithoutANGLEUsesSoftware) {
174 FlutterWindowsEngineBuilder builder{GetContext()};
175 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
176 EngineModifier modifier(engine.get());
177
178 modifier.embedder_api().NotifyDisplayUpdate =
179 MOCK_ENGINE_PROC(NotifyDisplayUpdate,
180 ([engine_instance = engine.get()](
181 FLUTTER_API_SYMBOL(FlutterEngine) raw_engine,
182 const FlutterEngineDisplaysUpdateType update_type,
183 const FlutterEngineDisplay* embedder_displays,
184 size_t display_count) { return kSuccess; }));
185
186 // The engine should be run with expected configuration values.
187 bool run_called = false;
188 modifier.embedder_api().Run = MOCK_ENGINE_PROC(
189 Run, ([&run_called, engine_instance = engine.get()](
190 size_t version, const FlutterRendererConfig* config,
191 const FlutterProjectArgs* args, void* user_data,
192 FLUTTER_API_SYMBOL(FlutterEngine) * engine_out) {
193 run_called = true;
194 *engine_out = reinterpret_cast<FLUTTER_API_SYMBOL(FlutterEngine)>(1);
195 // We don't have an AngleSurfaceManager, so we should be using software.
196 EXPECT_EQ(config->type, kSoftware);
197 return kSuccess;
198 }));
199 // Accessibility updates must do nothing when the embedder engine is mocked
200 modifier.embedder_api().UpdateAccessibilityFeatures = MOCK_ENGINE_PROC(
201 UpdateAccessibilityFeatures,
202 [](FLUTTER_API_SYMBOL(FlutterEngine) engine,
203 FlutterAccessibilityFeature flags) { return kSuccess; });
204
205 // Stub out UpdateLocales and SendPlatformMessage as we don't have a fully
206 // initialized engine instance.
207 modifier.embedder_api().UpdateLocales = MOCK_ENGINE_PROC(
208 UpdateLocales, ([](auto engine, const FlutterLocale** locales,
209 size_t locales_count) { return kSuccess; }));
210 modifier.embedder_api().SendPlatformMessage =
211 MOCK_ENGINE_PROC(SendPlatformMessage,
212 ([](auto engine, auto message) { return kSuccess; }));
213
214 // Set the AngleSurfaceManager to nullptr to test software fallback path.
215 modifier.SetSurfaceManager(nullptr);
216
217 engine->Run();
218
219 EXPECT_TRUE(run_called);
220
221 // Ensure that deallocation doesn't call the actual Shutdown with the bogus
222 // engine pointer that the overridden Run returned.
223 modifier.embedder_api().Shutdown = [](auto engine) { return kSuccess; };
224 }
225
226 TEST_F(FlutterWindowsEngineTest, RunWithoutANGLEOnImpellerFailsToStart) {
227 FlutterWindowsEngineBuilder builder{GetContext()};
228 builder.SetSwitches({"--enable-impeller=true"});
229 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
230 EngineModifier modifier(engine.get());
231
232 modifier.embedder_api().NotifyDisplayUpdate =
233 MOCK_ENGINE_PROC(NotifyDisplayUpdate,
234 ([engine_instance = engine.get()](
235 FLUTTER_API_SYMBOL(FlutterEngine) raw_engine,
236 const FlutterEngineDisplaysUpdateType update_type,
237 const FlutterEngineDisplay* embedder_displays,
238 size_t display_count) { return kSuccess; }));
239
240 // Accessibility updates must do nothing when the embedder engine is mocked
241 modifier.embedder_api().UpdateAccessibilityFeatures = MOCK_ENGINE_PROC(
242 UpdateAccessibilityFeatures,
243 [](FLUTTER_API_SYMBOL(FlutterEngine) engine,
244 FlutterAccessibilityFeature flags) { return kSuccess; });
245
246 // Stub out UpdateLocales and SendPlatformMessage as we don't have a fully
247 // initialized engine instance.
248 modifier.embedder_api().UpdateLocales = MOCK_ENGINE_PROC(
249 UpdateLocales, ([](auto engine, const FlutterLocale** locales,
250 size_t locales_count) { return kSuccess; }));
251 modifier.embedder_api().SendPlatformMessage =
252 MOCK_ENGINE_PROC(SendPlatformMessage,
253 ([](auto engine, auto message) { return kSuccess; }));
254
255 // Set the AngleSurfaceManager to nullptr to test software fallback path.
256 modifier.SetSurfaceManager(nullptr);
257
258 EXPECT_FALSE(engine->Run());
259 }
260
261 TEST_F(FlutterWindowsEngineTest, SendPlatformMessageWithoutResponse) {
262 FlutterWindowsEngineBuilder builder{GetContext()};
263 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
264 EngineModifier modifier(engine.get());
265
266 const char* channel = "test";
267 const std::vector<uint8_t> test_message = {1, 2, 3, 4};
268
269 // Without a response, SendPlatformMessage should be a simple pass-through.
270 bool called = false;
271 modifier.embedder_api().SendPlatformMessage = MOCK_ENGINE_PROC(
272 SendPlatformMessage, ([&called, test_message](auto engine, auto message) {
273 called = true;
274 EXPECT_STREQ(message->channel, "test");
275 EXPECT_EQ(message->message_size, test_message.size());
276 EXPECT_EQ(memcmp(message->message, test_message.data(),
277 message->message_size),
278 0);
279 EXPECT_EQ(message->response_handle, nullptr);
280 return kSuccess;
281 }));
282
283 engine->SendPlatformMessage(channel, test_message.data(), test_message.size(),
284 nullptr, nullptr);
285 EXPECT_TRUE(called);
286 }
287
288 TEST_F(FlutterWindowsEngineTest, PlatformMessageRoundTrip) {
289 FlutterWindowsEngineBuilder builder{GetContext()};
290 builder.SetDartEntrypoint("hiPlatformChannels");
291
292 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
293 EngineModifier modifier(engine.get());
294 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
295
296 auto binary_messenger =
297 std::make_unique<BinaryMessengerImpl>(engine->messenger());
298
299 engine->Run();
300 bool did_call_callback = false;
301 bool did_call_reply = false;
302 bool did_call_dart_reply = false;
303 std::string channel = "hi";
304 binary_messenger->SetMessageHandler(
305 channel,
306 [&did_call_callback, &did_call_dart_reply](
307 const uint8_t* message, size_t message_size, BinaryReply reply) {
308 if (message_size == 5) {
309 EXPECT_EQ(message[0], static_cast<uint8_t>('h'));
310 char response[] = {'b', 'y', 'e'};
311 reply(reinterpret_cast<uint8_t*>(response), 3);
312 did_call_callback = true;
313 } else {
314 EXPECT_EQ(message_size, 3);
315 EXPECT_EQ(message[0], static_cast<uint8_t>('b'));
316 did_call_dart_reply = true;
317 }
318 });
319 char payload[] = {'h', 'e', 'l', 'l', 'o'};
320 binary_messenger->Send(
321 channel, reinterpret_cast<uint8_t*>(payload), 5,
322 [&did_call_reply](const uint8_t* reply, size_t reply_size) {
323 EXPECT_EQ(reply_size, 5);
324 EXPECT_EQ(reply[0], static_cast<uint8_t>('h'));
325 did_call_reply = true;
326 });
327 // Rely on timeout mechanism in CI.
328 while (!did_call_callback || !did_call_reply || !did_call_dart_reply) {
329 engine->task_runner()->ProcessTasks();
330 }
331 }
332
333 TEST_F(FlutterWindowsEngineTest, PlatformMessageRespondOnDifferentThread) {
334 FlutterWindowsEngineBuilder builder{GetContext()};
335 builder.SetDartEntrypoint("hiPlatformChannels");
336
337 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
338
339 EngineModifier modifier(engine.get());
340 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
341
342 auto binary_messenger =
343 std::make_unique<BinaryMessengerImpl>(engine->messenger());
344
345 engine->Run();
346 bool did_call_callback = false;
347 bool did_call_reply = false;
348 bool did_call_dart_reply = false;
349 std::string channel = "hi";
350 std::unique_ptr<std::thread> reply_thread;
351 binary_messenger->SetMessageHandler(
352 channel,
353 [&did_call_callback, &did_call_dart_reply, &reply_thread](
354 const uint8_t* message, size_t message_size, BinaryReply reply) {
355 if (message_size == 5) {
356 EXPECT_EQ(message[0], static_cast<uint8_t>('h'));
357 reply_thread.reset(new std::thread([reply = std::move(reply)]() {
358 char response[] = {'b', 'y', 'e'};
359 reply(reinterpret_cast<uint8_t*>(response), 3);
360 }));
361 did_call_callback = true;
362 } else {
363 EXPECT_EQ(message_size, 3);
364 EXPECT_EQ(message[0], static_cast<uint8_t>('b'));
365 did_call_dart_reply = true;
366 }
367 });
368 char payload[] = {'h', 'e', 'l', 'l', 'o'};
369 binary_messenger->Send(
370 channel, reinterpret_cast<uint8_t*>(payload), 5,
371 [&did_call_reply](const uint8_t* reply, size_t reply_size) {
372 EXPECT_EQ(reply_size, 5);
373 EXPECT_EQ(reply[0], static_cast<uint8_t>('h'));
374 did_call_reply = true;
375 });
376 // Rely on timeout mechanism in CI.
377 while (!did_call_callback || !did_call_reply || !did_call_dart_reply) {
378 engine->task_runner()->ProcessTasks();
379 }
380 ASSERT_TRUE(reply_thread);
381 reply_thread->join();
382 }
383
384 TEST_F(FlutterWindowsEngineTest, SendPlatformMessageWithResponse) {
385 FlutterWindowsEngineBuilder builder{GetContext()};
386 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
387 EngineModifier modifier(engine.get());
388
389 const char* channel = "test";
390 const std::vector<uint8_t> test_message = {1, 2, 3, 4};
391 auto* dummy_response_handle =
392 reinterpret_cast<FlutterPlatformMessageResponseHandle*>(5);
393 const FlutterDesktopBinaryReply reply_handler = [](auto... args) {};
394 void* reply_user_data = reinterpret_cast<void*>(6);
395
396 // When a response is requested, a handle should be created, passed as part
397 // of the message, and then released.
398 bool create_response_handle_called = false;
399 modifier.embedder_api().PlatformMessageCreateResponseHandle =
400 MOCK_ENGINE_PROC(
401 PlatformMessageCreateResponseHandle,
402 ([&create_response_handle_called, &reply_handler, reply_user_data,
403 dummy_response_handle](auto engine, auto reply, auto user_data,
404 auto response_handle) {
405 create_response_handle_called = true;
406 EXPECT_EQ(reply, reply_handler);
407 EXPECT_EQ(user_data, reply_user_data);
408 EXPECT_NE(response_handle, nullptr);
409 *response_handle = dummy_response_handle;
410 return kSuccess;
411 }));
412 bool release_response_handle_called = false;
413 modifier.embedder_api().PlatformMessageReleaseResponseHandle =
414 MOCK_ENGINE_PROC(
415 PlatformMessageReleaseResponseHandle,
416 ([&release_response_handle_called, dummy_response_handle](
417 auto engine, auto response_handle) {
418 release_response_handle_called = true;
419 EXPECT_EQ(response_handle, dummy_response_handle);
420 return kSuccess;
421 }));
422 bool send_message_called = false;
423 modifier.embedder_api().SendPlatformMessage = MOCK_ENGINE_PROC(
424 SendPlatformMessage, ([&send_message_called, test_message,
425 dummy_response_handle](auto engine, auto message) {
426 send_message_called = true;
427 EXPECT_STREQ(message->channel, "test");
428 EXPECT_EQ(message->message_size, test_message.size());
429 EXPECT_EQ(memcmp(message->message, test_message.data(),
430 message->message_size),
431 0);
432 EXPECT_EQ(message->response_handle, dummy_response_handle);
433 return kSuccess;
434 }));
435
436 engine->SendPlatformMessage(channel, test_message.data(), test_message.size(),
437 reply_handler, reply_user_data);
438 EXPECT_TRUE(create_response_handle_called);
439 EXPECT_TRUE(release_response_handle_called);
440 EXPECT_TRUE(send_message_called);
441 }
442
443 TEST_F(FlutterWindowsEngineTest, DispatchSemanticsAction) {
444 FlutterWindowsEngineBuilder builder{GetContext()};
445 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
446 EngineModifier modifier(engine.get());
447
448 bool called = false;
449 std::string message = "Hello";
450 modifier.embedder_api().DispatchSemanticsAction = MOCK_ENGINE_PROC(
451 DispatchSemanticsAction,
452 ([&called, &message](auto engine, auto target, auto action, auto data,
453 auto data_length) {
454 called = true;
455 EXPECT_EQ(target, 42);
456 EXPECT_EQ(action, kFlutterSemanticsActionDismiss);
457 EXPECT_EQ(memcmp(data, message.c_str(), message.size()), 0);
458 EXPECT_EQ(data_length, message.size());
459 return kSuccess;
460 }));
461
462 auto data = fml::MallocMapping::Copy(message.c_str(), message.size());
463 engine->DispatchSemanticsAction(42, kFlutterSemanticsActionDismiss,
464 std::move(data));
465 EXPECT_TRUE(called);
466 }
467
468 TEST_F(FlutterWindowsEngineTest, SetsThreadPriority) {
469 WindowsPlatformThreadPrioritySetter(FlutterThreadPriority::kBackground);
470 EXPECT_EQ(GetThreadPriority(GetCurrentThread()),
471 THREAD_PRIORITY_BELOW_NORMAL);
472
473 WindowsPlatformThreadPrioritySetter(FlutterThreadPriority::kDisplay);
474 EXPECT_EQ(GetThreadPriority(GetCurrentThread()),
475 THREAD_PRIORITY_ABOVE_NORMAL);
476
477 WindowsPlatformThreadPrioritySetter(FlutterThreadPriority::kRaster);
478 EXPECT_EQ(GetThreadPriority(GetCurrentThread()),
479 THREAD_PRIORITY_ABOVE_NORMAL);
480
481 // FlutterThreadPriority::kNormal does not change thread priority, reset to 0
482 // here.
483 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
484
485 WindowsPlatformThreadPrioritySetter(FlutterThreadPriority::kNormal);
486 EXPECT_EQ(GetThreadPriority(GetCurrentThread()), THREAD_PRIORITY_NORMAL);
487 }
488
489 TEST_F(FlutterWindowsEngineTest, AddPluginRegistrarDestructionCallback) {
490 FlutterWindowsEngineBuilder builder{GetContext()};
491 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
492 EngineModifier modifier(engine.get());
493
494 MockEmbedderApiForKeyboard(modifier,
495 std::make_shared<MockKeyResponseController>());
496
497 engine->Run();
498
499 // Verify that destruction handlers don't overwrite each other.
500 int result1 = 0;
501 int result2 = 0;
502 engine->AddPluginRegistrarDestructionCallback(
503 [](FlutterDesktopPluginRegistrarRef ref) {
504 auto result = reinterpret_cast<int*>(ref);
505 *result = 1;
506 },
507 reinterpret_cast<FlutterDesktopPluginRegistrarRef>(&result1));
508 engine->AddPluginRegistrarDestructionCallback(
509 [](FlutterDesktopPluginRegistrarRef ref) {
510 auto result = reinterpret_cast<int*>(ref);
511 *result = 2;
512 },
513 reinterpret_cast<FlutterDesktopPluginRegistrarRef>(&result2));
514
515 engine->Stop();
516 EXPECT_EQ(result1, 1);
517 EXPECT_EQ(result2, 2);
518 }
519
520 TEST_F(FlutterWindowsEngineTest, ScheduleFrame) {
521 FlutterWindowsEngineBuilder builder{GetContext()};
522 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
523 EngineModifier modifier(engine.get());
524
525 bool called = false;
526 modifier.embedder_api().ScheduleFrame =
527 MOCK_ENGINE_PROC(ScheduleFrame, ([&called](auto engine) {
528 called = true;
529 return kSuccess;
530 }));
531
532 engine->ScheduleFrame();
533 EXPECT_TRUE(called);
534 }
535
536 TEST_F(FlutterWindowsEngineTest, SetNextFrameCallback) {
537 FlutterWindowsEngineBuilder builder{GetContext()};
538 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
539 EngineModifier modifier(engine.get());
540
541 bool called = false;
542 modifier.embedder_api().SetNextFrameCallback = MOCK_ENGINE_PROC(
543 SetNextFrameCallback, ([&called](auto engine, auto callback, auto data) {
544 called = true;
545 return kSuccess;
546 }));
547
548 engine->SetNextFrameCallback([]() {});
549 EXPECT_TRUE(called);
550 }
551
552 TEST_F(FlutterWindowsEngineTest, GetExecutableName) {
553 FlutterWindowsEngineBuilder builder{GetContext()};
554 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
555 EXPECT_EQ(engine->GetExecutableName(), "flutter_windows_unittests.exe");
556 }
557
558 // Ensure that after setting or resetting the high contrast feature,
559 // the corresponding status flag can be retrieved from the engine.
560 TEST_F(FlutterWindowsEngineTest, UpdateHighContrastFeature) {
561 FlutterWindowsEngineBuilder builder{GetContext()};
562 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
563 EngineModifier modifier(engine.get());
564
565 bool called = false;
566 modifier.embedder_api().UpdateAccessibilityFeatures = MOCK_ENGINE_PROC(
567 UpdateAccessibilityFeatures, ([&called](auto engine, auto flags) {
568 called = true;
569 return kSuccess;
570 }));
571
572 engine->UpdateHighContrastEnabled(true);
573 EXPECT_TRUE(
574 engine->EnabledAccessibilityFeatures() &
575 FlutterAccessibilityFeature::kFlutterAccessibilityFeatureHighContrast);
576 EXPECT_TRUE(engine->high_contrast_enabled());
577 EXPECT_TRUE(called);
578
579 engine->UpdateHighContrastEnabled(false);
580 EXPECT_FALSE(
581 engine->EnabledAccessibilityFeatures() &
582 FlutterAccessibilityFeature::kFlutterAccessibilityFeatureHighContrast);
583 EXPECT_FALSE(engine->high_contrast_enabled());
584 }
585
586 TEST_F(FlutterWindowsEngineTest, PostRasterThreadTask) {
587 FlutterWindowsEngineBuilder builder{GetContext()};
588 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
589 EngineModifier modifier(engine.get());
590
591 modifier.embedder_api().PostRenderThreadTask = MOCK_ENGINE_PROC(
592 PostRenderThreadTask, ([](auto engine, auto callback, auto context) {
593 callback(context);
594 return kSuccess;
595 }));
596
597 bool called = false;
598 engine->PostRasterThreadTask([&called]() { called = true; });
599
600 EXPECT_TRUE(called);
601 }
602
603 class MockFlutterWindowsView : public FlutterWindowsView {
604 public:
605 MockFlutterWindowsView(std::unique_ptr<WindowBindingHandler> wbh)
606 : FlutterWindowsView(std::move(wbh)) {}
607 ~MockFlutterWindowsView() {}
608
609 MOCK_METHOD(void,
610 NotifyWinEventWrapper,
611 (ui::AXPlatformNodeWin*, ax::mojom::Event),
612 (override));
613 MOCK_METHOD(PlatformWindow, GetPlatformWindow, (), (const, override));
614
615 private:
616 FML_DISALLOW_COPY_AND_ASSIGN(MockFlutterWindowsView);
617 };
618
619 TEST_F(FlutterWindowsEngineTest, AlertPlatformMessage) {
620 FlutterWindowsEngineBuilder builder{GetContext()};
621 builder.SetDartEntrypoint("alertPlatformChannel");
622
623 auto window_binding_handler =
624 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
625 ui::AXPlatformNodeDelegateBase parent_delegate;
626 AlertPlatformNodeDelegate delegate(parent_delegate);
627 ON_CALL(*window_binding_handler, GetAlertDelegate).WillByDefault([&delegate] {
628 return &delegate;
629 });
630 MockFlutterWindowsView view(std::move(window_binding_handler));
631 view.SetEngine(builder.Build());
632 FlutterWindowsEngine* engine = view.GetEngine();
633
634 EngineModifier modifier(engine);
635 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
636
637 auto binary_messenger =
638 std::make_unique<BinaryMessengerImpl>(engine->messenger());
639 binary_messenger->SetMessageHandler(
640 "semantics", [&engine](const uint8_t* message, size_t message_size,
641 BinaryReply reply) {
642 engine->UpdateSemanticsEnabled(true);
643 char response[] = "";
644 reply(reinterpret_cast<uint8_t*>(response), 0);
645 });
646
647 bool did_call = false;
648 ON_CALL(view, NotifyWinEventWrapper)
649 .WillByDefault([&did_call](ui::AXPlatformNodeWin* node,
650 ax::mojom::Event event) { did_call = true; });
651
652 engine->UpdateSemanticsEnabled(true);
653 engine->Run();
654
655 // Rely on timeout mechanism in CI.
656 while (!did_call) {
657 engine->task_runner()->ProcessTasks();
658 }
659 }
660
661 class MockWindowsLifecycleManager : public WindowsLifecycleManager {
662 public:
663 MockWindowsLifecycleManager(FlutterWindowsEngine* engine)
664 : WindowsLifecycleManager(engine) {}
665 virtual ~MockWindowsLifecycleManager() {}
666
667 MOCK_METHOD(
668 void,
669 Quit,
670 (std::optional<HWND>, std::optional<WPARAM>, std::optional<LPARAM>, UINT),
671 (override));
672 MOCK_METHOD(void, DispatchMessage, (HWND, UINT, WPARAM, LPARAM), (override));
673 MOCK_METHOD(bool, IsLastWindowOfProcess, (), (override));
674 MOCK_METHOD(void, SetLifecycleState, (AppLifecycleState), (override));
675
676 void BeginProcessingLifecycle() override {
677 WindowsLifecycleManager::BeginProcessingLifecycle();
678 if (begin_processing_callback) {
679 begin_processing_callback();
680 }
681 }
682
683 std::function<void()> begin_processing_callback = nullptr;
684 };
685
686 TEST_F(FlutterWindowsEngineTest, TestExit) {
687 FlutterWindowsEngineBuilder builder{GetContext()};
688 builder.SetDartEntrypoint("exitTestExit");
689 bool finished = false;
690
691 auto window_binding_handler =
692 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
693 MockFlutterWindowsView view(std::move(window_binding_handler));
694 view.SetEngine(builder.Build());
695 FlutterWindowsEngine* engine = view.GetEngine();
696
697 EngineModifier modifier(engine);
698 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
699 auto handler = std::make_unique<MockWindowsLifecycleManager>(engine);
700 ON_CALL(*handler, Quit)
701 .WillByDefault(
702 [&finished](std::optional<HWND> hwnd, std::optional<WPARAM> wparam,
703 std::optional<LPARAM> lparam,
704 UINT exit_code) { finished = exit_code == 0; });
705 ON_CALL(*handler, IsLastWindowOfProcess).WillByDefault([]() { return true; });
706 EXPECT_CALL(*handler, Quit).Times(1);
707 modifier.SetLifecycleManager(std::move(handler));
708
709 engine->lifecycle_manager()->BeginProcessingExit();
710
711 engine->Run();
712
713 engine->window_proc_delegate_manager()->OnTopLevelWindowProc(0, WM_CLOSE, 0,
714 0);
715
716 // The test will only succeed when this while loop exits. Otherwise it will
717 // timeout.
718 while (!finished) {
719 engine->task_runner()->ProcessTasks();
720 }
721 }
722
723 TEST_F(FlutterWindowsEngineTest, TestExitCancel) {
724 FlutterWindowsEngineBuilder builder{GetContext()};
725 builder.SetDartEntrypoint("exitTestCancel");
726 bool finished = false;
727 bool did_call = false;
728
729 auto window_binding_handler =
730 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
731 MockFlutterWindowsView view(std::move(window_binding_handler));
732 view.SetEngine(builder.Build());
733 FlutterWindowsEngine* engine = view.GetEngine();
734
735 EngineModifier modifier(engine);
736 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
737 auto handler = std::make_unique<MockWindowsLifecycleManager>(engine);
738 ON_CALL(*handler, Quit)
739 .WillByDefault([&finished](std::optional<HWND> hwnd,
740 std::optional<WPARAM> wparam,
741 std::optional<LPARAM> lparam,
742 UINT exit_code) { finished = true; });
743 ON_CALL(*handler, IsLastWindowOfProcess).WillByDefault([]() { return true; });
744 EXPECT_CALL(*handler, Quit).Times(0);
745 modifier.SetLifecycleManager(std::move(handler));
746 engine->lifecycle_manager()->BeginProcessingExit();
747
748 auto binary_messenger =
749 std::make_unique<BinaryMessengerImpl>(engine->messenger());
750 binary_messenger->SetMessageHandler(
751 "flutter/platform", [&did_call](const uint8_t* message,
752 size_t message_size, BinaryReply reply) {
753 std::string contents(message, message + message_size);
754 EXPECT_NE(contents.find("\"method\":\"System.exitApplication\""),
755 std::string::npos);
756 EXPECT_NE(contents.find("\"type\":\"required\""), std::string::npos);
757 EXPECT_NE(contents.find("\"exitCode\":0"), std::string::npos);
758 did_call = true;
759 char response[] = "";
760 reply(reinterpret_cast<uint8_t*>(response), 0);
761 });
762
763 engine->Run();
764
765 engine->window_proc_delegate_manager()->OnTopLevelWindowProc(0, WM_CLOSE, 0,
766 0);
767
768 while (!did_call) {
769 engine->task_runner()->ProcessTasks();
770 }
771
772 EXPECT_FALSE(finished);
773 }
774
775 TEST_F(FlutterWindowsEngineTest, TestExitSecondCloseMessage) {
776 FlutterWindowsEngineBuilder builder{GetContext()};
777 builder.SetDartEntrypoint("exitTestExit");
778 bool second_close = false;
779
780 auto window_binding_handler =
781 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
782 MockFlutterWindowsView view(std::move(window_binding_handler));
783 view.SetEngine(builder.Build());
784 FlutterWindowsEngine* engine = view.GetEngine();
785
786 EngineModifier modifier(engine);
787 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
788 auto handler = std::make_unique<MockWindowsLifecycleManager>(engine);
789 auto& handler_obj = *handler;
790 ON_CALL(handler_obj, IsLastWindowOfProcess).WillByDefault([]() {
791 return true;
792 });
793 ON_CALL(handler_obj, Quit)
794 .WillByDefault(
795 [&handler_obj](std::optional<HWND> hwnd, std::optional<WPARAM> wparam,
796 std::optional<LPARAM> lparam, UINT exit_code) {
797 handler_obj.WindowsLifecycleManager::Quit(hwnd, wparam, lparam,
798 exit_code);
799 });
800 ON_CALL(handler_obj, DispatchMessage)
801 .WillByDefault(
802 [&engine](HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
803 engine->window_proc_delegate_manager()->OnTopLevelWindowProc(
804 hwnd, msg, wparam, lparam);
805 });
806 modifier.SetLifecycleManager(std::move(handler));
807 engine->lifecycle_manager()->BeginProcessingExit();
808
809 engine->Run();
810
811 // This delegate will be registered after the lifecycle manager, so it will be
812 // called only when a message is not consumed by the lifecycle manager. This
813 // should be called on the second, synthesized WM_CLOSE message that the
814 // lifecycle manager posts.
815 engine->window_proc_delegate_manager()->RegisterTopLevelWindowProcDelegate(
816 [](HWND hwnd, UINT message, WPARAM wpar, LPARAM lpar, void* user_data,
817 LRESULT* result) {
818 switch (message) {
819 case WM_CLOSE: {
820 bool* called = reinterpret_cast<bool*>(user_data);
821 *called = true;
822 return true;
823 }
824 }
825 return false;
826 },
827 reinterpret_cast<void*>(&second_close));
828
829 engine->window_proc_delegate_manager()->OnTopLevelWindowProc(0, WM_CLOSE, 0,
830 0);
831
832 while (!second_close) {
833 engine->task_runner()->ProcessTasks();
834 }
835 }
836
837 TEST_F(FlutterWindowsEngineTest, TestExitCloseMultiWindow) {
838 FlutterWindowsEngineBuilder builder{GetContext()};
839 builder.SetDartEntrypoint("exitTestExit");
840 bool finished = false;
841
842 auto window_binding_handler =
843 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
844 MockFlutterWindowsView view(std::move(window_binding_handler));
845 view.SetEngine(builder.Build());
846 FlutterWindowsEngine* engine = view.GetEngine();
847
848 EngineModifier modifier(engine);
849 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
850 auto handler = std::make_unique<MockWindowsLifecycleManager>(engine);
851 ON_CALL(*handler, IsLastWindowOfProcess).WillByDefault([&finished]() {
852 finished = true;
853 return false;
854 });
855 // Quit should not be called when there is more than one window.
856 EXPECT_CALL(*handler, Quit).Times(0);
857 modifier.SetLifecycleManager(std::move(handler));
858 engine->lifecycle_manager()->BeginProcessingExit();
859
860 engine->Run();
861
862 engine->window_proc_delegate_manager()->OnTopLevelWindowProc(0, WM_CLOSE, 0,
863 0);
864
865 while (!finished) {
866 engine->task_runner()->ProcessTasks();
867 }
868 }
869
870 TEST_F(FlutterWindowsEngineTest, LifecycleManagerDisabledByDefault) {
871 FlutterWindowsEngineBuilder builder{GetContext()};
872
873 auto window_binding_handler =
874 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
875 MockFlutterWindowsView view(std::move(window_binding_handler));
876 view.SetEngine(builder.Build());
877 FlutterWindowsEngine* engine = view.GetEngine();
878
879 EngineModifier modifier(engine);
880 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
881 auto handler = std::make_unique<MockWindowsLifecycleManager>(engine);
882 EXPECT_CALL(*handler, IsLastWindowOfProcess).Times(0);
883 modifier.SetLifecycleManager(std::move(handler));
884
885 engine->window_proc_delegate_manager()->OnTopLevelWindowProc(0, WM_CLOSE, 0,
886 0);
887 }
888
889 TEST_F(FlutterWindowsEngineTest, EnableApplicationLifecycle) {
890 FlutterWindowsEngineBuilder builder{GetContext()};
891
892 auto window_binding_handler =
893 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
894 MockFlutterWindowsView view(std::move(window_binding_handler));
895 view.SetEngine(builder.Build());
896 FlutterWindowsEngine* engine = view.GetEngine();
897
898 EngineModifier modifier(engine);
899 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
900 auto handler = std::make_unique<MockWindowsLifecycleManager>(engine);
901 ON_CALL(*handler, IsLastWindowOfProcess).WillByDefault([]() {
902 return false;
903 });
904 EXPECT_CALL(*handler, IsLastWindowOfProcess).Times(1);
905 modifier.SetLifecycleManager(std::move(handler));
906 engine->lifecycle_manager()->BeginProcessingExit();
907
908 engine->window_proc_delegate_manager()->OnTopLevelWindowProc(0, WM_CLOSE, 0,
909 0);
910 }
911
912 TEST_F(FlutterWindowsEngineTest, ApplicationLifecycleExternalWindow) {
913 FlutterWindowsEngineBuilder builder{GetContext()};
914
915 auto window_binding_handler =
916 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
917 MockFlutterWindowsView view(std::move(window_binding_handler));
918 view.SetEngine(builder.Build());
919 FlutterWindowsEngine* engine = view.GetEngine();
920
921 EngineModifier modifier(engine);
922 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
923 auto handler = std::make_unique<MockWindowsLifecycleManager>(engine);
924 ON_CALL(*handler, IsLastWindowOfProcess).WillByDefault([]() {
925 return false;
926 });
927 EXPECT_CALL(*handler, IsLastWindowOfProcess).Times(1);
928 modifier.SetLifecycleManager(std::move(handler));
929 engine->lifecycle_manager()->BeginProcessingExit();
930
931 engine->lifecycle_manager()->ExternalWindowMessage(0, WM_CLOSE, 0, 0);
932 }
933
934 TEST_F(FlutterWindowsEngineTest, AppStartsInResumedState) {
935 FlutterWindowsEngineBuilder builder{GetContext()};
936
937 auto window_binding_handler =
938 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
939 MockFlutterWindowsView view(std::move(window_binding_handler));
940 view.SetEngine(builder.Build());
941 FlutterWindowsEngine* engine = view.GetEngine();
942
943 EngineModifier modifier(engine);
944 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
945 auto handler = std::make_unique<MockWindowsLifecycleManager>(engine);
946 EXPECT_CALL(*handler, SetLifecycleState(AppLifecycleState::kResumed))
947 .Times(1);
948 modifier.SetLifecycleManager(std::move(handler));
949 engine->Run();
950 }
951
952 TEST_F(FlutterWindowsEngineTest, LifecycleStateTransition) {
953 FlutterWindowsEngineBuilder builder{GetContext()};
954
955 auto window_binding_handler =
956 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
957 MockFlutterWindowsView view(std::move(window_binding_handler));
958 view.SetEngine(builder.Build());
959 FlutterWindowsEngine* engine = view.GetEngine();
960
961 EngineModifier modifier(engine);
962 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
963 engine->Run();
964
965 engine->window_proc_delegate_manager()->OnTopLevelWindowProc(
966 (HWND)1, WM_SIZE, SIZE_RESTORED, 0);
967 EXPECT_EQ(engine->lifecycle_manager()->GetLifecycleState(),
968 AppLifecycleState::kResumed);
969
970 engine->window_proc_delegate_manager()->OnTopLevelWindowProc(
971 (HWND)1, WM_SIZE, SIZE_MINIMIZED, 0);
972 EXPECT_EQ(engine->lifecycle_manager()->GetLifecycleState(),
973 AppLifecycleState::kHidden);
974
975 engine->window_proc_delegate_manager()->OnTopLevelWindowProc(
976 (HWND)1, WM_SIZE, SIZE_RESTORED, 0);
977 EXPECT_EQ(engine->lifecycle_manager()->GetLifecycleState(),
978 AppLifecycleState::kInactive);
979 }
980
981 TEST_F(FlutterWindowsEngineTest, ExternalWindowMessage) {
982 FlutterWindowsEngineBuilder builder{GetContext()};
983
984 auto window_binding_handler =
985 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
986 MockFlutterWindowsView view(std::move(window_binding_handler));
987 view.SetEngine(builder.Build());
988 FlutterWindowsEngine* engine = view.GetEngine();
989
990 EngineModifier modifier(engine);
991 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
992 // Sets lifecycle state to resumed.
993 engine->Run();
994
995 // Ensure HWND(1) is in the set of visible windows before hiding it.
996 engine->ProcessExternalWindowMessage(reinterpret_cast<HWND>(1), WM_SHOWWINDOW,
997 TRUE, NULL);
998 engine->ProcessExternalWindowMessage(reinterpret_cast<HWND>(1), WM_SHOWWINDOW,
999 FALSE, NULL);
1000
1001 EXPECT_EQ(engine->lifecycle_manager()->GetLifecycleState(),
1002 AppLifecycleState::kHidden);
1003 }
1004
1005 TEST_F(FlutterWindowsEngineTest, InnerWindowHidden) {
1006 FlutterWindowsEngineBuilder builder{GetContext()};
1007 HWND outer = reinterpret_cast<HWND>(1);
1008 HWND inner = reinterpret_cast<HWND>(2);
1009
1010 auto window_binding_handler =
1011 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
1012 MockFlutterWindowsView view(std::move(window_binding_handler));
1013 ON_CALL(view, GetPlatformWindow).WillByDefault([=]() { return inner; });
1014 view.SetEngine(builder.Build());
1015 FlutterWindowsEngine* engine = view.GetEngine();
1016
1017 EngineModifier modifier(engine);
1018 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1019 // Sets lifecycle state to resumed.
1020 engine->Run();
1021
1022 // Show both top-level and Flutter window.
1023 engine->window_proc_delegate_manager()->OnTopLevelWindowProc(
1024 outer, WM_SHOWWINDOW, TRUE, NULL);
1025 view.OnWindowStateEvent(inner, WindowStateEvent::kShow);
1026 view.OnWindowStateEvent(inner, WindowStateEvent::kFocus);
1027
1028 EXPECT_EQ(engine->lifecycle_manager()->GetLifecycleState(),
1029 AppLifecycleState::kResumed);
1030
1031 // Hide Flutter window, but not top level window.
1032 view.OnWindowStateEvent(inner, WindowStateEvent::kHide);
1033
1034 // The top-level window is still visible, so we ought not enter hidden state.
1035 EXPECT_EQ(engine->lifecycle_manager()->GetLifecycleState(),
1036 AppLifecycleState::kInactive);
1037 }
1038
1039 TEST_F(FlutterWindowsEngineTest, EnableLifecycleState) {
1040 FlutterWindowsEngineBuilder builder{GetContext()};
1041 builder.SetDartEntrypoint("enableLifecycleTest");
1042 bool finished = false;
1043
1044 auto window_binding_handler =
1045 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
1046 MockFlutterWindowsView view(std::move(window_binding_handler));
1047 view.SetEngine(builder.Build());
1048 FlutterWindowsEngine* engine = view.GetEngine();
1049
1050 EngineModifier modifier(engine);
1051 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1052 auto handler = std::make_unique<MockWindowsLifecycleManager>(engine);
1053 ON_CALL(*handler, SetLifecycleState)
1054 .WillByDefault([handler_ptr = handler.get()](AppLifecycleState state) {
1055 handler_ptr->WindowsLifecycleManager::SetLifecycleState(state);
1056 });
1057 modifier.SetLifecycleManager(std::move(handler));
1058
1059 auto binary_messenger =
1060 std::make_unique<BinaryMessengerImpl>(engine->messenger());
1061 // Mark the test only as completed on receiving an inactive state message.
1062 binary_messenger->SetMessageHandler(
1063 "flutter/unittest", [&finished](const uint8_t* message,
1064 size_t message_size, BinaryReply reply) {
1065 std::string contents(message, message + message_size);
1066 EXPECT_NE(contents.find("AppLifecycleState.inactive"),
1067 std::string::npos);
1068 finished = true;
1069 char response[] = "";
1070 reply(reinterpret_cast<uint8_t*>(response), 0);
1071 });
1072
1073 engine->Run();
1074
1075 // Test that setting the state before enabling lifecycle does nothing.
1076 HWND hwnd = reinterpret_cast<HWND>(1);
1077 view.OnWindowStateEvent(hwnd, WindowStateEvent::kShow);
1078 view.OnWindowStateEvent(hwnd, WindowStateEvent::kHide);
1079 EXPECT_FALSE(finished);
1080
1081 // Test that we can set the state afterwards.
1082
1083 engine->lifecycle_manager()->BeginProcessingLifecycle();
1084 view.OnWindowStateEvent(hwnd, WindowStateEvent::kShow);
1085
1086 while (!finished) {
1087 engine->task_runner()->ProcessTasks();
1088 }
1089 }
1090
1091 TEST_F(FlutterWindowsEngineTest, LifecycleStateToFrom) {
1092 FlutterWindowsEngineBuilder builder{GetContext()};
1093 builder.SetDartEntrypoint("enableLifecycleToFrom");
1094 bool enabled_lifecycle = false;
1095 bool dart_responded = false;
1096
1097 auto window_binding_handler =
1098 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
1099 MockFlutterWindowsView view(std::move(window_binding_handler));
1100 view.SetEngine(builder.Build());
1101 FlutterWindowsEngine* engine = view.GetEngine();
1102
1103 EngineModifier modifier(engine);
1104 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1105 auto handler = std::make_unique<MockWindowsLifecycleManager>(engine);
1106 ON_CALL(*handler, SetLifecycleState)
1107 .WillByDefault([handler_ptr = handler.get()](AppLifecycleState state) {
1108 handler_ptr->WindowsLifecycleManager::SetLifecycleState(state);
1109 });
1110 handler->begin_processing_callback = [&]() { enabled_lifecycle = true; };
1111 modifier.SetLifecycleManager(std::move(handler));
1112
1113 auto binary_messenger =
1114 std::make_unique<BinaryMessengerImpl>(engine->messenger());
1115 binary_messenger->SetMessageHandler(
1116 "flutter/unittest",
1117 [&](const uint8_t* message, size_t message_size, BinaryReply reply) {
1118 std::string contents(message, message + message_size);
1119 EXPECT_NE(contents.find("AppLifecycleState."), std::string::npos);
1120 dart_responded = true;
1121 char response[] = "";
1122 reply(reinterpret_cast<uint8_t*>(response), 0);
1123 });
1124
1125 engine->Run();
1126
1127 while (!enabled_lifecycle) {
1128 engine->task_runner()->ProcessTasks();
1129 }
1130
1131 HWND hwnd = reinterpret_cast<HWND>(1);
1132 view.OnWindowStateEvent(hwnd, WindowStateEvent::kShow);
1133 view.OnWindowStateEvent(hwnd, WindowStateEvent::kHide);
1134
1135 while (!dart_responded) {
1136 engine->task_runner()->ProcessTasks();
1137 }
1138 }
1139
1140 TEST_F(FlutterWindowsEngineTest, ChannelListenedTo) {
1141 FlutterWindowsEngineBuilder builder{GetContext()};
1142 builder.SetDartEntrypoint("enableLifecycleToFrom");
1143
1144 auto window_binding_handler =
1145 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
1146 MockFlutterWindowsView view(std::move(window_binding_handler));
1147 view.SetEngine(builder.Build());
1148 FlutterWindowsEngine* engine = view.GetEngine();
1149 EngineModifier modifier(engine);
1150 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1151
1152 bool lifecycle_began = false;
1153 auto handler = std::make_unique<MockWindowsLifecycleManager>(engine);
1154 handler->begin_processing_callback = [&]() { lifecycle_began = true; };
1155 modifier.SetLifecycleManager(std::move(handler));
1156
1157 engine->Run();
1158
1159 while (!lifecycle_began) {
1160 engine->task_runner()->ProcessTasks();
1161 }
1162 }
1163
1164 } // namespace testing
1165 } // namespace flutter
flutter::WindowsLifecycleManager::GetLifecycleState
AppLifecycleState GetLifecycleState()
Definition: windows_lifecycle_manager.h:75
flutter::AlertPlatformNodeDelegate
Definition: alert_platform_node_delegate.h:18
flutter::AppLifecycleState::kHidden
@ kHidden
flutter::WindowStateEvent::kHide
@ kHide
flutter::FlutterWindowsView
Definition: flutter_windows_view.h:35
flutter::FlutterEngine
Definition: flutter_engine.h:28
FlutterDesktopBinaryReply
void(* FlutterDesktopBinaryReply)(const uint8_t *data, size_t data_size, void *user_data)
Definition: flutter_messenger.h:26
flutter::testing::MockFlutterWindowsView::~MockFlutterWindowsView
~MockFlutterWindowsView()
Definition: flutter_windows_engine_unittests.cc:607
flutter::FlutterWindowsEngine::task_runner
TaskRunner * task_runner()
Definition: flutter_windows_engine.h:134
user_data
void * user_data
Definition: flutter_windows_view_unittests.cc:47
flutter::FlutterWindowsEngine
Definition: flutter_windows_engine.h:78
flutter::WindowProcDelegateManager::OnTopLevelWindowProc
std::optional< LRESULT > OnTopLevelWindowProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
Definition: window_proc_delegate_manager.cc:25
flutter::FlutterWindowsEngine::window_proc_delegate_manager
WindowProcDelegateManager * window_proc_delegate_manager()
Definition: flutter_windows_engine.h:144
flutter::FlutterWindowsEngine::lifecycle_manager
WindowsLifecycleManager * lifecycle_manager()
Definition: flutter_windows_engine.h:273
flutter::WindowsLifecycleManager::BeginProcessingLifecycle
virtual void BeginProcessingLifecycle()
Definition: windows_lifecycle_manager.cc:187
flutter::WindowProcDelegateManager::RegisterTopLevelWindowProcDelegate
void RegisterTopLevelWindowProcDelegate(FlutterDesktopWindowProcCallback delegate, void *user_data)
Definition: window_proc_delegate_manager.cc:14
flutter::testing::MockFlutterWindowsView::MockFlutterWindowsView
MockFlutterWindowsView(std::unique_ptr< WindowBindingHandler > wbh)
Definition: flutter_windows_engine_unittests.cc:605
flutter::testing::MockWindowsLifecycleManager::begin_processing_callback
std::function< void()> begin_processing_callback
Definition: flutter_windows_engine_unittests.cc:683
flutter::testing::MockWindowsLifecycleManager
Definition: flutter_windows_engine_unittests.cc:661
flutter::FlutterWindowsEngine::messenger
FlutterDesktopMessengerRef messenger()
Definition: flutter_windows_engine.h:128
flutter::FlutterWindowsEngine::ProcessExternalWindowMessage
std::optional< LRESULT > ProcessExternalWindowMessage(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
Definition: flutter_windows_engine.cc:814
flutter::FlutterEngine::Run
bool Run()
Definition: flutter_engine.cc:44
flutter::WindowsLifecycleManager::DispatchMessage
virtual void DispatchMessage(HWND window, UINT msg, WPARAM wparam, LPARAM lparam)
Definition: windows_lifecycle_manager.cc:34
flutter::AngleSurfaceManager
Definition: angle_surface_manager.h:28
flutter::PlatformWindow
HWND PlatformWindow
Definition: window_binding_handler.h:40
flutter::testing::MockWindowsLifecycleManager::MockWindowsLifecycleManager
MockWindowsLifecycleManager(FlutterWindowsEngine *engine)
Definition: flutter_windows_engine_unittests.cc:663
flutter_windows_view.h
flutter::testing::TEST_F
TEST_F(CursorHandlerTest, ActivateSystemCursor)
Definition: cursor_handler_unittests.cc:95
flutter::WindowsLifecycleManager::SetLifecycleState
virtual void SetLifecycleState(AppLifecycleState state)
Definition: windows_lifecycle_manager.cc:198
flutter::WindowStateEvent::kFocus
@ kFocus
flutter::AppLifecycleState::kInactive
@ kInactive
flutter::WindowsLifecycleManager::ExternalWindowMessage
std::optional< LRESULT > ExternalWindowMessage(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
Definition: windows_lifecycle_manager.cc:259
flutter::WindowStateEvent::kShow
@ kShow
flutter::testing::FlutterWindowsEngineTest
Definition: flutter_windows_engine_unittests.cc:28
flutter::BinaryReply
std::function< void(const uint8_t *reply, size_t reply_size)> BinaryReply
Definition: binary_messenger.h:17
flutter::testing::MockWindowsLifecycleManager::~MockWindowsLifecycleManager
virtual ~MockWindowsLifecycleManager()
Definition: flutter_windows_engine_unittests.cc:665
flutter::TaskRunner::ProcessTasks
std::chrono::nanoseconds ProcessTasks()
Definition: task_runner.cc:25
flutter
Definition: accessibility_bridge_windows.cc:11
flutter::WindowsLifecycleManager::IsLastWindowOfProcess
virtual bool IsLastWindowOfProcess()
Definition: windows_lifecycle_manager.cc:164
flutter_windows_engine.h
flutter::WindowsLifecycleManager::Quit
virtual void Quit(std::optional< HWND > window, std::optional< WPARAM > wparam, std::optional< LPARAM > lparam, UINT exit_code)
Definition: windows_lifecycle_manager.cc:21
flutter::WindowsLifecycleManager::BeginProcessingExit
virtual void BeginProcessingExit()
Definition: windows_lifecycle_manager.cc:191
flutter::AppLifecycleState::kResumed
@ kResumed
flutter_windows.h
message
Win32Message message
Definition: keyboard_unittests.cc:137
action
int action
Definition: keyboard_key_handler_unittests.cc:116
flutter::AppLifecycleState
AppLifecycleState
Definition: app_lifecycle_state.h:32
flutter::FlutterWindowsEngine::UpdateSemanticsEnabled
void UpdateSemanticsEnabled(bool enabled)
Definition: flutter_windows_engine.cc:711
flutter::testing::MockWindowsLifecycleManager::MOCK_METHOD
MOCK_METHOD(void, Quit,(std::optional< HWND >, std::optional< WPARAM >, std::optional< LPARAM >, UINT),(override))
flutter::WindowsLifecycleManager
Definition: windows_lifecycle_manager.h:37
flutter::testing::MockWindowsLifecycleManager::BeginProcessingLifecycle
void BeginProcessingLifecycle() override
Definition: flutter_windows_engine_unittests.cc:676
FlutterDesktopPluginRegistrar
Definition: window_state.h:31
flutter::FlutterWindowsEngine::Run
bool Run()
Definition: flutter_windows_engine.cc:246
flutter::WindowsPlatformThreadPrioritySetter
static void WindowsPlatformThreadPrioritySetter(FlutterThreadPriority priority)
Definition: flutter_windows_engine.h:48
callback
FlutterDesktopBinaryReply callback
Definition: flutter_windows_view_unittests.cc:46