| 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 <thread>
6 #include "flutter/shell/platform/windows/flutter_windows_engine.h"
7
8 #include "flutter/fml/logging.h"
9 #include "flutter/fml/macros.h"
10 #include "flutter/shell/platform/embedder/embedder.h"
11 #include "flutter/shell/platform/embedder/test_utils/proc_table_replacement.h"
12 #include "flutter/shell/platform/windows/flutter_windows_view.h"
13 #include "flutter/shell/platform/windows/public/flutter_windows.h"
14 #include "flutter/shell/platform/windows/testing/egl/mock_manager.h"
15 #include "flutter/shell/platform/windows/testing/engine_modifier.h"
16 #include "flutter/shell/platform/windows/testing/flutter_windows_engine_builder.h"
17 #include "flutter/shell/platform/windows/testing/mock_platform_view_manager.h"
18 #include "flutter/shell/platform/windows/testing/mock_window_binding_handler.h"
19 #include "flutter/shell/platform/windows/testing/mock_windows_proc_table.h"
20 #include "flutter/shell/platform/windows/testing/test_keyboard.h"
21 #include "flutter/shell/platform/windows/testing/windows_test.h"
22 #include "flutter/shell/platform/windows/testing/windows_test_config_builder.h"
23 #include "flutter/third_party/accessibility/ax/platform/ax_platform_node_win.h"
24 #include "fml/synchronization/waitable_event.h"
25 #include "gmock/gmock.h"
26 #include "gtest/gtest.h"
27
28 // winbase.h defines GetCurrentTime as a macro.
29 #undef GetCurrentTime
30
31 namespace {
32 // Process the next win32 message if there is one. This can be used to
33 // pump the Windows platform thread task runner.
34 void PumpMessage() {
35 ::MSG msg;
36 if (::GetMessage(&msg, nullptr, 0, 0)) {
37 ::TranslateMessage(&msg);
38 ::DispatchMessage(&msg);
39 }
40 }
41 } // namespace
42
43 namespace flutter {
44 namespace testing {
45
46 using ::testing::_;
47 using ::testing::DoAll;
48 using ::testing::NiceMock;
49 using ::testing::Return;
50 using ::testing::SetArgPointee;
51
52 class FlutterWindowsEngineTest : public WindowsTest {};
53
54 // The engine can be run without any views.
55 TEST_F(FlutterWindowsEngineTest, RunHeadless) {
56 FlutterWindowsEngineBuilder builder{GetContext()};
57 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
58
59 EngineModifier modifier(engine.get());
60 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
61
62 ASSERT_TRUE(engine->Run());
63 ASSERT_EQ(engine->view(kImplicitViewId), nullptr);
64 ASSERT_EQ(engine->view(123), nullptr);
65 }
66
67 TEST_F(FlutterWindowsEngineTest, TaskRunnerDelayedTask) {
68 bool finished = false;
69 auto runner = std::make_unique<TaskRunner>(
70 [] {
71 return static_cast<uint64_t>(
72 fml::TimePoint::Now().ToEpochDelta().ToNanoseconds());
73 },
74 [&](const FlutterTask*) { finished = true; });
75 runner->PostFlutterTask(
76 FlutterTask{},
77 static_cast<uint64_t>((fml::TimePoint::Now().ToEpochDelta() +
78 fml::TimeDelta::FromMilliseconds(50))
79 .ToNanoseconds()));
80 auto start = fml::TimePoint::Now();
81 while (!finished) {
82 PumpMessage();
83 }
84 auto duration = fml::TimePoint::Now() - start;
85 EXPECT_GE(duration, fml::TimeDelta::FromMilliseconds(50));
86 }
87
88 // https://github.com/flutter/flutter/issues/173843)
89 TEST_F(FlutterWindowsEngineTest, TaskRunnerDoesNotDeadlock) {
90 auto runner = std::make_unique<TaskRunner>(
91 [] {
92 return static_cast<uint64_t>(
93 fml::TimePoint::Now().ToEpochDelta().ToNanoseconds());
94 },
95 [&](const FlutterTask*) {});
96
97 struct RunnerHolder {
98 void PostTaskLoop() {
99 runner->PostTask([this] { PostTaskLoop(); });
100 }
101 std::unique_ptr<TaskRunner> runner;
102 };
103
104 RunnerHolder container{.runner = std::move(runner)};
105 // Spam flutter tasks.
106 container.PostTaskLoop();
107
108 const LPCWSTR class_name = L"FlutterTestWindowClass";
109 WNDCLASS wc = {0};
110 wc.lpfnWndProc = DefWindowProc;
111 wc.lpszClassName = class_name;
112 RegisterClass(&wc);
113
114 HWND window;
115 container.runner->PostTask([&] {
116 window = CreateWindowEx(0, class_name, L"Empty Window", WS_OVERLAPPEDWINDOW,
117 CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, nullptr,
118 nullptr, nullptr, nullptr);
119 ShowWindow(window, SW_SHOW);
120 });
121
122 while (true) {
123 ::MSG msg;
124 if (::GetMessage(&msg, nullptr, 0, 0)) {
125 if (msg.message == WM_PAINT) {
126 break;
127 }
128 ::TranslateMessage(&msg);
129 ::DispatchMessage(&msg);
130 }
131 }
132
133 DestroyWindow(window);
134 UnregisterClassW(class_name, nullptr);
135 }
136
137 TEST_F(FlutterWindowsEngineTest, RunDoesExpectedInitialization) {
138 FlutterWindowsEngineBuilder builder{GetContext()};
139 builder.AddDartEntrypointArgument("arg1");
140 builder.AddDartEntrypointArgument("arg2");
141
142 auto windows_proc_table = std::make_shared<MockWindowsProcTable>();
143
144 HMONITOR mock_monitor = reinterpret_cast<HMONITOR>(1);
145
146 MONITORINFOEXW monitor_info = {};
147 monitor_info.cbSize = sizeof(MONITORINFOEXW);
148 monitor_info.rcMonitor = {0, 0, 1920, 1080};
149 monitor_info.rcWork = {0, 0, 1920, 1080};
150 monitor_info.dwFlags = MONITORINFOF_PRIMARY;
151 wcscpy_s(monitor_info.szDevice, L"\\\\.\\DISPLAY1");
152
153 EXPECT_CALL(*windows_proc_table, GetMonitorInfoW(mock_monitor, _))
154 .WillRepeatedly(DoAll(SetArgPointee<1>(monitor_info), Return(TRUE)));
155
156 EXPECT_CALL(*windows_proc_table, EnumDisplayMonitors(nullptr, nullptr, _, _))
157 .WillRepeatedly([&](HDC hdc, LPCRECT lprcClip, MONITORENUMPROC lpfnEnum,
158 LPARAM dwData) {
159 lpfnEnum(mock_monitor, nullptr, &monitor_info.rcMonitor, dwData);
160 return TRUE;
161 });
162
163 EXPECT_CALL(*windows_proc_table, GetDpiForMonitor(mock_monitor, _))
164 .WillRepeatedly(Return(96));
165
166 // Mock locale information
167 EXPECT_CALL(*windows_proc_table, GetThreadPreferredUILanguages(_, _, _, _))
168 .WillRepeatedly(
169 [](DWORD flags, PULONG count, PZZWSTR languages, PULONG length) {
170 // We need to mock the locale information twice because the first
171 // call is to get the size and the second call is to fill the
172 // buffer.
173 if (languages == nullptr) {
174 // First call is to get the size
175 *count = 1; // One language
176 *length = 10; // "fr-FR\0\0" (double null-terminated)
177 return TRUE;
178 } else {
179 // Second call is to fill the buffer
180 *count = 1;
181 // Fill with "fr-FR\0\0" (double null-terminated)
182 wchar_t* lang_buffer = languages;
183 wcscpy(lang_buffer, L"fr-FR");
184 // Move past the first null terminator to add the second
185 lang_buffer += wcslen(L"fr-FR") + 1;
186 *lang_buffer = L'\0';
187 return TRUE;
188 }
189 });
190
191 builder.SetWindowsProcTable(windows_proc_table);
192
193 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
194 EngineModifier modifier(engine.get());
195
196 // The engine should be run with expected configuration values.
197 bool run_called = false;
198 modifier.embedder_api().Run = MOCK_ENGINE_PROC(
199 Run, ([&run_called, engine_instance = engine.get()](
200 size_t version, const FlutterRendererConfig* config,
201 const FlutterProjectArgs* args, void* user_data,
202 FLUTTER_API_SYMBOL(FlutterEngine) * engine_out) {
203 run_called = true;
204 *engine_out = reinterpret_cast<FLUTTER_API_SYMBOL(FlutterEngine)>(1);
205
206 EXPECT_EQ(version, FLUTTER_ENGINE_VERSION);
207 EXPECT_NE(config, nullptr);
208 // We have an EGL manager, so this should be using OpenGL.
209 EXPECT_EQ(config->type, kOpenGL);
210 EXPECT_EQ(user_data, engine_instance);
211 // Spot-check arguments.
212 EXPECT_NE(args->assets_path, nullptr);
213 EXPECT_NE(args->icu_data_path, nullptr);
214 EXPECT_EQ(args->dart_entrypoint_argc, 2U);
215 EXPECT_EQ(strcmp(args->dart_entrypoint_argv[0], "arg1"), 0);
216 EXPECT_EQ(strcmp(args->dart_entrypoint_argv[1], "arg2"), 0);
217 EXPECT_NE(args->platform_message_callback, nullptr);
218 EXPECT_NE(args->custom_task_runners, nullptr);
219 EXPECT_NE(args->custom_task_runners->thread_priority_setter, nullptr);
220 EXPECT_EQ(args->custom_dart_entrypoint, nullptr);
221 EXPECT_NE(args->vsync_callback, nullptr);
222 EXPECT_EQ(args->update_semantics_callback, nullptr);
223 EXPECT_NE(args->update_semantics_callback2, nullptr);
224 EXPECT_EQ(args->update_semantics_node_callback, nullptr);
225 EXPECT_EQ(args->update_semantics_custom_action_callback, nullptr);
226 EXPECT_NE(args->view_focus_change_request_callback, nullptr);
227
228 args->custom_task_runners->thread_priority_setter(
229 FlutterThreadPriority::kRaster);
230 EXPECT_EQ(GetThreadPriority(GetCurrentThread()),
231 THREAD_PRIORITY_ABOVE_NORMAL);
232 return kSuccess;
233 }));
234 // Accessibility updates must do nothing when the embedder engine is mocked
235 modifier.embedder_api().UpdateAccessibilityFeatures = MOCK_ENGINE_PROC(
236 UpdateAccessibilityFeatures,
237 [](FLUTTER_API_SYMBOL(FlutterEngine) engine,
238 FlutterAccessibilityFeature flags) { return kSuccess; });
239
240 // It should send locale info.
241 bool update_locales_called = false;
242 modifier.embedder_api().UpdateLocales = MOCK_ENGINE_PROC(
243 UpdateLocales,
244 ([&update_locales_called](auto engine, const FlutterLocale** locales,
245 size_t locales_count) {
246 update_locales_called = true;
247
248 EXPECT_GT(locales_count, 0);
249 EXPECT_NE(locales, nullptr);
250
251 return kSuccess;
252 }));
253
254 // And it should send initial settings info.
255 bool settings_message_sent = false;
256 modifier.embedder_api().SendPlatformMessage = MOCK_ENGINE_PROC(
257 SendPlatformMessage,
258 ([&settings_message_sent](auto engine, auto message) {
259 if (std::string(message->channel) == std::string("flutter/settings")) {
260 settings_message_sent = true;
261 }
262
263 return kSuccess;
264 }));
265
266 // And it should send display info.
267 bool notify_display_update_called = false;
268
269 modifier.embedder_api().NotifyDisplayUpdate = MOCK_ENGINE_PROC(
270 NotifyDisplayUpdate,
271 ([&notify_display_update_called](
272 FLUTTER_API_SYMBOL(FlutterEngine) raw_engine,
273 const FlutterEngineDisplaysUpdateType update_type,
274 const FlutterEngineDisplay* embedder_displays,
275 size_t display_count) {
276 EXPECT_EQ(update_type, kFlutterEngineDisplaysUpdateTypeStartup);
277 notify_display_update_called = true;
278 return kSuccess;
279 }));
280
281 // Set the EGL manager to !nullptr to test ANGLE rendering.
282 modifier.SetEGLManager(std::make_unique<egl::MockManager>());
283
284 engine->Run();
285
286 EXPECT_TRUE(run_called);
287 EXPECT_TRUE(update_locales_called);
288 EXPECT_TRUE(settings_message_sent);
289 EXPECT_TRUE(notify_display_update_called);
290
291 // Ensure that deallocation doesn't call the actual Shutdown with the bogus
292 // engine pointer that the overridden Run returned.
293 modifier.embedder_api().Shutdown = [](auto engine) { return kSuccess; };
294 modifier.ReleaseEGLManager();
295 }
296
297 TEST_F(FlutterWindowsEngineTest, ConfiguresFrameVsync) {
298 FlutterWindowsEngineBuilder builder{GetContext()};
299 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
300 EngineModifier modifier(engine.get());
301 bool on_vsync_called = false;
302
303 modifier.embedder_api().GetCurrentTime =
304 MOCK_ENGINE_PROC(GetCurrentTime, ([]() -> uint64_t { return 1; }));
305 modifier.embedder_api().OnVsync = MOCK_ENGINE_PROC(
306 OnVsync,
307 ([&on_vsync_called, engine_instance = engine.get()](
308 FLUTTER_API_SYMBOL(FlutterEngine) engine, intptr_t baton,
309 uint64_t frame_start_time_nanos, uint64_t frame_target_time_nanos) {
310 EXPECT_EQ(baton, 1);
311 EXPECT_EQ(frame_start_time_nanos, 16600000);
312 EXPECT_EQ(frame_target_time_nanos, 33200000);
313 on_vsync_called = true;
314 return kSuccess;
315 }));
316 modifier.SetStartTime(0);
317 modifier.SetFrameInterval(16600000);
318
319 engine->OnVsync(1);
320
321 EXPECT_TRUE(on_vsync_called);
322 }
323
324 TEST_F(FlutterWindowsEngineTest, RunWithoutANGLEUsesSoftware) {
325 FlutterWindowsEngineBuilder builder{GetContext()};
326 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
327 EngineModifier modifier(engine.get());
328
329 modifier.embedder_api().NotifyDisplayUpdate =
330 MOCK_ENGINE_PROC(NotifyDisplayUpdate,
331 ([engine_instance = engine.get()](
332 FLUTTER_API_SYMBOL(FlutterEngine) raw_engine,
333 const FlutterEngineDisplaysUpdateType update_type,
334 const FlutterEngineDisplay* embedder_displays,
335 size_t display_count) { return kSuccess; }));
336
337 // The engine should be run with expected configuration values.
338 bool run_called = false;
339 modifier.embedder_api().Run = MOCK_ENGINE_PROC(
340 Run, ([&run_called, engine_instance = engine.get()](
341 size_t version, const FlutterRendererConfig* config,
342 const FlutterProjectArgs* args, void* user_data,
343 FLUTTER_API_SYMBOL(FlutterEngine) * engine_out) {
344 run_called = true;
345 *engine_out = reinterpret_cast<FLUTTER_API_SYMBOL(FlutterEngine)>(1);
346 // We don't have an EGL Manager, so we should be using software.
347 EXPECT_EQ(config->type, kSoftware);
348 return kSuccess;
349 }));
350 // Accessibility updates must do nothing when the embedder engine is mocked
351 modifier.embedder_api().UpdateAccessibilityFeatures = MOCK_ENGINE_PROC(
352 UpdateAccessibilityFeatures,
353 [](FLUTTER_API_SYMBOL(FlutterEngine) engine,
354 FlutterAccessibilityFeature flags) { return kSuccess; });
355
356 // Stub out UpdateLocales and SendPlatformMessage as we don't have a fully
357 // initialized engine instance.
358 modifier.embedder_api().UpdateLocales = MOCK_ENGINE_PROC(
359 UpdateLocales, ([](auto engine, const FlutterLocale** locales,
360 size_t locales_count) { return kSuccess; }));
361 modifier.embedder_api().SendPlatformMessage =
362 MOCK_ENGINE_PROC(SendPlatformMessage,
363 ([](auto engine, auto message) { return kSuccess; }));
364
365 // Set the EGL manager to nullptr to test software fallback path.
366 modifier.SetEGLManager(nullptr);
367
368 engine->Run();
369
370 EXPECT_TRUE(run_called);
371
372 // Ensure that deallocation doesn't call the actual Shutdown with the bogus
373 // engine pointer that the overridden Run returned.
374 modifier.embedder_api().Shutdown = [](auto engine) { return kSuccess; };
375 }
376
377 TEST_F(FlutterWindowsEngineTest, RunWithoutANGLEOnImpellerFailsToStart) {
378 FlutterWindowsEngineBuilder builder{GetContext()};
379 builder.SetSwitches({"--enable-impeller=true"});
380 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
381 EngineModifier modifier(engine.get());
382
383 modifier.embedder_api().NotifyDisplayUpdate =
384 MOCK_ENGINE_PROC(NotifyDisplayUpdate,
385 ([engine_instance = engine.get()](
386 FLUTTER_API_SYMBOL(FlutterEngine) raw_engine,
387 const FlutterEngineDisplaysUpdateType update_type,
388 const FlutterEngineDisplay* embedder_displays,
389 size_t display_count) { return kSuccess; }));
390
391 // Accessibility updates must do nothing when the embedder engine is mocked
392 modifier.embedder_api().UpdateAccessibilityFeatures = MOCK_ENGINE_PROC(
393 UpdateAccessibilityFeatures,
394 [](FLUTTER_API_SYMBOL(FlutterEngine) engine,
395 FlutterAccessibilityFeature flags) { return kSuccess; });
396
397 // Stub out UpdateLocales and SendPlatformMessage as we don't have a fully
398 // initialized engine instance.
399 modifier.embedder_api().UpdateLocales = MOCK_ENGINE_PROC(
400 UpdateLocales, ([](auto engine, const FlutterLocale** locales,
401 size_t locales_count) { return kSuccess; }));
402 modifier.embedder_api().SendPlatformMessage =
403 MOCK_ENGINE_PROC(SendPlatformMessage,
404 ([](auto engine, auto message) { return kSuccess; }));
405
406 // Set the EGL manager to nullptr to test software fallback path.
407 modifier.SetEGLManager(nullptr);
408
409 EXPECT_FALSE(engine->Run());
410 }
411
412 TEST_F(FlutterWindowsEngineTest, SendPlatformMessageWithoutResponse) {
413 FlutterWindowsEngineBuilder builder{GetContext()};
414 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
415 EngineModifier modifier(engine.get());
416
417 const char* channel = "test";
418 const std::vector<uint8_t> test_message = {1, 2, 3, 4};
419
420 // Without a response, SendPlatformMessage should be a simple pass-through.
421 bool called = false;
422 modifier.embedder_api().SendPlatformMessage = MOCK_ENGINE_PROC(
423 SendPlatformMessage, ([&called, test_message](auto engine, auto message) {
424 called = true;
425 EXPECT_STREQ(message->channel, "test");
426 EXPECT_EQ(message->message_size, test_message.size());
427 EXPECT_EQ(memcmp(message->message, test_message.data(),
428 message->message_size),
429 0);
430 EXPECT_EQ(message->response_handle, nullptr);
431 return kSuccess;
432 }));
433
434 engine->SendPlatformMessage(channel, test_message.data(), test_message.size(),
435 nullptr, nullptr);
436 EXPECT_TRUE(called);
437 }
438
439 TEST_F(FlutterWindowsEngineTest, PlatformMessageRoundTrip) {
440 FlutterWindowsEngineBuilder builder{GetContext()};
441 builder.SetDartEntrypoint("hiPlatformChannels");
442
443 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
444 EngineModifier modifier(engine.get());
445 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
446
447 auto binary_messenger =
448 std::make_unique<BinaryMessengerImpl>(engine->messenger());
449
450 engine->Run();
451 bool did_call_callback = false;
452 bool did_call_reply = false;
453 bool did_call_dart_reply = false;
454 std::string channel = "hi";
455 binary_messenger->SetMessageHandler(
456 channel,
457 [&did_call_callback, &did_call_dart_reply](
458 const uint8_t* message, size_t message_size, BinaryReply reply) {
459 if (message_size == 5) {
460 EXPECT_EQ(message[0], static_cast<uint8_t>('h'));
461 char response[] = {'b', 'y', 'e'};
462 reply(reinterpret_cast<uint8_t*>(response), 3);
463 did_call_callback = true;
464 } else {
465 EXPECT_EQ(message_size, 3);
466 EXPECT_EQ(message[0], static_cast<uint8_t>('b'));
467 did_call_dart_reply = true;
468 }
469 });
470 char payload[] = {'h', 'e', 'l', 'l', 'o'};
471 binary_messenger->Send(
472 channel, reinterpret_cast<uint8_t*>(payload), 5,
473 [&did_call_reply](const uint8_t* reply, size_t reply_size) {
474 EXPECT_EQ(reply_size, 5);
475 EXPECT_EQ(reply[0], static_cast<uint8_t>('h'));
476 did_call_reply = true;
477 });
478 // Rely on timeout mechanism in CI.
479 while (!did_call_callback || !did_call_reply || !did_call_dart_reply) {
480 engine->task_runner()->ProcessTasks();
481 }
482 }
483
484 TEST_F(FlutterWindowsEngineTest, PlatformMessageRespondOnDifferentThread) {
485 FlutterWindowsEngineBuilder builder{GetContext()};
486 builder.SetDartEntrypoint("hiPlatformChannels");
487
488 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
489
490 EngineModifier modifier(engine.get());
491 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
492
493 auto binary_messenger =
494 std::make_unique<BinaryMessengerImpl>(engine->messenger());
495
496 engine->Run();
497 bool did_call_callback = false;
498 bool did_call_reply = false;
499 bool did_call_dart_reply = false;
500 std::string channel = "hi";
501 std::unique_ptr<std::thread> reply_thread;
502 binary_messenger->SetMessageHandler(
503 channel,
504 [&did_call_callback, &did_call_dart_reply, &reply_thread](
505 const uint8_t* message, size_t message_size, BinaryReply reply) {
506 if (message_size == 5) {
507 EXPECT_EQ(message[0], static_cast<uint8_t>('h'));
508 reply_thread.reset(new std::thread([reply = std::move(reply)]() {
509 char response[] = {'b', 'y', 'e'};
510 reply(reinterpret_cast<uint8_t*>(response), 3);
511 }));
512 did_call_callback = true;
513 } else {
514 EXPECT_EQ(message_size, 3);
515 EXPECT_EQ(message[0], static_cast<uint8_t>('b'));
516 did_call_dart_reply = true;
517 }
518 });
519 char payload[] = {'h', 'e', 'l', 'l', 'o'};
520 binary_messenger->Send(
521 channel, reinterpret_cast<uint8_t*>(payload), 5,
522 [&did_call_reply](const uint8_t* reply, size_t reply_size) {
523 EXPECT_EQ(reply_size, 5);
524 EXPECT_EQ(reply[0], static_cast<uint8_t>('h'));
525 did_call_reply = true;
526 });
527 // Rely on timeout mechanism in CI.
528 while (!did_call_callback || !did_call_reply || !did_call_dart_reply) {
529 engine->task_runner()->ProcessTasks();
530 }
531 ASSERT_TRUE(reply_thread);
532 reply_thread->join();
533 }
534
535 TEST_F(FlutterWindowsEngineTest, SendPlatformMessageWithResponse) {
536 FlutterWindowsEngineBuilder builder{GetContext()};
537 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
538 EngineModifier modifier(engine.get());
539
540 const char* channel = "test";
541 const std::vector<uint8_t> test_message = {1, 2, 3, 4};
542 auto* dummy_response_handle =
543 reinterpret_cast<FlutterPlatformMessageResponseHandle*>(5);
544 const FlutterDesktopBinaryReply reply_handler = [](auto... args) {};
545 void* reply_user_data = reinterpret_cast<void*>(6);
546
547 // When a response is requested, a handle should be created, passed as part
548 // of the message, and then released.
549 bool create_response_handle_called = false;
550 modifier.embedder_api().PlatformMessageCreateResponseHandle =
551 MOCK_ENGINE_PROC(
552 PlatformMessageCreateResponseHandle,
553 ([&create_response_handle_called, &reply_handler, reply_user_data,
554 dummy_response_handle](auto engine, auto reply, auto user_data,
555 auto response_handle) {
556 create_response_handle_called = true;
557 EXPECT_EQ(reply, reply_handler);
558 EXPECT_EQ(user_data, reply_user_data);
559 EXPECT_NE(response_handle, nullptr);
560 *response_handle = dummy_response_handle;
561 return kSuccess;
562 }));
563 bool release_response_handle_called = false;
564 modifier.embedder_api().PlatformMessageReleaseResponseHandle =
565 MOCK_ENGINE_PROC(
566 PlatformMessageReleaseResponseHandle,
567 ([&release_response_handle_called, dummy_response_handle](
568 auto engine, auto response_handle) {
569 release_response_handle_called = true;
570 EXPECT_EQ(response_handle, dummy_response_handle);
571 return kSuccess;
572 }));
573 bool send_message_called = false;
574 modifier.embedder_api().SendPlatformMessage = MOCK_ENGINE_PROC(
575 SendPlatformMessage, ([&send_message_called, test_message,
576 dummy_response_handle](auto engine, auto message) {
577 send_message_called = true;
578 EXPECT_STREQ(message->channel, "test");
579 EXPECT_EQ(message->message_size, test_message.size());
580 EXPECT_EQ(memcmp(message->message, test_message.data(),
581 message->message_size),
582 0);
583 EXPECT_EQ(message->response_handle, dummy_response_handle);
584 return kSuccess;
585 }));
586
587 engine->SendPlatformMessage(channel, test_message.data(), test_message.size(),
588 reply_handler, reply_user_data);
589 EXPECT_TRUE(create_response_handle_called);
590 EXPECT_TRUE(release_response_handle_called);
591 EXPECT_TRUE(send_message_called);
592 }
593
594 TEST_F(FlutterWindowsEngineTest, DispatchSemanticsAction) {
595 FlutterWindowsEngineBuilder builder{GetContext()};
596 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
597 EngineModifier modifier(engine.get());
598
599 bool called = false;
600 std::string message = "Hello";
601 modifier.embedder_api().SendSemanticsAction = MOCK_ENGINE_PROC(
602 SendSemanticsAction, ([&called, &message](auto engine, auto info) {
603 called = true;
604 EXPECT_EQ(info->view_id, 456);
605 EXPECT_EQ(info->node_id, 42);
606 EXPECT_EQ(info->action, kFlutterSemanticsActionDismiss);
607 EXPECT_EQ(memcmp(info->data, message.c_str(), message.size()), 0);
608 EXPECT_EQ(info->data_length, message.size());
609 return kSuccess;
610 }));
611
612 auto data = fml::MallocMapping::Copy(message.c_str(), message.size());
613 engine->DispatchSemanticsAction(456, 42, kFlutterSemanticsActionDismiss,
614 std::move(data));
615 EXPECT_TRUE(called);
616 }
617
618 TEST_F(FlutterWindowsEngineTest, SetsThreadPriority) {
619 WindowsPlatformThreadPrioritySetter(FlutterThreadPriority::kBackground);
620 EXPECT_EQ(GetThreadPriority(GetCurrentThread()),
621 THREAD_PRIORITY_BELOW_NORMAL);
622
623 WindowsPlatformThreadPrioritySetter(FlutterThreadPriority::kDisplay);
624 EXPECT_EQ(GetThreadPriority(GetCurrentThread()),
625 THREAD_PRIORITY_ABOVE_NORMAL);
626
627 WindowsPlatformThreadPrioritySetter(FlutterThreadPriority::kRaster);
628 EXPECT_EQ(GetThreadPriority(GetCurrentThread()),
629 THREAD_PRIORITY_ABOVE_NORMAL);
630
631 // FlutterThreadPriority::kNormal does not change thread priority, reset to 0
632 // here.
633 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
634
635 WindowsPlatformThreadPrioritySetter(FlutterThreadPriority::kNormal);
636 EXPECT_EQ(GetThreadPriority(GetCurrentThread()), THREAD_PRIORITY_NORMAL);
637 }
638
639 TEST_F(FlutterWindowsEngineTest, AddPluginRegistrarDestructionCallback) {
640 FlutterWindowsEngineBuilder builder{GetContext()};
641 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
642 EngineModifier modifier(engine.get());
643
644 MockEmbedderApiForKeyboard(modifier,
645 std::make_shared<MockKeyResponseController>());
646
647 engine->Run();
648
649 // Verify that destruction handlers don't overwrite each other.
650 int result1 = 0;
651 int result2 = 0;
652 engine->AddPluginRegistrarDestructionCallback(
653 [](FlutterDesktopPluginRegistrarRef ref) {
654 auto result = reinterpret_cast<int*>(ref);
655 *result = 1;
656 },
657 reinterpret_cast<FlutterDesktopPluginRegistrarRef>(&result1));
658 engine->AddPluginRegistrarDestructionCallback(
659 [](FlutterDesktopPluginRegistrarRef ref) {
660 auto result = reinterpret_cast<int*>(ref);
661 *result = 2;
662 },
663 reinterpret_cast<FlutterDesktopPluginRegistrarRef>(&result2));
664
665 engine->Stop();
666 EXPECT_EQ(result1, 1);
667 EXPECT_EQ(result2, 2);
668 }
669
670 TEST_F(FlutterWindowsEngineTest, ScheduleFrame) {
671 FlutterWindowsEngineBuilder builder{GetContext()};
672 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
673 EngineModifier modifier(engine.get());
674
675 bool called = false;
676 modifier.embedder_api().ScheduleFrame =
677 MOCK_ENGINE_PROC(ScheduleFrame, ([&called](auto engine) {
678 called = true;
679 return kSuccess;
680 }));
681
682 engine->ScheduleFrame();
683 EXPECT_TRUE(called);
684 }
685
686 TEST_F(FlutterWindowsEngineTest, SetNextFrameCallback) {
687 FlutterWindowsEngineBuilder builder{GetContext()};
688 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
689 EngineModifier modifier(engine.get());
690
691 bool called = false;
692 modifier.embedder_api().SetNextFrameCallback = MOCK_ENGINE_PROC(
693 SetNextFrameCallback, ([&called](auto engine, auto callback, auto data) {
694 called = true;
695 return kSuccess;
696 }));
697
698 engine->SetNextFrameCallback([]() {});
699 EXPECT_TRUE(called);
700 }
701
702 TEST_F(FlutterWindowsEngineTest, GetExecutableName) {
703 FlutterWindowsEngineBuilder builder{GetContext()};
704 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
705 EXPECT_EQ(engine->GetExecutableName(), "flutter_windows_unittests.exe");
706 }
707
708 // Ensure that after setting or resetting the high contrast feature,
709 // the corresponding status flag can be retrieved from the engine.
710 TEST_F(FlutterWindowsEngineTest, UpdateHighContrastFeature) {
711 auto windows_proc_table = std::make_shared<MockWindowsProcTable>();
712 EXPECT_CALL(*windows_proc_table, GetHighContrastEnabled)
713 .WillOnce(Return(true))
714 .WillOnce(Return(false));
715
716 FlutterWindowsEngineBuilder builder{GetContext()};
717 builder.SetWindowsProcTable(windows_proc_table);
718 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
719 EngineModifier modifier(engine.get());
720
721 std::optional<FlutterAccessibilityFeature> engine_flags;
722 modifier.embedder_api().UpdateAccessibilityFeatures = MOCK_ENGINE_PROC(
723 UpdateAccessibilityFeatures, ([&engine_flags](auto engine, auto flags) {
724 engine_flags = flags;
725 return kSuccess;
726 }));
727 modifier.embedder_api().SendPlatformMessage = MOCK_ENGINE_PROC(
728 SendPlatformMessage,
729 [](auto engine, const auto message) { return kSuccess; });
730
731 // 1: High contrast is enabled.
732 engine->UpdateHighContrastMode();
733
734 EXPECT_TRUE(engine->high_contrast_enabled());
735 EXPECT_TRUE(engine_flags.has_value());
736 EXPECT_TRUE(
737 engine_flags.value() &
738 FlutterAccessibilityFeature::kFlutterAccessibilityFeatureHighContrast);
739
740 // 2: High contrast is disabled.
741 engine_flags.reset();
742 engine->UpdateHighContrastMode();
743
744 EXPECT_FALSE(engine->high_contrast_enabled());
745 EXPECT_TRUE(engine_flags.has_value());
746 EXPECT_FALSE(
747 engine_flags.value() &
748 FlutterAccessibilityFeature::kFlutterAccessibilityFeatureHighContrast);
749 }
750
751 TEST_F(FlutterWindowsEngineTest, PostRasterThreadTask) {
752 FlutterWindowsEngineBuilder builder{GetContext()};
753 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
754 EngineModifier modifier(engine.get());
755
756 modifier.embedder_api().PostRenderThreadTask = MOCK_ENGINE_PROC(
757 PostRenderThreadTask, ([](auto engine, auto callback, auto context) {
758 callback(context);
759 return kSuccess;
760 }));
761
762 bool called = false;
763 engine->PostRasterThreadTask([&called]() { called = true; });
764
765 EXPECT_TRUE(called);
766 }
767
768 class MockFlutterWindowsView : public FlutterWindowsView {
769 public:
770 MockFlutterWindowsView(FlutterWindowsEngine* engine,
771 std::unique_ptr<WindowBindingHandler> wbh)
772 : FlutterWindowsView(kImplicitViewId, engine, std::move(wbh)) {}
773 ~MockFlutterWindowsView() {}
774
775 MOCK_METHOD(void,
776 NotifyWinEventWrapper,
777 (ui::AXPlatformNodeWin*, ax::mojom::Event),
778 (override));
779 MOCK_METHOD(HWND, GetWindowHandle, (), (const, override));
780 MOCK_METHOD(bool, Focus, (), (override));
781
782 private:
783 FML_DISALLOW_COPY_AND_ASSIGN(MockFlutterWindowsView);
784 };
785
786 // Verify the view is notified of accessibility announcements.
787 TEST_F(FlutterWindowsEngineTest, AccessibilityAnnouncement) {
788 auto& context = GetContext();
789 WindowsConfigBuilder builder{context};
790 builder.SetDartEntrypoint("sendAccessibilityAnnouncement");
791
792 bool done = false;
793 auto native_entry =
794 CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { done = true; });
795 context.AddNativeFunction("Signal", native_entry);
796
797 EnginePtr engine{builder.RunHeadless()};
798 ASSERT_NE(engine, nullptr);
799
800 ui::AXPlatformNodeDelegateBase parent_delegate;
801 AlertPlatformNodeDelegate delegate{parent_delegate};
802
803 auto window_binding_handler =
804 std::make_unique<NiceMock<MockWindowBindingHandler>>();
805 EXPECT_CALL(*window_binding_handler, GetAlertDelegate)
806 .WillOnce(Return(&delegate));
807
808 auto windows_engine = reinterpret_cast<FlutterWindowsEngine*>(engine.get());
809 MockFlutterWindowsView view{windows_engine,
810 std::move(window_binding_handler)};
811 EngineModifier modifier{windows_engine};
812 modifier.SetImplicitView(&view);
813
814 windows_engine->UpdateSemanticsEnabled(true);
815
816 EXPECT_CALL(view, NotifyWinEventWrapper).Times(1);
817
818 // Rely on timeout mechanism in CI.
819 while (!done) {
820 windows_engine->task_runner()->ProcessTasks();
821 }
822 }
823
824 // Verify the app can send accessibility announcements while in headless mode.
825 TEST_F(FlutterWindowsEngineTest, AccessibilityAnnouncementHeadless) {
826 auto& context = GetContext();
827 WindowsConfigBuilder builder{context};
828 builder.SetDartEntrypoint("sendAccessibilityAnnouncement");
829
830 bool done = false;
831 auto native_entry =
832 CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { done = true; });
833 context.AddNativeFunction("Signal", native_entry);
834
835 EnginePtr engine{builder.RunHeadless()};
836 ASSERT_NE(engine, nullptr);
837
838 auto windows_engine = reinterpret_cast<FlutterWindowsEngine*>(engine.get());
839 windows_engine->UpdateSemanticsEnabled(true);
840
841 // Rely on timeout mechanism in CI.
842 while (!done) {
843 windows_engine->task_runner()->ProcessTasks();
844 }
845 }
846
847 // Verify the engine does not crash if it receives an accessibility event
848 // it does not support yet.
849 TEST_F(FlutterWindowsEngineTest, AccessibilityTooltip) {
850 fml::testing::LogCapture log_capture;
851
852 auto& context = GetContext();
853 WindowsConfigBuilder builder{context};
854 builder.SetDartEntrypoint("sendAccessibilityTooltipEvent");
855
856 bool done = false;
857 auto native_entry =
858 CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { done = true; });
859 context.AddNativeFunction("Signal", native_entry);
860
861 ViewControllerPtr controller{builder.Run()};
862 ASSERT_NE(controller, nullptr);
863
864 auto engine = FlutterDesktopViewControllerGetEngine(controller.get());
865 auto windows_engine = reinterpret_cast<FlutterWindowsEngine*>(engine);
866 windows_engine->UpdateSemanticsEnabled(true);
867
868 // Rely on timeout mechanism in CI.
869 while (!done) {
870 windows_engine->task_runner()->ProcessTasks();
871 }
872
873 // Verify no error was logged.
874 // Regression test for:
875 // https://github.com/flutter/flutter/issues/144274
876 EXPECT_EQ(log_capture.str().find("tooltip"), std::string::npos);
877 }
878
879 class MockWindowsLifecycleManager : public WindowsLifecycleManager {
880 public:
881 MockWindowsLifecycleManager(FlutterWindowsEngine* engine)
882 : WindowsLifecycleManager(engine) {}
883 virtual ~MockWindowsLifecycleManager() {}
884
885 MOCK_METHOD(
886 void,
887 Quit,
888 (std::optional<HWND>, std::optional<WPARAM>, std::optional<LPARAM>, UINT),
889 (override));
890 MOCK_METHOD(void, DispatchMessage, (HWND, UINT, WPARAM, LPARAM), (override));
891 MOCK_METHOD(bool, IsLastWindowOfProcess, (), (override));
892 MOCK_METHOD(void, SetLifecycleState, (AppLifecycleState), (override));
893
894 void BeginProcessingLifecycle() override {
895 WindowsLifecycleManager::BeginProcessingLifecycle();
896 if (begin_processing_callback) {
897 begin_processing_callback();
898 }
899 }
900
901 std::function<void()> begin_processing_callback = nullptr;
902 };
903
904 TEST_F(FlutterWindowsEngineTest, TestExit) {
905 FlutterWindowsEngineBuilder builder{GetContext()};
906 builder.SetDartEntrypoint("exitTestExit");
907 bool finished = false;
908
909 auto engine = builder.Build();
910 auto window_binding_handler =
911 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
912 MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler));
913
914 EngineModifier modifier(engine.get());
915 modifier.SetImplicitView(&view);
916 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
917 auto handler = std::make_unique<MockWindowsLifecycleManager>(engine.get());
918 EXPECT_CALL(*handler, Quit)
919 .WillOnce([&finished](std::optional<HWND> hwnd,
920 std::optional<WPARAM> wparam,
921 std::optional<LPARAM> lparam,
922 UINT exit_code) { finished = exit_code == 0; });
923 EXPECT_CALL(*handler, IsLastWindowOfProcess).WillRepeatedly(Return(true));
924 modifier.SetLifecycleManager(std::move(handler));
925
926 engine->lifecycle_manager()->BeginProcessingExit();
927
928 engine->Run();
929
930 engine->window_proc_delegate_manager()->OnTopLevelWindowProc(0, WM_CLOSE, 0,
931 0);
932
933 // The test will only succeed when this while loop exits. Otherwise it will
934 // timeout.
935 while (!finished) {
936 engine->task_runner()->ProcessTasks();
937 }
938 }
939
940 TEST_F(FlutterWindowsEngineTest, TestExitCancel) {
941 FlutterWindowsEngineBuilder builder{GetContext()};
942 builder.SetDartEntrypoint("exitTestCancel");
943 bool did_call = false;
944
945 auto engine = builder.Build();
946 auto window_binding_handler =
947 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
948 MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler));
949
950 EngineModifier modifier(engine.get());
951 modifier.SetImplicitView(&view);
952 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
953 auto handler = std::make_unique<MockWindowsLifecycleManager>(engine.get());
954 EXPECT_CALL(*handler, IsLastWindowOfProcess).WillRepeatedly(Return(true));
955 EXPECT_CALL(*handler, Quit).Times(0);
956 modifier.SetLifecycleManager(std::move(handler));
957 engine->lifecycle_manager()->BeginProcessingExit();
958
959 auto binary_messenger =
960 std::make_unique<BinaryMessengerImpl>(engine->messenger());
961 binary_messenger->SetMessageHandler(
962 "flutter/platform", [&did_call](const uint8_t* message,
963 size_t message_size, BinaryReply reply) {
964 std::string contents(message, message + message_size);
965 EXPECT_NE(contents.find("\"method\":\"System.exitApplication\""),
966 std::string::npos);
967 EXPECT_NE(contents.find("\"type\":\"required\""), std::string::npos);
968 EXPECT_NE(contents.find("\"exitCode\":0"), std::string::npos);
969 did_call = true;
970 char response[] = "";
971 reply(reinterpret_cast<uint8_t*>(response), 0);
972 });
973
974 engine->Run();
975
976 engine->window_proc_delegate_manager()->OnTopLevelWindowProc(0, WM_CLOSE, 0,
977 0);
978
979 while (!did_call) {
980 engine->task_runner()->ProcessTasks();
981 }
982 }
983
984 // Flutter consumes the first WM_CLOSE message to allow the app to cancel the
985 // exit. If the app does not cancel the exit, Flutter synthesizes a second
986 // WM_CLOSE message.
987 TEST_F(FlutterWindowsEngineTest, TestExitSecondCloseMessage) {
988 FlutterWindowsEngineBuilder builder{GetContext()};
989 builder.SetDartEntrypoint("exitTestExit");
990 bool second_close = false;
991
992 auto engine = builder.Build();
993 auto window_binding_handler =
994 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
995 MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler));
996
997 EngineModifier modifier(engine.get());
998 modifier.SetImplicitView(&view);
999 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1000 auto handler = std::make_unique<MockWindowsLifecycleManager>(engine.get());
1001 EXPECT_CALL(*handler, IsLastWindowOfProcess).WillOnce(Return(true));
1002 EXPECT_CALL(*handler, Quit)
1003 .WillOnce([handler_ptr = handler.get()](
1004 std::optional<HWND> hwnd, std::optional<WPARAM> wparam,
1005 std::optional<LPARAM> lparam, UINT exit_code) {
1006 handler_ptr->WindowsLifecycleManager::Quit(hwnd, wparam, lparam,
1007 exit_code);
1008 });
1009 EXPECT_CALL(*handler, DispatchMessage)
1010 .WillRepeatedly(
1011 [&engine](HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
1012 engine->window_proc_delegate_manager()->OnTopLevelWindowProc(
1013 hwnd, msg, wparam, lparam);
1014 });
1015 modifier.SetLifecycleManager(std::move(handler));
1016 engine->lifecycle_manager()->BeginProcessingExit();
1017
1018 engine->Run();
1019
1020 // This delegate will be registered after the lifecycle manager, so it will be
1021 // called only when a message is not consumed by the lifecycle manager. This
1022 // should be called on the second, synthesized WM_CLOSE message that the
1023 // lifecycle manager posts.
1024 engine->window_proc_delegate_manager()->RegisterTopLevelWindowProcDelegate(
1025 [](HWND hwnd, UINT message, WPARAM wpar, LPARAM lpar, void* user_data,
1026 LRESULT* result) {
1027 switch (message) {
1028 case WM_CLOSE: {
1029 bool* called = reinterpret_cast<bool*>(user_data);
1030 *called = true;
1031 return true;
1032 }
1033 }
1034 return false;
1035 },
1036 reinterpret_cast<void*>(&second_close));
1037
1038 engine->window_proc_delegate_manager()->OnTopLevelWindowProc(0, WM_CLOSE, 0,
1039 0);
1040
1041 while (!second_close) {
1042 engine->task_runner()->ProcessTasks();
1043 }
1044 }
1045
1046 TEST_F(FlutterWindowsEngineTest, TestExitCloseMultiWindow) {
1047 FlutterWindowsEngineBuilder builder{GetContext()};
1048 builder.SetDartEntrypoint("exitTestExit");
1049 bool finished = false;
1050
1051 auto engine = builder.Build();
1052 auto window_binding_handler =
1053 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
1054 MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler));
1055
1056 EngineModifier modifier(engine.get());
1057 modifier.SetImplicitView(&view);
1058 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1059 auto handler = std::make_unique<MockWindowsLifecycleManager>(engine.get());
1060 EXPECT_CALL(*handler, IsLastWindowOfProcess).WillOnce([&finished]() {
1061 finished = true;
1062 return false;
1063 });
1064 // Quit should not be called when there is more than one window.
1065 EXPECT_CALL(*handler, Quit).Times(0);
1066 modifier.SetLifecycleManager(std::move(handler));
1067 engine->lifecycle_manager()->BeginProcessingExit();
1068
1069 engine->Run();
1070
1071 engine->window_proc_delegate_manager()->OnTopLevelWindowProc(0, WM_CLOSE, 0,
1072 0);
1073
1074 while (!finished) {
1075 engine->task_runner()->ProcessTasks();
1076 }
1077 }
1078
1079 TEST_F(FlutterWindowsEngineTest, LifecycleManagerDisabledByDefault) {
1080 FlutterWindowsEngineBuilder builder{GetContext()};
1081
1082 auto engine = builder.Build();
1083 auto window_binding_handler =
1084 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
1085 MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler));
1086
1087 EngineModifier modifier(engine.get());
1088 modifier.SetImplicitView(&view);
1089 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1090 auto handler = std::make_unique<MockWindowsLifecycleManager>(engine.get());
1091 EXPECT_CALL(*handler, IsLastWindowOfProcess).Times(0);
1092 modifier.SetLifecycleManager(std::move(handler));
1093
1094 engine->window_proc_delegate_manager()->OnTopLevelWindowProc(0, WM_CLOSE, 0,
1095 0);
1096 }
1097
1098 TEST_F(FlutterWindowsEngineTest, EnableApplicationLifecycle) {
1099 FlutterWindowsEngineBuilder builder{GetContext()};
1100
1101 auto engine = builder.Build();
1102 auto window_binding_handler =
1103 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
1104 MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler));
1105
1106 EngineModifier modifier(engine.get());
1107 modifier.SetImplicitView(&view);
1108 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1109 auto handler = std::make_unique<MockWindowsLifecycleManager>(engine.get());
1110 EXPECT_CALL(*handler, IsLastWindowOfProcess).WillOnce(Return(false));
1111 modifier.SetLifecycleManager(std::move(handler));
1112 engine->lifecycle_manager()->BeginProcessingExit();
1113
1114 engine->window_proc_delegate_manager()->OnTopLevelWindowProc(0, WM_CLOSE, 0,
1115 0);
1116 }
1117
1118 TEST_F(FlutterWindowsEngineTest, ApplicationLifecycleExternalWindow) {
1119 FlutterWindowsEngineBuilder builder{GetContext()};
1120
1121 auto engine = builder.Build();
1122 auto window_binding_handler =
1123 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
1124 MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler));
1125
1126 EngineModifier modifier(engine.get());
1127 modifier.SetImplicitView(&view);
1128 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1129 auto handler = std::make_unique<MockWindowsLifecycleManager>(engine.get());
1130 EXPECT_CALL(*handler, IsLastWindowOfProcess).WillOnce(Return(false));
1131 modifier.SetLifecycleManager(std::move(handler));
1132 engine->lifecycle_manager()->BeginProcessingExit();
1133
1134 engine->lifecycle_manager()->ExternalWindowMessage(0, WM_CLOSE, 0, 0);
1135 }
1136
1137 TEST_F(FlutterWindowsEngineTest, LifecycleStateTransition) {
1138 FlutterWindowsEngineBuilder builder{GetContext()};
1139
1140 auto engine = builder.Build();
1141 auto window_binding_handler =
1142 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
1143 MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler));
1144
1145 EngineModifier modifier(engine.get());
1146 modifier.SetImplicitView(&view);
1147 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1148 engine->Run();
1149
1150 engine->window_proc_delegate_manager()->OnTopLevelWindowProc(
1151 (HWND)1, WM_SIZE, SIZE_RESTORED, 0);
1152
1153 while (engine->lifecycle_manager()->IsUpdateStateScheduled()) {
1154 PumpMessage();
1155 }
1156
1157 EXPECT_EQ(engine->lifecycle_manager()->GetLifecycleState(),
1158 AppLifecycleState::kInactive);
1159
1160 engine->lifecycle_manager()->OnWindowStateEvent((HWND)1,
1161 WindowStateEvent::kFocus);
1162
1163 while (engine->lifecycle_manager()->IsUpdateStateScheduled()) {
1164 PumpMessage();
1165 }
1166
1167 EXPECT_EQ(engine->lifecycle_manager()->GetLifecycleState(),
1168 AppLifecycleState::kResumed);
1169
1170 engine->window_proc_delegate_manager()->OnTopLevelWindowProc(
1171 (HWND)1, WM_SIZE, SIZE_MINIMIZED, 0);
1172
1173 while (engine->lifecycle_manager()->IsUpdateStateScheduled()) {
1174 PumpMessage();
1175 }
1176
1177 EXPECT_EQ(engine->lifecycle_manager()->GetLifecycleState(),
1178 AppLifecycleState::kHidden);
1179
1180 engine->window_proc_delegate_manager()->OnTopLevelWindowProc(
1181 (HWND)1, WM_SIZE, SIZE_RESTORED, 0);
1182
1183 while (engine->lifecycle_manager()->IsUpdateStateScheduled()) {
1184 PumpMessage();
1185 }
1186
1187 EXPECT_EQ(engine->lifecycle_manager()->GetLifecycleState(),
1188 AppLifecycleState::kInactive);
1189 }
1190
1191 TEST_F(FlutterWindowsEngineTest, ExternalWindowMessage) {
1192 FlutterWindowsEngineBuilder builder{GetContext()};
1193
1194 auto engine = builder.Build();
1195 auto window_binding_handler =
1196 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
1197 MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler));
1198
1199 EngineModifier modifier(engine.get());
1200 modifier.SetImplicitView(&view);
1201 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1202 // Sets lifecycle state to resumed.
1203 engine->Run();
1204
1205 // Ensure HWND(1) is in the set of visible windows before hiding it.
1206 engine->ProcessExternalWindowMessage(reinterpret_cast<HWND>(1), WM_SHOWWINDOW,
1207 TRUE, NULL);
1208 engine->ProcessExternalWindowMessage(reinterpret_cast<HWND>(1), WM_SHOWWINDOW,
1209 FALSE, NULL);
1210
1211 while (engine->lifecycle_manager()->IsUpdateStateScheduled()) {
1212 PumpMessage();
1213 }
1214
1215 EXPECT_EQ(engine->lifecycle_manager()->GetLifecycleState(),
1216 AppLifecycleState::kHidden);
1217 }
1218
1219 TEST_F(FlutterWindowsEngineTest, InnerWindowHidden) {
1220 FlutterWindowsEngineBuilder builder{GetContext()};
1221 HWND outer = reinterpret_cast<HWND>(1);
1222 HWND inner = reinterpret_cast<HWND>(2);
1223
1224 auto engine = builder.Build();
1225 auto window_binding_handler =
1226 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
1227 MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler));
1228 ON_CALL(view, GetWindowHandle).WillByDefault([=]() { return inner; });
1229
1230 EngineModifier modifier(engine.get());
1231 modifier.SetImplicitView(&view);
1232 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1233 // Sets lifecycle state to resumed.
1234 engine->Run();
1235
1236 // Show both top-level and Flutter window.
1237 engine->window_proc_delegate_manager()->OnTopLevelWindowProc(
1238 outer, WM_SHOWWINDOW, TRUE, NULL);
1239 view.OnWindowStateEvent(inner, WindowStateEvent::kShow);
1240 view.OnWindowStateEvent(inner, WindowStateEvent::kFocus);
1241
1242 while (engine->lifecycle_manager()->IsUpdateStateScheduled()) {
1243 PumpMessage();
1244 }
1245
1246 EXPECT_EQ(engine->lifecycle_manager()->GetLifecycleState(),
1247 AppLifecycleState::kResumed);
1248
1249 // Hide Flutter window, but not top level window.
1250 view.OnWindowStateEvent(inner, WindowStateEvent::kHide);
1251
1252 while (engine->lifecycle_manager()->IsUpdateStateScheduled()) {
1253 PumpMessage();
1254 }
1255
1256 // The top-level window is still visible, so we ought not enter hidden state.
1257 EXPECT_EQ(engine->lifecycle_manager()->GetLifecycleState(),
1258 AppLifecycleState::kInactive);
1259 }
1260
1261 TEST_F(FlutterWindowsEngineTest, EnableLifecycleState) {
1262 FlutterWindowsEngineBuilder builder{GetContext()};
1263 builder.SetDartEntrypoint("enableLifecycleTest");
1264 bool finished = false;
1265
1266 auto engine = builder.Build();
1267 auto window_binding_handler =
1268 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
1269 MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler));
1270
1271 EngineModifier modifier(engine.get());
1272 modifier.SetImplicitView(&view);
1273 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1274 auto handler = std::make_unique<MockWindowsLifecycleManager>(engine.get());
1275 EXPECT_CALL(*handler, SetLifecycleState)
1276 .WillRepeatedly([handler_ptr = handler.get()](AppLifecycleState state) {
1277 handler_ptr->WindowsLifecycleManager::SetLifecycleState(state);
1278 });
1279 modifier.SetLifecycleManager(std::move(handler));
1280
1281 auto binary_messenger =
1282 std::make_unique<BinaryMessengerImpl>(engine->messenger());
1283 // Mark the test only as completed on receiving an inactive state message.
1284 binary_messenger->SetMessageHandler(
1285 "flutter/unittest", [&finished](const uint8_t* message,
1286 size_t message_size, BinaryReply reply) {
1287 std::string contents(message, message + message_size);
1288 EXPECT_NE(contents.find("AppLifecycleState.inactive"),
1289 std::string::npos);
1290 finished = true;
1291 char response[] = "";
1292 reply(reinterpret_cast<uint8_t*>(response), 0);
1293 });
1294
1295 engine->Run();
1296
1297 // Test that setting the state before enabling lifecycle does nothing.
1298 HWND hwnd = reinterpret_cast<HWND>(1);
1299 view.OnWindowStateEvent(hwnd, WindowStateEvent::kShow);
1300 view.OnWindowStateEvent(hwnd, WindowStateEvent::kHide);
1301 EXPECT_FALSE(finished);
1302
1303 // Test that we can set the state afterwards.
1304
1305 engine->lifecycle_manager()->BeginProcessingLifecycle();
1306 view.OnWindowStateEvent(hwnd, WindowStateEvent::kShow);
1307
1308 while (!finished) {
1309 engine->task_runner()->ProcessTasks();
1310 }
1311 }
1312
1313 TEST_F(FlutterWindowsEngineTest, LifecycleStateToFrom) {
1314 FlutterWindowsEngineBuilder builder{GetContext()};
1315 builder.SetDartEntrypoint("enableLifecycleToFrom");
1316 bool enabled_lifecycle = false;
1317 bool dart_responded = false;
1318
1319 auto engine = builder.Build();
1320 auto window_binding_handler =
1321 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
1322 MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler));
1323
1324 EngineModifier modifier(engine.get());
1325 modifier.SetImplicitView(&view);
1326 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1327 auto handler = std::make_unique<MockWindowsLifecycleManager>(engine.get());
1328 EXPECT_CALL(*handler, SetLifecycleState)
1329 .WillRepeatedly([handler_ptr = handler.get()](AppLifecycleState state) {
1330 handler_ptr->WindowsLifecycleManager::SetLifecycleState(state);
1331 });
1332 handler->begin_processing_callback = [&]() { enabled_lifecycle = true; };
1333 modifier.SetLifecycleManager(std::move(handler));
1334
1335 auto binary_messenger =
1336 std::make_unique<BinaryMessengerImpl>(engine->messenger());
1337 binary_messenger->SetMessageHandler(
1338 "flutter/unittest",
1339 [&](const uint8_t* message, size_t message_size, BinaryReply reply) {
1340 std::string contents(message, message + message_size);
1341 EXPECT_NE(contents.find("AppLifecycleState."), std::string::npos);
1342 dart_responded = true;
1343 char response[] = "";
1344 reply(reinterpret_cast<uint8_t*>(response), 0);
1345 });
1346
1347 engine->Run();
1348
1349 while (!enabled_lifecycle) {
1350 engine->task_runner()->ProcessTasks();
1351 }
1352
1353 HWND hwnd = reinterpret_cast<HWND>(1);
1354 view.OnWindowStateEvent(hwnd, WindowStateEvent::kShow);
1355 view.OnWindowStateEvent(hwnd, WindowStateEvent::kHide);
1356
1357 while (!dart_responded) {
1358 engine->task_runner()->ProcessTasks();
1359 }
1360 }
1361
1362 TEST_F(FlutterWindowsEngineTest, ChannelListenedTo) {
1363 FlutterWindowsEngineBuilder builder{GetContext()};
1364 builder.SetDartEntrypoint("enableLifecycleToFrom");
1365
1366 auto engine = builder.Build();
1367 auto window_binding_handler =
1368 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
1369 MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler));
1370
1371 EngineModifier modifier(engine.get());
1372 modifier.SetImplicitView(&view);
1373 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1374
1375 bool lifecycle_began = false;
1376 auto handler = std::make_unique<MockWindowsLifecycleManager>(engine.get());
1377 handler->begin_processing_callback = [&]() { lifecycle_began = true; };
1378 modifier.SetLifecycleManager(std::move(handler));
1379
1380 engine->Run();
1381
1382 while (!lifecycle_began) {
1383 engine->task_runner()->ProcessTasks();
1384 }
1385 }
1386
1387 TEST_F(FlutterWindowsEngineTest, ReceivePlatformViewMessage) {
1388 FlutterWindowsEngineBuilder builder{GetContext()};
1389 builder.SetDartEntrypoint("sendCreatePlatformViewMethod");
1390 auto engine = builder.Build();
1391
1392 EngineModifier modifier{engine.get()};
1393 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1394
1395 bool received_call = false;
1396
1397 auto manager = std::make_unique<MockPlatformViewManager>(engine.get());
1398 EXPECT_CALL(*manager, AddPlatformView)
1399 .WillOnce([&](PlatformViewId id, std::string_view type_name) {
1400 received_call = true;
1401 return true;
1402 });
1403 modifier.SetPlatformViewPlugin(std::move(manager));
1404
1405 engine->Run();
1406
1407 while (!received_call) {
1408 engine->task_runner()->ProcessTasks();
1409 }
1410 }
1411
1412 TEST_F(FlutterWindowsEngineTest, AddViewFailureDoesNotHang) {
1413 FlutterWindowsEngineBuilder builder{GetContext()};
1414 auto engine = builder.Build();
1415
1416 EngineModifier modifier{engine.get()};
1417
1418 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1419 modifier.embedder_api().AddView = MOCK_ENGINE_PROC(
1420 AddView,
1421 [](FLUTTER_API_SYMBOL(FlutterEngine) engine,
1422 const FlutterAddViewInfo* info) { return kInternalInconsistency; });
1423
1424 ASSERT_TRUE(engine->Run());
1425
1426 // Create the first view. This is the implicit view and isn't added to the
1427 // engine.
1428 auto implicit_window = std::make_unique<NiceMock<MockWindowBindingHandler>>();
1429
1430 std::unique_ptr<FlutterWindowsView> implicit_view =
1431 engine->CreateView(std::move(implicit_window));
1432
1433 EXPECT_TRUE(implicit_view);
1434
1435 // Create a second view. The embedder attempts to add it to the engine.
1436 auto second_window = std::make_unique<NiceMock<MockWindowBindingHandler>>();
1437
1438 EXPECT_DEBUG_DEATH(engine->CreateView(std::move(second_window)),
1439 "FlutterEngineAddView returned an unexpected result");
1440 }
1441
1442 TEST_F(FlutterWindowsEngineTest, RemoveViewFailureDoesNotHang) {
1443 FlutterWindowsEngineBuilder builder{GetContext()};
1444 builder.SetDartEntrypoint("sendCreatePlatformViewMethod");
1445 auto engine = builder.Build();
1446
1447 EngineModifier modifier{engine.get()};
1448
1449 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1450 modifier.embedder_api().RemoveView = MOCK_ENGINE_PROC(
1451 RemoveView,
1452 [](FLUTTER_API_SYMBOL(FlutterEngine) engine,
1453 const FlutterRemoveViewInfo* info) { return kInternalInconsistency; });
1454
1455 ASSERT_TRUE(engine->Run());
1456 EXPECT_DEBUG_DEATH(engine->RemoveView(123),
1457 "FlutterEngineRemoveView returned an unexpected result");
1458 }
1459
1460 TEST_F(FlutterWindowsEngineTest, MergedUIThread) {
1461 auto& context = GetContext();
1462 WindowsConfigBuilder builder{context};
1463 builder.SetDartEntrypoint("mergedUIThread");
1464 builder.SetUIThreadPolicy(FlutterDesktopUIThreadPolicy::RunOnPlatformThread);
1465
1466 std::optional<std::thread::id> ui_thread_id;
1467
1468 auto native_entry = CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
1469 ui_thread_id = std::this_thread::get_id();
1470 });
1471 context.AddNativeFunction("Signal", native_entry);
1472
1473 EnginePtr engine{builder.RunHeadless()};
1474 while (!ui_thread_id) {
1475 PumpMessage();
1476 }
1477 ASSERT_EQ(*ui_thread_id, std::this_thread::get_id());
1478 }
1479
1480 TEST_F(FlutterWindowsEngineTest, OnViewFocusChangeRequest) {
1481 FlutterWindowsEngineBuilder builder{GetContext()};
1482 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
1483 auto window_binding_handler =
1484 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
1485 MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler));
1486
1487 EngineModifier modifier(engine.get());
1488 modifier.SetImplicitView(&view);
1489
1490 FlutterViewFocusChangeRequest request;
1491 request.view_id = kImplicitViewId;
1492
1493 EXPECT_CALL(view, Focus()).WillOnce(Return(true));
1494 modifier.OnViewFocusChangeRequest(&request);
1495 }
1496
1497 TEST_F(FlutterWindowsEngineTest, UpdateSemanticsMultiView) {
1498 auto& context = GetContext();
1499 WindowsConfigBuilder builder{context};
1500 builder.SetDartEntrypoint("sendSemanticsTreeInfo");
1501
1502 // Setup: a signal for when we have send out all of our semantics updates
1503 bool done = false;
1504 auto native_entry =
1505 CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { done = true; });
1506 context.AddNativeFunction("Signal", native_entry);
1507
1508 // Setup: Create the engine and two views + enable semantics
1509 EnginePtr engine{builder.RunHeadless()};
1510 ASSERT_NE(engine, nullptr);
1511
1512 auto window_binding_handler1 =
1513 std::make_unique<NiceMock<MockWindowBindingHandler>>();
1514 auto window_binding_handler2 =
1515 std::make_unique<NiceMock<MockWindowBindingHandler>>();
1516
1517 // The following mocks are required by
1518 // FlutterWindowsView::CreateWindowMetricsEvent so that we create a valid
1519 // view.
1520 EXPECT_CALL(*window_binding_handler1, GetPhysicalWindowBounds)
1521 .WillRepeatedly(testing::Return(PhysicalWindowBounds{100, 100}));
1522 EXPECT_CALL(*window_binding_handler1, GetDpiScale)
1523 .WillRepeatedly(testing::Return(96.0));
1524 EXPECT_CALL(*window_binding_handler2, GetPhysicalWindowBounds)
1525 .WillRepeatedly(testing::Return(PhysicalWindowBounds{200, 200}));
1526 EXPECT_CALL(*window_binding_handler2, GetDpiScale)
1527 .WillRepeatedly(testing::Return(96.0));
1528
1529 auto windows_engine = reinterpret_cast<FlutterWindowsEngine*>(engine.get());
1530 EngineModifier modifier{windows_engine};
1531 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1532
1533 // We want to avoid adding an implicit view as the first view
1534 modifier.SetNextViewId(kImplicitViewId + 1);
1535
1536 auto view1 = windows_engine->CreateView(std::move(window_binding_handler1));
1537 auto view2 = windows_engine->CreateView(std::move(window_binding_handler2));
1538
1539 // Act: UpdateSemanticsEnabled will trigger the semantics updates
1540 // to get sent.
1541 windows_engine->UpdateSemanticsEnabled(true);
1542
1543 while (!done) {
1544 windows_engine->task_runner()->ProcessTasks();
1545 }
1546
1547 auto accessibility_bridge1 = view1->accessibility_bridge().lock();
1548 auto accessibility_bridge2 = view2->accessibility_bridge().lock();
1549
1550 // Expect: that the semantics trees are updated with their
1551 // respective nodes.
1552 while (
1553 !accessibility_bridge1->GetPlatformNodeFromTree(view1->view_id() + 1)) {
1554 windows_engine->task_runner()->ProcessTasks();
1555 }
1556
1557 while (
1558 !accessibility_bridge2->GetPlatformNodeFromTree(view2->view_id() + 1)) {
1559 windows_engine->task_runner()->ProcessTasks();
1560 }
1561
1562 // Rely on timeout mechanism in CI.
1563 auto tree1 = accessibility_bridge1->GetTree();
1564 auto tree2 = accessibility_bridge2->GetTree();
1565 EXPECT_NE(tree1->GetFromId(view1->view_id() + 1), nullptr);
1566 EXPECT_NE(tree2->GetFromId(view2->view_id() + 1), nullptr);
1567 }
1568
1569 } // namespace testing
1570 } // namespace flutter
flutter::AlertPlatformNodeDelegate
Definition: alert_platform_node_delegate.h:18
flutter::FlutterEngine
Definition: flutter_engine.h:28
flutter::FlutterEngine::Run
bool Run()
Definition: flutter_engine.cc:49
flutter::FlutterWindowsEngine
Definition: flutter_windows_engine.h:92
flutter::FlutterWindowsEngine::UpdateSemanticsEnabled
void UpdateSemanticsEnabled(bool enabled)
Definition: flutter_windows_engine.cc:986
flutter::FlutterWindowsEngine::CreateView
std::unique_ptr< FlutterWindowsView > CreateView(std::unique_ptr< WindowBindingHandler > window)
Definition: flutter_windows_engine.cc:526
flutter::FlutterWindowsView
Definition: flutter_windows_view.h:34
flutter::WindowsLifecycleManager
Definition: windows_lifecycle_manager.h:37
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::BeginProcessingLifecycle
virtual void BeginProcessingLifecycle()
Definition: windows_lifecycle_manager.cc:187
flutter::WindowsLifecycleManager::DispatchMessage
virtual void DispatchMessage(HWND window, UINT msg, WPARAM wparam, LPARAM lparam)
Definition: windows_lifecycle_manager.cc:34
flutter::WindowsLifecycleManager::IsLastWindowOfProcess
virtual bool IsLastWindowOfProcess()
Definition: windows_lifecycle_manager.cc:164
flutter::WindowsLifecycleManager::SetLifecycleState
virtual void SetLifecycleState(AppLifecycleState state)
Definition: windows_lifecycle_manager.cc:195
flutter::testing::FlutterWindowsEngineTest
Definition: flutter_windows_engine_unittests.cc:52
flutter::testing::MockFlutterWindowsView::~MockFlutterWindowsView
~MockFlutterWindowsView()
Definition: flutter_windows_engine_unittests.cc:773
flutter::testing::MockFlutterWindowsView::MOCK_METHOD
MOCK_METHOD(bool, Focus,(),(override))
flutter::testing::MockFlutterWindowsView::MOCK_METHOD
MOCK_METHOD(void, NotifyWinEventWrapper,(ui::AXPlatformNodeWin *, ax::mojom::Event),(override))
flutter::testing::MockFlutterWindowsView::MockFlutterWindowsView
MockFlutterWindowsView(FlutterWindowsEngine *engine, std::unique_ptr< WindowBindingHandler > wbh)
Definition: flutter_windows_engine_unittests.cc:770
flutter::testing::MockFlutterWindowsView::MOCK_METHOD
MOCK_METHOD(HWND, GetWindowHandle,(),(const, override))
flutter::testing::MockWindowsLifecycleManager
Definition: flutter_windows_engine_unittests.cc:879
flutter::testing::MockWindowsLifecycleManager::~MockWindowsLifecycleManager
virtual ~MockWindowsLifecycleManager()
Definition: flutter_windows_engine_unittests.cc:883
flutter::testing::MockWindowsLifecycleManager::begin_processing_callback
std::function< void()> begin_processing_callback
Definition: flutter_windows_engine_unittests.cc:901
flutter::testing::MockWindowsLifecycleManager::MOCK_METHOD
MOCK_METHOD(void, DispatchMessage,(HWND, UINT, WPARAM, LPARAM),(override))
flutter::testing::MockWindowsLifecycleManager::MOCK_METHOD
MOCK_METHOD(void, Quit,(std::optional< HWND >, std::optional< WPARAM >, std::optional< LPARAM >, UINT),(override))
flutter::testing::MockWindowsLifecycleManager::MOCK_METHOD
MOCK_METHOD(void, SetLifecycleState,(AppLifecycleState),(override))
flutter::testing::MockWindowsLifecycleManager::BeginProcessingLifecycle
void BeginProcessingLifecycle() override
Definition: flutter_windows_engine_unittests.cc:894
flutter::testing::MockWindowsLifecycleManager::MOCK_METHOD
MOCK_METHOD(bool, IsLastWindowOfProcess,(),(override))
flutter::testing::MockWindowsLifecycleManager::MockWindowsLifecycleManager
MockWindowsLifecycleManager(FlutterWindowsEngine *engine)
Definition: flutter_windows_engine_unittests.cc:881
FlutterDesktopBinaryReply
void(* FlutterDesktopBinaryReply)(const uint8_t *data, size_t data_size, void *user_data)
Definition: flutter_messenger.h:26
FlutterDesktopViewControllerGetEngine
FlutterDesktopEngineRef FlutterDesktopViewControllerGetEngine(FlutterDesktopViewControllerRef ref)
Definition: flutter_windows.cc:148
flutter_windows.h
RunOnPlatformThread
@ RunOnPlatformThread
Definition: flutter_windows.h:58
flutter_windows_engine.h
PlatformViewId
int64_t PlatformViewId
Definition: flutter_windows_internal.h:42
flutter_windows_view.h
user_data
void * user_data
Definition: flutter_windows_view_unittests.cc:53
callback
FlutterDesktopBinaryReply callback
Definition: flutter_windows_view_unittests.cc:52
message
Win32Message message
Definition: keyboard_unittests.cc:137
flutter::testing::TEST_F
TEST_F(AccessibilityPluginTest, DirectAnnounceCall)
Definition: accessibility_plugin_unittests.cc:98
flutter
Definition: accessibility_bridge_windows.cc:11
flutter::GetDpiForMonitor
UINT GetDpiForMonitor(HMONITOR monitor)
Definition: dpi_utils.cc:132
flutter::WindowStateEvent::kHide
@ kHide
flutter::WindowStateEvent::kShow
@ kShow
flutter::WindowStateEvent::kFocus
@ kFocus
flutter::BinaryReply
std::function< void(const uint8_t *reply, size_t reply_size)> BinaryReply
Definition: binary_messenger.h:18
flutter::AppLifecycleState
AppLifecycleState
Definition: app_lifecycle_state.h:32
flutter::AppLifecycleState::kHidden
@ kHidden
flutter::AppLifecycleState::kResumed
@ kResumed
flutter::AppLifecycleState::kInactive
@ kInactive
flutter::WindowsPlatformThreadPrioritySetter
static void WindowsPlatformThreadPrioritySetter(FlutterThreadPriority priority)
Definition: flutter_windows_engine.h:62
flutter::kImplicitViewId
constexpr FlutterViewId kImplicitViewId
Definition: flutter_windows_engine.h:56
FlutterDesktopPluginRegistrar
Definition: window_state.h:23
flutter::PhysicalWindowBounds
Definition: window_binding_handler.h:28