| 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,
773 engine,
774 std::move(wbh),
775 false,
776 BoxConstraints()) {}
777 ~MockFlutterWindowsView() {}
778
779 MOCK_METHOD(void,
780 NotifyWinEventWrapper,
781 (ui::AXPlatformNodeWin*, ax::mojom::Event),
782 (override));
783 MOCK_METHOD(HWND, GetWindowHandle, (), (const, override));
784 MOCK_METHOD(bool, Focus, (), (override));
785
786 private:
787 FML_DISALLOW_COPY_AND_ASSIGN(MockFlutterWindowsView);
788 };
789
790 // Verify the view is notified of accessibility announcements.
791 TEST_F(FlutterWindowsEngineTest, AccessibilityAnnouncement) {
792 auto& context = GetContext();
793 WindowsConfigBuilder builder{context};
794 builder.SetDartEntrypoint("sendAccessibilityAnnouncement");
795
796 bool done = false;
797 auto native_entry =
798 CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { done = true; });
799 context.AddNativeFunction("Signal", native_entry);
800
801 EnginePtr engine{builder.RunHeadless()};
802 ASSERT_NE(engine, nullptr);
803
804 ui::AXPlatformNodeDelegateBase parent_delegate;
805 AlertPlatformNodeDelegate delegate{parent_delegate};
806
807 auto window_binding_handler =
808 std::make_unique<NiceMock<MockWindowBindingHandler>>();
809 EXPECT_CALL(*window_binding_handler, GetAlertDelegate)
810 .WillOnce(Return(&delegate));
811
812 auto windows_engine = reinterpret_cast<FlutterWindowsEngine*>(engine.get());
813 MockFlutterWindowsView view{windows_engine,
814 std::move(window_binding_handler)};
815 EngineModifier modifier{windows_engine};
816 modifier.SetImplicitView(&view);
817
818 windows_engine->UpdateSemanticsEnabled(true);
819
820 EXPECT_CALL(view, NotifyWinEventWrapper).Times(1);
821
822 // Rely on timeout mechanism in CI.
823 while (!done) {
824 windows_engine->task_runner()->ProcessTasks();
825 }
826 }
827
828 // Verify the app can send accessibility announcements while in headless mode.
829 TEST_F(FlutterWindowsEngineTest, AccessibilityAnnouncementHeadless) {
830 auto& context = GetContext();
831 WindowsConfigBuilder builder{context};
832 builder.SetDartEntrypoint("sendAccessibilityAnnouncement");
833
834 bool done = false;
835 auto native_entry =
836 CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { done = true; });
837 context.AddNativeFunction("Signal", native_entry);
838
839 EnginePtr engine{builder.RunHeadless()};
840 ASSERT_NE(engine, nullptr);
841
842 auto windows_engine = reinterpret_cast<FlutterWindowsEngine*>(engine.get());
843 windows_engine->UpdateSemanticsEnabled(true);
844
845 // Rely on timeout mechanism in CI.
846 while (!done) {
847 windows_engine->task_runner()->ProcessTasks();
848 }
849 }
850
851 // Verify the engine does not crash if it receives an accessibility event
852 // it does not support yet.
853 TEST_F(FlutterWindowsEngineTest, AccessibilityTooltip) {
854 fml::testing::LogCapture log_capture;
855
856 auto& context = GetContext();
857 WindowsConfigBuilder builder{context};
858 builder.SetDartEntrypoint("sendAccessibilityTooltipEvent");
859
860 bool done = false;
861 auto native_entry =
862 CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { done = true; });
863 context.AddNativeFunction("Signal", native_entry);
864
865 ViewControllerPtr controller{builder.Run()};
866 ASSERT_NE(controller, nullptr);
867
868 auto engine = FlutterDesktopViewControllerGetEngine(controller.get());
869 auto windows_engine = reinterpret_cast<FlutterWindowsEngine*>(engine);
870 windows_engine->UpdateSemanticsEnabled(true);
871
872 // Rely on timeout mechanism in CI.
873 while (!done) {
874 windows_engine->task_runner()->ProcessTasks();
875 }
876
877 // Verify no error was logged.
878 // Regression test for:
879 // https://github.com/flutter/flutter/issues/144274
880 EXPECT_EQ(log_capture.str().find("tooltip"), std::string::npos);
881 }
882
883 class MockWindowsLifecycleManager : public WindowsLifecycleManager {
884 public:
885 MockWindowsLifecycleManager(FlutterWindowsEngine* engine)
886 : WindowsLifecycleManager(engine) {}
887 virtual ~MockWindowsLifecycleManager() {}
888
889 MOCK_METHOD(
890 void,
891 Quit,
892 (std::optional<HWND>, std::optional<WPARAM>, std::optional<LPARAM>, UINT),
893 (override));
894 MOCK_METHOD(void, DispatchMessage, (HWND, UINT, WPARAM, LPARAM), (override));
895 MOCK_METHOD(bool, IsLastWindowOfProcess, (), (override));
896 MOCK_METHOD(void, SetLifecycleState, (AppLifecycleState), (override));
897
898 void BeginProcessingLifecycle() override {
899 WindowsLifecycleManager::BeginProcessingLifecycle();
900 if (begin_processing_callback) {
901 begin_processing_callback();
902 }
903 }
904
905 std::function<void()> begin_processing_callback = nullptr;
906 };
907
908 TEST_F(FlutterWindowsEngineTest, TestExit) {
909 FlutterWindowsEngineBuilder builder{GetContext()};
910 builder.SetDartEntrypoint("exitTestExit");
911 bool finished = false;
912
913 auto engine = builder.Build();
914 auto window_binding_handler =
915 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
916 MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler));
917
918 EngineModifier modifier(engine.get());
919 modifier.SetImplicitView(&view);
920 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
921 auto handler = std::make_unique<MockWindowsLifecycleManager>(engine.get());
922 EXPECT_CALL(*handler, Quit)
923 .WillOnce([&finished](std::optional<HWND> hwnd,
924 std::optional<WPARAM> wparam,
925 std::optional<LPARAM> lparam,
926 UINT exit_code) { finished = exit_code == 0; });
927 EXPECT_CALL(*handler, IsLastWindowOfProcess).WillRepeatedly(Return(true));
928 modifier.SetLifecycleManager(std::move(handler));
929
930 engine->lifecycle_manager()->BeginProcessingExit();
931
932 engine->Run();
933
934 engine->window_proc_delegate_manager()->OnTopLevelWindowProc(0, WM_CLOSE, 0,
935 0);
936
937 // The test will only succeed when this while loop exits. Otherwise it will
938 // timeout.
939 while (!finished) {
940 engine->task_runner()->ProcessTasks();
941 }
942 }
943
944 TEST_F(FlutterWindowsEngineTest, TestExitCancel) {
945 FlutterWindowsEngineBuilder builder{GetContext()};
946 builder.SetDartEntrypoint("exitTestCancel");
947 bool did_call = false;
948
949 auto engine = builder.Build();
950 auto window_binding_handler =
951 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
952 MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler));
953
954 EngineModifier modifier(engine.get());
955 modifier.SetImplicitView(&view);
956 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
957 auto handler = std::make_unique<MockWindowsLifecycleManager>(engine.get());
958 EXPECT_CALL(*handler, IsLastWindowOfProcess).WillRepeatedly(Return(true));
959 EXPECT_CALL(*handler, Quit).Times(0);
960 modifier.SetLifecycleManager(std::move(handler));
961 engine->lifecycle_manager()->BeginProcessingExit();
962
963 auto binary_messenger =
964 std::make_unique<BinaryMessengerImpl>(engine->messenger());
965 binary_messenger->SetMessageHandler(
966 "flutter/platform", [&did_call](const uint8_t* message,
967 size_t message_size, BinaryReply reply) {
968 std::string contents(message, message + message_size);
969 EXPECT_NE(contents.find("\"method\":\"System.exitApplication\""),
970 std::string::npos);
971 EXPECT_NE(contents.find("\"type\":\"required\""), std::string::npos);
972 EXPECT_NE(contents.find("\"exitCode\":0"), std::string::npos);
973 did_call = true;
974 char response[] = "";
975 reply(reinterpret_cast<uint8_t*>(response), 0);
976 });
977
978 engine->Run();
979
980 engine->window_proc_delegate_manager()->OnTopLevelWindowProc(0, WM_CLOSE, 0,
981 0);
982
983 while (!did_call) {
984 engine->task_runner()->ProcessTasks();
985 }
986 }
987
988 // Flutter consumes the first WM_CLOSE message to allow the app to cancel the
989 // exit. If the app does not cancel the exit, Flutter synthesizes a second
990 // WM_CLOSE message.
991 TEST_F(FlutterWindowsEngineTest, TestExitSecondCloseMessage) {
992 FlutterWindowsEngineBuilder builder{GetContext()};
993 builder.SetDartEntrypoint("exitTestExit");
994 bool second_close = false;
995
996 auto engine = builder.Build();
997 auto window_binding_handler =
998 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
999 MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler));
1000
1001 EngineModifier modifier(engine.get());
1002 modifier.SetImplicitView(&view);
1003 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1004 auto handler = std::make_unique<MockWindowsLifecycleManager>(engine.get());
1005 EXPECT_CALL(*handler, IsLastWindowOfProcess).WillOnce(Return(true));
1006 EXPECT_CALL(*handler, Quit)
1007 .WillOnce([handler_ptr = handler.get()](
1008 std::optional<HWND> hwnd, std::optional<WPARAM> wparam,
1009 std::optional<LPARAM> lparam, UINT exit_code) {
1010 handler_ptr->WindowsLifecycleManager::Quit(hwnd, wparam, lparam,
1011 exit_code);
1012 });
1013 EXPECT_CALL(*handler, DispatchMessage)
1014 .WillRepeatedly(
1015 [&engine](HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
1016 engine->window_proc_delegate_manager()->OnTopLevelWindowProc(
1017 hwnd, msg, wparam, lparam);
1018 });
1019 modifier.SetLifecycleManager(std::move(handler));
1020 engine->lifecycle_manager()->BeginProcessingExit();
1021
1022 engine->Run();
1023
1024 // This delegate will be registered after the lifecycle manager, so it will be
1025 // called only when a message is not consumed by the lifecycle manager. This
1026 // should be called on the second, synthesized WM_CLOSE message that the
1027 // lifecycle manager posts.
1028 engine->window_proc_delegate_manager()->RegisterTopLevelWindowProcDelegate(
1029 [](HWND hwnd, UINT message, WPARAM wpar, LPARAM lpar, void* user_data,
1030 LRESULT* result) {
1031 switch (message) {
1032 case WM_CLOSE: {
1033 bool* called = reinterpret_cast<bool*>(user_data);
1034 *called = true;
1035 return true;
1036 }
1037 }
1038 return false;
1039 },
1040 reinterpret_cast<void*>(&second_close));
1041
1042 engine->window_proc_delegate_manager()->OnTopLevelWindowProc(0, WM_CLOSE, 0,
1043 0);
1044
1045 while (!second_close) {
1046 engine->task_runner()->ProcessTasks();
1047 }
1048 }
1049
1050 TEST_F(FlutterWindowsEngineTest, TestExitCloseMultiWindow) {
1051 FlutterWindowsEngineBuilder builder{GetContext()};
1052 builder.SetDartEntrypoint("exitTestExit");
1053 bool finished = false;
1054
1055 auto engine = builder.Build();
1056 auto window_binding_handler =
1057 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
1058 MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler));
1059
1060 EngineModifier modifier(engine.get());
1061 modifier.SetImplicitView(&view);
1062 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1063 auto handler = std::make_unique<MockWindowsLifecycleManager>(engine.get());
1064 EXPECT_CALL(*handler, IsLastWindowOfProcess).WillOnce([&finished]() {
1065 finished = true;
1066 return false;
1067 });
1068 // Quit should not be called when there is more than one window.
1069 EXPECT_CALL(*handler, Quit).Times(0);
1070 modifier.SetLifecycleManager(std::move(handler));
1071 engine->lifecycle_manager()->BeginProcessingExit();
1072
1073 engine->Run();
1074
1075 engine->window_proc_delegate_manager()->OnTopLevelWindowProc(0, WM_CLOSE, 0,
1076 0);
1077
1078 while (!finished) {
1079 engine->task_runner()->ProcessTasks();
1080 }
1081 }
1082
1083 TEST_F(FlutterWindowsEngineTest, LifecycleManagerDisabledByDefault) {
1084 FlutterWindowsEngineBuilder builder{GetContext()};
1085
1086 auto engine = builder.Build();
1087 auto window_binding_handler =
1088 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
1089 MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler));
1090
1091 EngineModifier modifier(engine.get());
1092 modifier.SetImplicitView(&view);
1093 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1094 auto handler = std::make_unique<MockWindowsLifecycleManager>(engine.get());
1095 EXPECT_CALL(*handler, IsLastWindowOfProcess).Times(0);
1096 modifier.SetLifecycleManager(std::move(handler));
1097
1098 engine->window_proc_delegate_manager()->OnTopLevelWindowProc(0, WM_CLOSE, 0,
1099 0);
1100 }
1101
1102 TEST_F(FlutterWindowsEngineTest, EnableApplicationLifecycle) {
1103 FlutterWindowsEngineBuilder builder{GetContext()};
1104
1105 auto engine = builder.Build();
1106 auto window_binding_handler =
1107 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
1108 MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler));
1109
1110 EngineModifier modifier(engine.get());
1111 modifier.SetImplicitView(&view);
1112 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1113 auto handler = std::make_unique<MockWindowsLifecycleManager>(engine.get());
1114 EXPECT_CALL(*handler, IsLastWindowOfProcess).WillOnce(Return(false));
1115 modifier.SetLifecycleManager(std::move(handler));
1116 engine->lifecycle_manager()->BeginProcessingExit();
1117
1118 engine->window_proc_delegate_manager()->OnTopLevelWindowProc(0, WM_CLOSE, 0,
1119 0);
1120 }
1121
1122 TEST_F(FlutterWindowsEngineTest, ApplicationLifecycleExternalWindow) {
1123 FlutterWindowsEngineBuilder builder{GetContext()};
1124
1125 auto engine = builder.Build();
1126 auto window_binding_handler =
1127 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
1128 MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler));
1129
1130 EngineModifier modifier(engine.get());
1131 modifier.SetImplicitView(&view);
1132 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1133 auto handler = std::make_unique<MockWindowsLifecycleManager>(engine.get());
1134 EXPECT_CALL(*handler, IsLastWindowOfProcess).WillOnce(Return(false));
1135 modifier.SetLifecycleManager(std::move(handler));
1136 engine->lifecycle_manager()->BeginProcessingExit();
1137
1138 engine->lifecycle_manager()->ExternalWindowMessage(0, WM_CLOSE, 0, 0);
1139 }
1140
1141 TEST_F(FlutterWindowsEngineTest, LifecycleStateTransition) {
1142 FlutterWindowsEngineBuilder builder{GetContext()};
1143
1144 auto engine = builder.Build();
1145 auto window_binding_handler =
1146 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
1147 MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler));
1148
1149 EngineModifier modifier(engine.get());
1150 modifier.SetImplicitView(&view);
1151 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1152 engine->Run();
1153
1154 engine->window_proc_delegate_manager()->OnTopLevelWindowProc(
1155 (HWND)1, WM_SIZE, SIZE_RESTORED, 0);
1156
1157 while (engine->lifecycle_manager()->IsUpdateStateScheduled()) {
1158 PumpMessage();
1159 }
1160
1161 EXPECT_EQ(engine->lifecycle_manager()->GetLifecycleState(),
1162 AppLifecycleState::kInactive);
1163
1164 engine->lifecycle_manager()->OnWindowStateEvent((HWND)1,
1165 WindowStateEvent::kFocus);
1166
1167 while (engine->lifecycle_manager()->IsUpdateStateScheduled()) {
1168 PumpMessage();
1169 }
1170
1171 EXPECT_EQ(engine->lifecycle_manager()->GetLifecycleState(),
1172 AppLifecycleState::kResumed);
1173
1174 engine->window_proc_delegate_manager()->OnTopLevelWindowProc(
1175 (HWND)1, WM_SIZE, SIZE_MINIMIZED, 0);
1176
1177 while (engine->lifecycle_manager()->IsUpdateStateScheduled()) {
1178 PumpMessage();
1179 }
1180
1181 EXPECT_EQ(engine->lifecycle_manager()->GetLifecycleState(),
1182 AppLifecycleState::kHidden);
1183
1184 engine->window_proc_delegate_manager()->OnTopLevelWindowProc(
1185 (HWND)1, WM_SIZE, SIZE_RESTORED, 0);
1186
1187 while (engine->lifecycle_manager()->IsUpdateStateScheduled()) {
1188 PumpMessage();
1189 }
1190
1191 EXPECT_EQ(engine->lifecycle_manager()->GetLifecycleState(),
1192 AppLifecycleState::kInactive);
1193 }
1194
1195 TEST_F(FlutterWindowsEngineTest, ExternalWindowMessage) {
1196 FlutterWindowsEngineBuilder builder{GetContext()};
1197
1198 auto engine = builder.Build();
1199 auto window_binding_handler =
1200 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
1201 MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler));
1202
1203 EngineModifier modifier(engine.get());
1204 modifier.SetImplicitView(&view);
1205 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1206 // Sets lifecycle state to resumed.
1207 engine->Run();
1208
1209 // Ensure HWND(1) is in the set of visible windows before hiding it.
1210 engine->ProcessExternalWindowMessage(reinterpret_cast<HWND>(1), WM_SHOWWINDOW,
1211 TRUE, NULL);
1212 engine->ProcessExternalWindowMessage(reinterpret_cast<HWND>(1), WM_SHOWWINDOW,
1213 FALSE, NULL);
1214
1215 while (engine->lifecycle_manager()->IsUpdateStateScheduled()) {
1216 PumpMessage();
1217 }
1218
1219 EXPECT_EQ(engine->lifecycle_manager()->GetLifecycleState(),
1220 AppLifecycleState::kHidden);
1221 }
1222
1223 TEST_F(FlutterWindowsEngineTest, InnerWindowHidden) {
1224 FlutterWindowsEngineBuilder builder{GetContext()};
1225 HWND outer = reinterpret_cast<HWND>(1);
1226 HWND inner = reinterpret_cast<HWND>(2);
1227
1228 auto engine = builder.Build();
1229 auto window_binding_handler =
1230 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
1231 MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler));
1232 ON_CALL(view, GetWindowHandle).WillByDefault([=]() { return inner; });
1233
1234 EngineModifier modifier(engine.get());
1235 modifier.SetImplicitView(&view);
1236 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1237 // Sets lifecycle state to resumed.
1238 engine->Run();
1239
1240 // Show both top-level and Flutter window.
1241 engine->window_proc_delegate_manager()->OnTopLevelWindowProc(
1242 outer, WM_SHOWWINDOW, TRUE, NULL);
1243 view.OnWindowStateEvent(inner, WindowStateEvent::kShow);
1244 view.OnWindowStateEvent(inner, WindowStateEvent::kFocus);
1245
1246 while (engine->lifecycle_manager()->IsUpdateStateScheduled()) {
1247 PumpMessage();
1248 }
1249
1250 EXPECT_EQ(engine->lifecycle_manager()->GetLifecycleState(),
1251 AppLifecycleState::kResumed);
1252
1253 // Hide Flutter window, but not top level window.
1254 view.OnWindowStateEvent(inner, WindowStateEvent::kHide);
1255
1256 while (engine->lifecycle_manager()->IsUpdateStateScheduled()) {
1257 PumpMessage();
1258 }
1259
1260 // The top-level window is still visible, so we ought not enter hidden state.
1261 EXPECT_EQ(engine->lifecycle_manager()->GetLifecycleState(),
1262 AppLifecycleState::kInactive);
1263 }
1264
1265 TEST_F(FlutterWindowsEngineTest, EnableLifecycleState) {
1266 FlutterWindowsEngineBuilder builder{GetContext()};
1267 builder.SetDartEntrypoint("enableLifecycleTest");
1268 bool finished = false;
1269
1270 auto engine = builder.Build();
1271 auto window_binding_handler =
1272 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
1273 MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler));
1274
1275 EngineModifier modifier(engine.get());
1276 modifier.SetImplicitView(&view);
1277 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1278 auto handler = std::make_unique<MockWindowsLifecycleManager>(engine.get());
1279 EXPECT_CALL(*handler, SetLifecycleState)
1280 .WillRepeatedly([handler_ptr = handler.get()](AppLifecycleState state) {
1281 handler_ptr->WindowsLifecycleManager::SetLifecycleState(state);
1282 });
1283 modifier.SetLifecycleManager(std::move(handler));
1284
1285 auto binary_messenger =
1286 std::make_unique<BinaryMessengerImpl>(engine->messenger());
1287 // Mark the test only as completed on receiving an inactive state message.
1288 binary_messenger->SetMessageHandler(
1289 "flutter/unittest", [&finished](const uint8_t* message,
1290 size_t message_size, BinaryReply reply) {
1291 std::string contents(message, message + message_size);
1292 EXPECT_NE(contents.find("AppLifecycleState.inactive"),
1293 std::string::npos);
1294 finished = true;
1295 char response[] = "";
1296 reply(reinterpret_cast<uint8_t*>(response), 0);
1297 });
1298
1299 engine->Run();
1300
1301 // Test that setting the state before enabling lifecycle does nothing.
1302 HWND hwnd = reinterpret_cast<HWND>(1);
1303 view.OnWindowStateEvent(hwnd, WindowStateEvent::kShow);
1304 view.OnWindowStateEvent(hwnd, WindowStateEvent::kHide);
1305 EXPECT_FALSE(finished);
1306
1307 // Test that we can set the state afterwards.
1308
1309 engine->lifecycle_manager()->BeginProcessingLifecycle();
1310 view.OnWindowStateEvent(hwnd, WindowStateEvent::kShow);
1311
1312 while (!finished) {
1313 engine->task_runner()->ProcessTasks();
1314 }
1315 }
1316
1317 TEST_F(FlutterWindowsEngineTest, LifecycleStateToFrom) {
1318 FlutterWindowsEngineBuilder builder{GetContext()};
1319 builder.SetDartEntrypoint("enableLifecycleToFrom");
1320 bool enabled_lifecycle = false;
1321 bool dart_responded = false;
1322
1323 auto engine = builder.Build();
1324 auto window_binding_handler =
1325 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
1326 MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler));
1327
1328 EngineModifier modifier(engine.get());
1329 modifier.SetImplicitView(&view);
1330 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1331 auto handler = std::make_unique<MockWindowsLifecycleManager>(engine.get());
1332 EXPECT_CALL(*handler, SetLifecycleState)
1333 .WillRepeatedly([handler_ptr = handler.get()](AppLifecycleState state) {
1334 handler_ptr->WindowsLifecycleManager::SetLifecycleState(state);
1335 });
1336 handler->begin_processing_callback = [&]() { enabled_lifecycle = true; };
1337 modifier.SetLifecycleManager(std::move(handler));
1338
1339 auto binary_messenger =
1340 std::make_unique<BinaryMessengerImpl>(engine->messenger());
1341 binary_messenger->SetMessageHandler(
1342 "flutter/unittest",
1343 [&](const uint8_t* message, size_t message_size, BinaryReply reply) {
1344 std::string contents(message, message + message_size);
1345 EXPECT_NE(contents.find("AppLifecycleState."), std::string::npos);
1346 dart_responded = true;
1347 char response[] = "";
1348 reply(reinterpret_cast<uint8_t*>(response), 0);
1349 });
1350
1351 engine->Run();
1352
1353 while (!enabled_lifecycle) {
1354 engine->task_runner()->ProcessTasks();
1355 }
1356
1357 HWND hwnd = reinterpret_cast<HWND>(1);
1358 view.OnWindowStateEvent(hwnd, WindowStateEvent::kShow);
1359 view.OnWindowStateEvent(hwnd, WindowStateEvent::kHide);
1360
1361 while (!dart_responded) {
1362 engine->task_runner()->ProcessTasks();
1363 }
1364 }
1365
1366 TEST_F(FlutterWindowsEngineTest, ChannelListenedTo) {
1367 FlutterWindowsEngineBuilder builder{GetContext()};
1368 builder.SetDartEntrypoint("enableLifecycleToFrom");
1369
1370 auto engine = builder.Build();
1371 auto window_binding_handler =
1372 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
1373 MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler));
1374
1375 EngineModifier modifier(engine.get());
1376 modifier.SetImplicitView(&view);
1377 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1378
1379 bool lifecycle_began = false;
1380 auto handler = std::make_unique<MockWindowsLifecycleManager>(engine.get());
1381 handler->begin_processing_callback = [&]() { lifecycle_began = true; };
1382 modifier.SetLifecycleManager(std::move(handler));
1383
1384 engine->Run();
1385
1386 while (!lifecycle_began) {
1387 engine->task_runner()->ProcessTasks();
1388 }
1389 }
1390
1391 TEST_F(FlutterWindowsEngineTest, ReceivePlatformViewMessage) {
1392 FlutterWindowsEngineBuilder builder{GetContext()};
1393 builder.SetDartEntrypoint("sendCreatePlatformViewMethod");
1394 auto engine = builder.Build();
1395
1396 EngineModifier modifier{engine.get()};
1397 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1398
1399 bool received_call = false;
1400
1401 auto manager = std::make_unique<MockPlatformViewManager>(engine.get());
1402 EXPECT_CALL(*manager, AddPlatformView)
1403 .WillOnce([&](PlatformViewId id, std::string_view type_name) {
1404 received_call = true;
1405 return true;
1406 });
1407 modifier.SetPlatformViewPlugin(std::move(manager));
1408
1409 engine->Run();
1410
1411 while (!received_call) {
1412 engine->task_runner()->ProcessTasks();
1413 }
1414 }
1415
1416 TEST_F(FlutterWindowsEngineTest, AddViewFailureDoesNotHang) {
1417 FlutterWindowsEngineBuilder builder{GetContext()};
1418 auto engine = builder.Build();
1419
1420 EngineModifier modifier{engine.get()};
1421
1422 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1423 modifier.embedder_api().AddView = MOCK_ENGINE_PROC(
1424 AddView,
1425 [](FLUTTER_API_SYMBOL(FlutterEngine) engine,
1426 const FlutterAddViewInfo* info) { return kInternalInconsistency; });
1427
1428 ASSERT_TRUE(engine->Run());
1429
1430 // Create the first view. This is the implicit view and isn't added to the
1431 // engine.
1432 auto implicit_window = std::make_unique<NiceMock<MockWindowBindingHandler>>();
1433
1434 std::unique_ptr<FlutterWindowsView> implicit_view =
1435 engine->CreateView(std::move(implicit_window),
1436 /*is_sized_to_content=*/false, BoxConstraints());
1437
1438 EXPECT_TRUE(implicit_view);
1439
1440 // Create a second view. The embedder attempts to add it to the engine.
1441 auto second_window = std::make_unique<NiceMock<MockWindowBindingHandler>>();
1442
1443 EXPECT_DEBUG_DEATH(
1444 engine->CreateView(std::move(second_window),
1445 /*is_sized_to_content=*/false, BoxConstraints()),
1446 "FlutterEngineAddView returned an unexpected result");
1447 }
1448
1449 TEST_F(FlutterWindowsEngineTest, RemoveViewFailureDoesNotHang) {
1450 FlutterWindowsEngineBuilder builder{GetContext()};
1451 builder.SetDartEntrypoint("sendCreatePlatformViewMethod");
1452 auto engine = builder.Build();
1453
1454 EngineModifier modifier{engine.get()};
1455
1456 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1457 modifier.embedder_api().RemoveView = MOCK_ENGINE_PROC(
1458 RemoveView,
1459 [](FLUTTER_API_SYMBOL(FlutterEngine) engine,
1460 const FlutterRemoveViewInfo* info) { return kInternalInconsistency; });
1461
1462 ASSERT_TRUE(engine->Run());
1463 EXPECT_DEBUG_DEATH(engine->RemoveView(123),
1464 "FlutterEngineRemoveView returned an unexpected result");
1465 }
1466
1467 TEST_F(FlutterWindowsEngineTest, MergedUIThread) {
1468 auto& context = GetContext();
1469 WindowsConfigBuilder builder{context};
1470 builder.SetDartEntrypoint("mergedUIThread");
1471 builder.SetUIThreadPolicy(FlutterDesktopUIThreadPolicy::RunOnPlatformThread);
1472
1473 std::optional<std::thread::id> ui_thread_id;
1474
1475 auto native_entry = CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
1476 ui_thread_id = std::this_thread::get_id();
1477 });
1478 context.AddNativeFunction("Signal", native_entry);
1479
1480 EnginePtr engine{builder.RunHeadless()};
1481 while (!ui_thread_id) {
1482 PumpMessage();
1483 }
1484 ASSERT_EQ(*ui_thread_id, std::this_thread::get_id());
1485 }
1486
1487 TEST_F(FlutterWindowsEngineTest, OnViewFocusChangeRequest) {
1488 FlutterWindowsEngineBuilder builder{GetContext()};
1489 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
1490 auto window_binding_handler =
1491 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
1492 MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler));
1493
1494 EngineModifier modifier(engine.get());
1495 modifier.SetImplicitView(&view);
1496
1497 FlutterViewFocusChangeRequest request;
1498 request.view_id = kImplicitViewId;
1499
1500 EXPECT_CALL(view, Focus()).WillOnce(Return(true));
1501 modifier.OnViewFocusChangeRequest(&request);
1502 }
1503
1504 TEST_F(FlutterWindowsEngineTest, UpdateSemanticsMultiView) {
1505 auto& context = GetContext();
1506 WindowsConfigBuilder builder{context};
1507 builder.SetDartEntrypoint("sendSemanticsTreeInfo");
1508
1509 // Setup: a signal for when we have send out all of our semantics updates
1510 bool done = false;
1511 auto native_entry =
1512 CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { done = true; });
1513 context.AddNativeFunction("Signal", native_entry);
1514
1515 // Setup: Create the engine and two views + enable semantics
1516 EnginePtr engine{builder.RunHeadless()};
1517 ASSERT_NE(engine, nullptr);
1518
1519 auto window_binding_handler1 =
1520 std::make_unique<NiceMock<MockWindowBindingHandler>>();
1521 auto window_binding_handler2 =
1522 std::make_unique<NiceMock<MockWindowBindingHandler>>();
1523
1524 // The following mocks are required by
1525 // FlutterWindowsView::CreateWindowMetricsEvent so that we create a valid
1526 // view.
1527 EXPECT_CALL(*window_binding_handler1, GetPhysicalWindowBounds)
1528 .WillRepeatedly(testing::Return(PhysicalWindowBounds{100, 100}));
1529 EXPECT_CALL(*window_binding_handler1, GetDpiScale)
1530 .WillRepeatedly(testing::Return(96.0));
1531 EXPECT_CALL(*window_binding_handler2, GetPhysicalWindowBounds)
1532 .WillRepeatedly(testing::Return(PhysicalWindowBounds{200, 200}));
1533 EXPECT_CALL(*window_binding_handler2, GetDpiScale)
1534 .WillRepeatedly(testing::Return(96.0));
1535
1536 auto windows_engine = reinterpret_cast<FlutterWindowsEngine*>(engine.get());
1537 EngineModifier modifier{windows_engine};
1538 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1539
1540 // We want to avoid adding an implicit view as the first view
1541 modifier.SetNextViewId(kImplicitViewId + 1);
1542
1543 auto view1 = windows_engine->CreateView(std::move(window_binding_handler1),
1544 /*is_sized_to_content=*/false,
1545 BoxConstraints());
1546 auto view2 = windows_engine->CreateView(std::move(window_binding_handler2),
1547 /*is_sized_to_content=*/false,
1548 BoxConstraints());
1549
1550 // Act: UpdateSemanticsEnabled will trigger the semantics updates
1551 // to get sent.
1552 windows_engine->UpdateSemanticsEnabled(true);
1553
1554 while (!done) {
1555 windows_engine->task_runner()->ProcessTasks();
1556 }
1557
1558 auto accessibility_bridge1 = view1->accessibility_bridge().lock();
1559 auto accessibility_bridge2 = view2->accessibility_bridge().lock();
1560
1561 // Expect: that the semantics trees are updated with their
1562 // respective nodes.
1563 while (
1564 !accessibility_bridge1->GetPlatformNodeFromTree(view1->view_id() + 1)) {
1565 windows_engine->task_runner()->ProcessTasks();
1566 }
1567
1568 while (
1569 !accessibility_bridge2->GetPlatformNodeFromTree(view2->view_id() + 1)) {
1570 windows_engine->task_runner()->ProcessTasks();
1571 }
1572
1573 // Rely on timeout mechanism in CI.
1574 auto tree1 = accessibility_bridge1->GetTree();
1575 auto tree2 = accessibility_bridge2->GetTree();
1576 EXPECT_NE(tree1->GetFromId(view1->view_id() + 1), nullptr);
1577 EXPECT_NE(tree2->GetFromId(view2->view_id() + 1), nullptr);
1578 }
1579
1580 } // namespace testing
1581 } // 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:990
flutter::FlutterWindowsEngine::CreateView
std::unique_ptr< FlutterWindowsView > CreateView(std::unique_ptr< WindowBindingHandler > window, bool is_sized_to_content, const BoxConstraints &box_constraints, FlutterWindowsViewSizingDelegate *sizing_delegate=nullptr)
Definition: flutter_windows_engine.cc:526
flutter::FlutterWindowsView
Definition: flutter_windows_view.h:46
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:777
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:883
flutter::testing::MockWindowsLifecycleManager::~MockWindowsLifecycleManager
virtual ~MockWindowsLifecycleManager()
Definition: flutter_windows_engine_unittests.cc:887
flutter::testing::MockWindowsLifecycleManager::begin_processing_callback
std::function< void()> begin_processing_callback
Definition: flutter_windows_engine_unittests.cc:905
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:898
flutter::testing::MockWindowsLifecycleManager::MOCK_METHOD
MOCK_METHOD(bool, IsLastWindowOfProcess,(),(override))
flutter::testing::MockWindowsLifecycleManager::MockWindowsLifecycleManager
MockWindowsLifecycleManager(FlutterWindowsEngine *engine)
Definition: flutter_windows_engine_unittests.cc:885
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:102
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