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