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