Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
flutter_windows_engine_unittests.cc
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "flutter/shell/platform/windows/flutter_windows_engine.h"
6
7#include "flutter/fml/logging.h"
8#include "flutter/fml/macros.h"
9#include "flutter/shell/platform/embedder/embedder.h"
10#include "flutter/shell/platform/embedder/test_utils/proc_table_replacement.h"
11#include "flutter/shell/platform/windows/flutter_windows_view.h"
12#include "flutter/shell/platform/windows/public/flutter_windows.h"
13#include "flutter/shell/platform/windows/testing/egl/mock_manager.h"
14#include "flutter/shell/platform/windows/testing/engine_modifier.h"
15#include "flutter/shell/platform/windows/testing/flutter_windows_engine_builder.h"
16#include "flutter/shell/platform/windows/testing/mock_platform_view_manager.h"
17#include "flutter/shell/platform/windows/testing/mock_window_binding_handler.h"
18#include "flutter/shell/platform/windows/testing/mock_windows_proc_table.h"
19#include "flutter/shell/platform/windows/testing/test_keyboard.h"
20#include "flutter/shell/platform/windows/testing/windows_test.h"
21#include "flutter/shell/platform/windows/testing/windows_test_config_builder.h"
22#include "flutter/third_party/accessibility/ax/platform/ax_platform_node_win.h"
24#include "gmock/gmock.h"
25#include "gtest/gtest.h"
26
27// winbase.h defines GetCurrentTime as a macro.
28#undef GetCurrentTime
29
30namespace flutter {
31namespace testing {
32
33using ::testing::NiceMock;
34using ::testing::Return;
35
37
38// The engine can be run without any views.
40 FlutterWindowsEngineBuilder builder{GetContext()};
41 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
42
43 EngineModifier modifier(engine.get());
44 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
45
46 ASSERT_TRUE(engine->Run());
47 ASSERT_EQ(engine->view(kImplicitViewId), nullptr);
48 ASSERT_EQ(engine->view(123), nullptr);
49}
50
51TEST_F(FlutterWindowsEngineTest, RunDoesExpectedInitialization) {
52 FlutterWindowsEngineBuilder builder{GetContext()};
53 builder.AddDartEntrypointArgument("arg1");
54 builder.AddDartEntrypointArgument("arg2");
55
56 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
57 EngineModifier modifier(engine.get());
58
59 // The engine should be run with expected configuration values.
60 bool run_called = false;
62 Run, ([&run_called, engine_instance = engine.get()](
63 size_t version, const FlutterRendererConfig* config,
64 const FlutterProjectArgs* args, void* user_data,
65 FLUTTER_API_SYMBOL(FlutterEngine) * engine_out) {
66 run_called = true;
67 *engine_out = reinterpret_cast<FLUTTER_API_SYMBOL(FlutterEngine)>(1);
68
69 EXPECT_EQ(version, FLUTTER_ENGINE_VERSION);
70 EXPECT_NE(config, nullptr);
71 // We have an EGL manager, so this should be using OpenGL.
72 EXPECT_EQ(config->type, kOpenGL);
73 EXPECT_EQ(user_data, engine_instance);
74 // Spot-check arguments.
75 EXPECT_NE(args->assets_path, nullptr);
76 EXPECT_NE(args->icu_data_path, nullptr);
77 EXPECT_EQ(args->dart_entrypoint_argc, 2U);
78 EXPECT_EQ(strcmp(args->dart_entrypoint_argv[0], "arg1"), 0);
79 EXPECT_EQ(strcmp(args->dart_entrypoint_argv[1], "arg2"), 0);
80 EXPECT_NE(args->platform_message_callback, nullptr);
81 EXPECT_NE(args->custom_task_runners, nullptr);
82 EXPECT_NE(args->custom_task_runners->thread_priority_setter, nullptr);
83 EXPECT_EQ(args->custom_dart_entrypoint, nullptr);
84 EXPECT_NE(args->vsync_callback, nullptr);
85 EXPECT_EQ(args->update_semantics_callback, nullptr);
86 EXPECT_NE(args->update_semantics_callback2, nullptr);
87 EXPECT_EQ(args->update_semantics_node_callback, nullptr);
88 EXPECT_EQ(args->update_semantics_custom_action_callback, nullptr);
89
90 args->custom_task_runners->thread_priority_setter(
92 EXPECT_EQ(GetThreadPriority(GetCurrentThread()),
93 THREAD_PRIORITY_ABOVE_NORMAL);
94 return kSuccess;
95 }));
96 // Accessibility updates must do nothing when the embedder engine is mocked
98 UpdateAccessibilityFeatures,
101
102 // It should send locale info.
103 bool update_locales_called = false;
105 UpdateLocales,
106 ([&update_locales_called](auto engine, const FlutterLocale** locales,
107 size_t locales_count) {
108 update_locales_called = true;
109
110 EXPECT_GT(locales_count, 0);
111 EXPECT_NE(locales, nullptr);
112
113 return kSuccess;
114 }));
115
116 // And it should send initial settings info.
117 bool settings_message_sent = false;
119 SendPlatformMessage,
120 ([&settings_message_sent](auto engine, auto message) {
121 if (std::string(message->channel) == std::string("flutter/settings")) {
122 settings_message_sent = true;
123 }
124
125 return kSuccess;
126 }));
127
128 // And it should send display info.
129 bool notify_display_update_called = false;
130 modifier.SetFrameInterval(16600000); // 60 fps.
132 NotifyDisplayUpdate,
133 ([&notify_display_update_called, engine_instance = engine.get()](
135 const FlutterEngineDisplaysUpdateType update_type,
136 const FlutterEngineDisplay* embedder_displays,
137 size_t display_count) {
138 EXPECT_EQ(update_type, kFlutterEngineDisplaysUpdateTypeStartup);
139 EXPECT_EQ(display_count, 1);
140
141 FlutterEngineDisplay display = embedder_displays[0];
142
143 EXPECT_EQ(display.display_id, 0);
144 EXPECT_EQ(display.single_display, true);
145 EXPECT_EQ(std::floor(display.refresh_rate), 60.0);
146
147 notify_display_update_called = true;
148 return kSuccess;
149 }));
150
151 // Set the EGL manager to !nullptr to test ANGLE rendering.
152 modifier.SetEGLManager(std::make_unique<egl::MockManager>());
153
154 engine->Run();
155
156 EXPECT_TRUE(run_called);
157 EXPECT_TRUE(update_locales_called);
158 EXPECT_TRUE(settings_message_sent);
159 EXPECT_TRUE(notify_display_update_called);
160
161 // Ensure that deallocation doesn't call the actual Shutdown with the bogus
162 // engine pointer that the overridden Run returned.
163 modifier.embedder_api().Shutdown = [](auto engine) { return kSuccess; };
164 modifier.ReleaseEGLManager();
165}
166
167TEST_F(FlutterWindowsEngineTest, ConfiguresFrameVsync) {
168 FlutterWindowsEngineBuilder builder{GetContext()};
169 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
170 EngineModifier modifier(engine.get());
171 bool on_vsync_called = false;
172
173 modifier.embedder_api().GetCurrentTime =
174 MOCK_ENGINE_PROC(GetCurrentTime, ([]() -> uint64_t { return 1; }));
176 OnVsync,
177 ([&on_vsync_called, engine_instance = engine.get()](
178 FLUTTER_API_SYMBOL(FlutterEngine) engine, intptr_t baton,
179 uint64_t frame_start_time_nanos, uint64_t frame_target_time_nanos) {
180 EXPECT_EQ(baton, 1);
181 EXPECT_EQ(frame_start_time_nanos, 16600000);
182 EXPECT_EQ(frame_target_time_nanos, 33200000);
183 on_vsync_called = true;
184 return kSuccess;
185 }));
186 modifier.SetStartTime(0);
187 modifier.SetFrameInterval(16600000);
188
189 engine->OnVsync(1);
190
191 EXPECT_TRUE(on_vsync_called);
192}
193
194TEST_F(FlutterWindowsEngineTest, RunWithoutANGLEUsesSoftware) {
195 FlutterWindowsEngineBuilder builder{GetContext()};
196 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
197 EngineModifier modifier(engine.get());
198
200 MOCK_ENGINE_PROC(NotifyDisplayUpdate,
201 ([engine_instance = engine.get()](
203 const FlutterEngineDisplaysUpdateType update_type,
204 const FlutterEngineDisplay* embedder_displays,
205 size_t display_count) { return kSuccess; }));
206
207 // The engine should be run with expected configuration values.
208 bool run_called = false;
209 modifier.embedder_api().Run = MOCK_ENGINE_PROC(
210 Run, ([&run_called, engine_instance = engine.get()](
211 size_t version, const FlutterRendererConfig* config,
212 const FlutterProjectArgs* args, void* user_data,
213 FLUTTER_API_SYMBOL(FlutterEngine) * engine_out) {
214 run_called = true;
215 *engine_out = reinterpret_cast<FLUTTER_API_SYMBOL(FlutterEngine)>(1);
216 // We don't have an EGL Manager, so we should be using software.
217 EXPECT_EQ(config->type, kSoftware);
218 return kSuccess;
219 }));
220 // Accessibility updates must do nothing when the embedder engine is mocked
222 UpdateAccessibilityFeatures,
225
226 // Stub out UpdateLocales and SendPlatformMessage as we don't have a fully
227 // initialized engine instance.
229 UpdateLocales, ([](auto engine, const FlutterLocale** locales,
230 size_t locales_count) { return kSuccess; }));
232 MOCK_ENGINE_PROC(SendPlatformMessage,
233 ([](auto engine, auto message) { return kSuccess; }));
234
235 // Set the EGL manager to nullptr to test software fallback path.
236 modifier.SetEGLManager(nullptr);
237
238 engine->Run();
239
240 EXPECT_TRUE(run_called);
241
242 // Ensure that deallocation doesn't call the actual Shutdown with the bogus
243 // engine pointer that the overridden Run returned.
244 modifier.embedder_api().Shutdown = [](auto engine) { return kSuccess; };
245}
246
247TEST_F(FlutterWindowsEngineTest, RunWithoutANGLEOnImpellerFailsToStart) {
248 FlutterWindowsEngineBuilder builder{GetContext()};
249 builder.SetSwitches({"--enable-impeller=true"});
250 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
251 EngineModifier modifier(engine.get());
252
254 MOCK_ENGINE_PROC(NotifyDisplayUpdate,
255 ([engine_instance = engine.get()](
257 const FlutterEngineDisplaysUpdateType update_type,
258 const FlutterEngineDisplay* embedder_displays,
259 size_t display_count) { return kSuccess; }));
260
261 // Accessibility updates must do nothing when the embedder engine is mocked
263 UpdateAccessibilityFeatures,
266
267 // Stub out UpdateLocales and SendPlatformMessage as we don't have a fully
268 // initialized engine instance.
270 UpdateLocales, ([](auto engine, const FlutterLocale** locales,
271 size_t locales_count) { return kSuccess; }));
273 MOCK_ENGINE_PROC(SendPlatformMessage,
274 ([](auto engine, auto message) { return kSuccess; }));
275
276 // Set the EGL manager to nullptr to test software fallback path.
277 modifier.SetEGLManager(nullptr);
278
279 EXPECT_FALSE(engine->Run());
280}
281
282TEST_F(FlutterWindowsEngineTest, SendPlatformMessageWithoutResponse) {
283 FlutterWindowsEngineBuilder builder{GetContext()};
284 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
285 EngineModifier modifier(engine.get());
286
287 const char* channel = "test";
288 const std::vector<uint8_t> test_message = {1, 2, 3, 4};
289
290 // Without a response, SendPlatformMessage should be a simple pass-through.
291 bool called = false;
293 SendPlatformMessage, ([&called, test_message](auto engine, auto message) {
294 called = true;
295 EXPECT_STREQ(message->channel, "test");
296 EXPECT_EQ(message->message_size, test_message.size());
297 EXPECT_EQ(memcmp(message->message, test_message.data(),
298 message->message_size),
299 0);
300 EXPECT_EQ(message->response_handle, nullptr);
301 return kSuccess;
302 }));
303
304 engine->SendPlatformMessage(channel, test_message.data(), test_message.size(),
305 nullptr, nullptr);
306 EXPECT_TRUE(called);
307}
308
309TEST_F(FlutterWindowsEngineTest, PlatformMessageRoundTrip) {
310 FlutterWindowsEngineBuilder builder{GetContext()};
311 builder.SetDartEntrypoint("hiPlatformChannels");
312
313 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
314 EngineModifier modifier(engine.get());
315 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
316
317 auto binary_messenger =
318 std::make_unique<BinaryMessengerImpl>(engine->messenger());
319
320 engine->Run();
321 bool did_call_callback = false;
322 bool did_call_reply = false;
323 bool did_call_dart_reply = false;
324 std::string channel = "hi";
325 binary_messenger->SetMessageHandler(
326 channel,
327 [&did_call_callback, &did_call_dart_reply](
328 const uint8_t* message, size_t message_size, BinaryReply reply) {
329 if (message_size == 5) {
330 EXPECT_EQ(message[0], static_cast<uint8_t>('h'));
331 char response[] = {'b', 'y', 'e'};
332 reply(reinterpret_cast<uint8_t*>(response), 3);
333 did_call_callback = true;
334 } else {
335 EXPECT_EQ(message_size, 3);
336 EXPECT_EQ(message[0], static_cast<uint8_t>('b'));
337 did_call_dart_reply = true;
338 }
339 });
340 char payload[] = {'h', 'e', 'l', 'l', 'o'};
341 binary_messenger->Send(
342 channel, reinterpret_cast<uint8_t*>(payload), 5,
343 [&did_call_reply](const uint8_t* reply, size_t reply_size) {
344 EXPECT_EQ(reply_size, 5);
345 EXPECT_EQ(reply[0], static_cast<uint8_t>('h'));
346 did_call_reply = true;
347 });
348 // Rely on timeout mechanism in CI.
349 while (!did_call_callback || !did_call_reply || !did_call_dart_reply) {
350 engine->task_runner()->ProcessTasks();
351 }
352}
353
354TEST_F(FlutterWindowsEngineTest, PlatformMessageRespondOnDifferentThread) {
355 FlutterWindowsEngineBuilder builder{GetContext()};
356 builder.SetDartEntrypoint("hiPlatformChannels");
357
358 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
359
360 EngineModifier modifier(engine.get());
361 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
362
363 auto binary_messenger =
364 std::make_unique<BinaryMessengerImpl>(engine->messenger());
365
366 engine->Run();
367 bool did_call_callback = false;
368 bool did_call_reply = false;
369 bool did_call_dart_reply = false;
370 std::string channel = "hi";
371 std::unique_ptr<std::thread> reply_thread;
372 binary_messenger->SetMessageHandler(
373 channel,
374 [&did_call_callback, &did_call_dart_reply, &reply_thread](
375 const uint8_t* message, size_t message_size, BinaryReply reply) {
376 if (message_size == 5) {
377 EXPECT_EQ(message[0], static_cast<uint8_t>('h'));
378 reply_thread.reset(new std::thread([reply = std::move(reply)]() {
379 char response[] = {'b', 'y', 'e'};
380 reply(reinterpret_cast<uint8_t*>(response), 3);
381 }));
382 did_call_callback = true;
383 } else {
384 EXPECT_EQ(message_size, 3);
385 EXPECT_EQ(message[0], static_cast<uint8_t>('b'));
386 did_call_dart_reply = true;
387 }
388 });
389 char payload[] = {'h', 'e', 'l', 'l', 'o'};
390 binary_messenger->Send(
391 channel, reinterpret_cast<uint8_t*>(payload), 5,
392 [&did_call_reply](const uint8_t* reply, size_t reply_size) {
393 EXPECT_EQ(reply_size, 5);
394 EXPECT_EQ(reply[0], static_cast<uint8_t>('h'));
395 did_call_reply = true;
396 });
397 // Rely on timeout mechanism in CI.
398 while (!did_call_callback || !did_call_reply || !did_call_dart_reply) {
399 engine->task_runner()->ProcessTasks();
400 }
401 ASSERT_TRUE(reply_thread);
402 reply_thread->join();
403}
404
405TEST_F(FlutterWindowsEngineTest, SendPlatformMessageWithResponse) {
406 FlutterWindowsEngineBuilder builder{GetContext()};
407 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
408 EngineModifier modifier(engine.get());
409
410 const char* channel = "test";
411 const std::vector<uint8_t> test_message = {1, 2, 3, 4};
412 auto* dummy_response_handle =
413 reinterpret_cast<FlutterPlatformMessageResponseHandle*>(5);
414 const FlutterDesktopBinaryReply reply_handler = [](auto... args) {};
415 void* reply_user_data = reinterpret_cast<void*>(6);
416
417 // When a response is requested, a handle should be created, passed as part
418 // of the message, and then released.
419 bool create_response_handle_called = false;
422 PlatformMessageCreateResponseHandle,
423 ([&create_response_handle_called, &reply_handler, reply_user_data,
424 dummy_response_handle](auto engine, auto reply, auto user_data,
425 auto response_handle) {
426 create_response_handle_called = true;
427 EXPECT_EQ(reply, reply_handler);
428 EXPECT_EQ(user_data, reply_user_data);
429 EXPECT_NE(response_handle, nullptr);
430 *response_handle = dummy_response_handle;
431 return kSuccess;
432 }));
433 bool release_response_handle_called = false;
436 PlatformMessageReleaseResponseHandle,
437 ([&release_response_handle_called, dummy_response_handle](
438 auto engine, auto response_handle) {
439 release_response_handle_called = true;
440 EXPECT_EQ(response_handle, dummy_response_handle);
441 return kSuccess;
442 }));
443 bool send_message_called = false;
445 SendPlatformMessage, ([&send_message_called, test_message,
446 dummy_response_handle](auto engine, auto message) {
447 send_message_called = true;
448 EXPECT_STREQ(message->channel, "test");
449 EXPECT_EQ(message->message_size, test_message.size());
450 EXPECT_EQ(memcmp(message->message, test_message.data(),
451 message->message_size),
452 0);
453 EXPECT_EQ(message->response_handle, dummy_response_handle);
454 return kSuccess;
455 }));
456
457 engine->SendPlatformMessage(channel, test_message.data(), test_message.size(),
458 reply_handler, reply_user_data);
459 EXPECT_TRUE(create_response_handle_called);
460 EXPECT_TRUE(release_response_handle_called);
461 EXPECT_TRUE(send_message_called);
462}
463
465 FlutterWindowsEngineBuilder builder{GetContext()};
466 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
467 EngineModifier modifier(engine.get());
468
469 bool called = false;
470 std::string message = "Hello";
473 ([&called, &message](auto engine, auto target, auto action, auto data,
474 auto data_length) {
475 called = true;
476 EXPECT_EQ(target, 42);
478 EXPECT_EQ(memcmp(data, message.c_str(), message.size()), 0);
479 EXPECT_EQ(data_length, message.size());
480 return kSuccess;
481 }));
482
483 auto data = fml::MallocMapping::Copy(message.c_str(), message.size());
484 engine->DispatchSemanticsAction(42, kFlutterSemanticsActionDismiss,
485 std::move(data));
486 EXPECT_TRUE(called);
487}
488
489TEST_F(FlutterWindowsEngineTest, SetsThreadPriority) {
491 EXPECT_EQ(GetThreadPriority(GetCurrentThread()),
492 THREAD_PRIORITY_BELOW_NORMAL);
493
495 EXPECT_EQ(GetThreadPriority(GetCurrentThread()),
496 THREAD_PRIORITY_ABOVE_NORMAL);
497
499 EXPECT_EQ(GetThreadPriority(GetCurrentThread()),
500 THREAD_PRIORITY_ABOVE_NORMAL);
501
502 // FlutterThreadPriority::kNormal does not change thread priority, reset to 0
503 // here.
504 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
505
507 EXPECT_EQ(GetThreadPriority(GetCurrentThread()), THREAD_PRIORITY_NORMAL);
508}
509
510TEST_F(FlutterWindowsEngineTest, AddPluginRegistrarDestructionCallback) {
511 FlutterWindowsEngineBuilder builder{GetContext()};
512 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
513 EngineModifier modifier(engine.get());
514
516 std::make_shared<MockKeyResponseController>());
517
518 engine->Run();
519
520 // Verify that destruction handlers don't overwrite each other.
521 int result1 = 0;
522 int result2 = 0;
523 engine->AddPluginRegistrarDestructionCallback(
525 auto result = reinterpret_cast<int*>(ref);
526 *result = 1;
527 },
528 reinterpret_cast<FlutterDesktopPluginRegistrarRef>(&result1));
529 engine->AddPluginRegistrarDestructionCallback(
531 auto result = reinterpret_cast<int*>(ref);
532 *result = 2;
533 },
534 reinterpret_cast<FlutterDesktopPluginRegistrarRef>(&result2));
535
536 engine->Stop();
537 EXPECT_EQ(result1, 1);
538 EXPECT_EQ(result2, 2);
539}
540
542 FlutterWindowsEngineBuilder builder{GetContext()};
543 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
544 EngineModifier modifier(engine.get());
545
546 bool called = false;
547 modifier.embedder_api().ScheduleFrame =
548 MOCK_ENGINE_PROC(ScheduleFrame, ([&called](auto engine) {
549 called = true;
550 return kSuccess;
551 }));
552
553 engine->ScheduleFrame();
554 EXPECT_TRUE(called);
555}
556
557TEST_F(FlutterWindowsEngineTest, SetNextFrameCallback) {
558 FlutterWindowsEngineBuilder builder{GetContext()};
559 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
560 EngineModifier modifier(engine.get());
561
562 bool called = false;
564 SetNextFrameCallback, ([&called](auto engine, auto callback, auto data) {
565 called = true;
566 return kSuccess;
567 }));
568
569 engine->SetNextFrameCallback([]() {});
570 EXPECT_TRUE(called);
571}
572
573TEST_F(FlutterWindowsEngineTest, GetExecutableName) {
574 FlutterWindowsEngineBuilder builder{GetContext()};
575 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
576 EXPECT_EQ(engine->GetExecutableName(), "flutter_windows_unittests.exe");
577}
578
579// Ensure that after setting or resetting the high contrast feature,
580// the corresponding status flag can be retrieved from the engine.
581TEST_F(FlutterWindowsEngineTest, UpdateHighContrastFeature) {
582 auto windows_proc_table = std::make_shared<MockWindowsProcTable>();
583 EXPECT_CALL(*windows_proc_table, GetHighContrastEnabled)
584 .WillOnce(Return(true))
585 .WillOnce(Return(false));
586
587 FlutterWindowsEngineBuilder builder{GetContext()};
588 builder.SetWindowsProcTable(windows_proc_table);
589 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
590 EngineModifier modifier(engine.get());
591
592 std::optional<FlutterAccessibilityFeature> engine_flags;
594 UpdateAccessibilityFeatures, ([&engine_flags](auto engine, auto flags) {
595 engine_flags = flags;
596 return kSuccess;
597 }));
599 SendPlatformMessage,
600 [](auto engine, const auto message) { return kSuccess; });
601
602 // 1: High contrast is enabled.
603 engine->UpdateHighContrastMode();
604
605 EXPECT_TRUE(engine->high_contrast_enabled());
606 EXPECT_TRUE(engine_flags.has_value());
608 engine_flags.value() &
610
611 // 2: High contrast is disabled.
612 engine_flags.reset();
613 engine->UpdateHighContrastMode();
614
615 EXPECT_FALSE(engine->high_contrast_enabled());
616 EXPECT_TRUE(engine_flags.has_value());
617 EXPECT_FALSE(
618 engine_flags.value() &
620}
621
622TEST_F(FlutterWindowsEngineTest, PostRasterThreadTask) {
623 FlutterWindowsEngineBuilder builder{GetContext()};
624 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
625 EngineModifier modifier(engine.get());
626
628 PostRenderThreadTask, ([](auto engine, auto callback, auto context) {
629 callback(context);
630 return kSuccess;
631 }));
632
633 bool called = false;
634 engine->PostRasterThreadTask([&called]() { called = true; });
635
636 EXPECT_TRUE(called);
637}
638
639class MockFlutterWindowsView : public FlutterWindowsView {
640 public:
642 std::unique_ptr<WindowBindingHandler> wbh)
645
647 NotifyWinEventWrapper,
648 (ui::AXPlatformNodeWin*, ax::mojom::Event),
649 (override));
650 MOCK_METHOD(HWND, GetWindowHandle, (), (const, override));
651
652 private:
653 FML_DISALLOW_COPY_AND_ASSIGN(MockFlutterWindowsView);
654};
655
656// Verify the view is notified of accessibility announcements.
657TEST_F(FlutterWindowsEngineTest, AccessibilityAnnouncement) {
658 auto& context = GetContext();
659 WindowsConfigBuilder builder{context};
660 builder.SetDartEntrypoint("sendAccessibilityAnnouncement");
661
662 bool done = false;
663 auto native_entry =
665 context.AddNativeFunction("Signal", native_entry);
666
667 EnginePtr engine{builder.RunHeadless()};
668 ASSERT_NE(engine, nullptr);
669
670 ui::AXPlatformNodeDelegateBase parent_delegate;
671 AlertPlatformNodeDelegate delegate{parent_delegate};
672
673 auto window_binding_handler =
674 std::make_unique<NiceMock<MockWindowBindingHandler>>();
675 EXPECT_CALL(*window_binding_handler, GetAlertDelegate)
676 .WillOnce(Return(&delegate));
677
678 auto windows_engine = reinterpret_cast<FlutterWindowsEngine*>(engine.get());
679 MockFlutterWindowsView view{windows_engine,
680 std::move(window_binding_handler)};
681 EngineModifier modifier{windows_engine};
682 modifier.SetImplicitView(&view);
683
684 windows_engine->UpdateSemanticsEnabled(true);
685
686 EXPECT_CALL(view, NotifyWinEventWrapper).Times(1);
687
688 // Rely on timeout mechanism in CI.
689 while (!done) {
690 windows_engine->task_runner()->ProcessTasks();
691 }
692}
693
694// Verify the app can send accessibility announcements while in headless mode.
695TEST_F(FlutterWindowsEngineTest, AccessibilityAnnouncementHeadless) {
696 auto& context = GetContext();
697 WindowsConfigBuilder builder{context};
698 builder.SetDartEntrypoint("sendAccessibilityAnnouncement");
699
700 bool done = false;
701 auto native_entry =
703 context.AddNativeFunction("Signal", native_entry);
704
705 EnginePtr engine{builder.RunHeadless()};
706 ASSERT_NE(engine, nullptr);
707
708 auto windows_engine = reinterpret_cast<FlutterWindowsEngine*>(engine.get());
709 windows_engine->UpdateSemanticsEnabled(true);
710
711 // Rely on timeout mechanism in CI.
712 while (!done) {
713 windows_engine->task_runner()->ProcessTasks();
714 }
715}
716
717// Verify the engine does not crash if it receives an accessibility event
718// it does not support yet.
719TEST_F(FlutterWindowsEngineTest, AccessibilityTooltip) {
720 fml::testing::LogCapture log_capture;
721
722 auto& context = GetContext();
723 WindowsConfigBuilder builder{context};
724 builder.SetDartEntrypoint("sendAccessibilityTooltipEvent");
725
726 bool done = false;
727 auto native_entry =
729 context.AddNativeFunction("Signal", native_entry);
730
731 ViewControllerPtr controller{builder.Run()};
732 ASSERT_NE(controller, nullptr);
733
734 auto engine = FlutterDesktopViewControllerGetEngine(controller.get());
735 auto windows_engine = reinterpret_cast<FlutterWindowsEngine*>(engine);
736 windows_engine->UpdateSemanticsEnabled(true);
737
738 // Rely on timeout mechanism in CI.
739 while (!done) {
740 windows_engine->task_runner()->ProcessTasks();
741 }
742
743 // Verify no error was logged.
744 // Regression test for:
745 // https://github.com/flutter/flutter/issues/144274
746 EXPECT_EQ(log_capture.str().find("tooltip"), std::string::npos);
747}
748
750 public:
754
756 void,
757 Quit,
758 (std::optional<HWND>, std::optional<WPARAM>, std::optional<LPARAM>, UINT),
759 (override));
760 MOCK_METHOD(void, DispatchMessage, (HWND, UINT, WPARAM, LPARAM), (override));
761 MOCK_METHOD(bool, IsLastWindowOfProcess, (), (override));
763
770
771 std::function<void()> begin_processing_callback = nullptr;
772};
773
775 FlutterWindowsEngineBuilder builder{GetContext()};
776 builder.SetDartEntrypoint("exitTestExit");
777 bool finished = false;
778
779 auto engine = builder.Build();
780 auto window_binding_handler =
781 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
782 MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler));
783
784 EngineModifier modifier(engine.get());
785 modifier.SetImplicitView(&view);
786 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
787 auto handler = std::make_unique<MockWindowsLifecycleManager>(engine.get());
788 EXPECT_CALL(*handler, SetLifecycleState(AppLifecycleState::kResumed));
789 EXPECT_CALL(*handler, Quit)
790 .WillOnce([&finished](std::optional<HWND> hwnd,
791 std::optional<WPARAM> wparam,
792 std::optional<LPARAM> lparam,
793 UINT exit_code) { finished = exit_code == 0; });
794 EXPECT_CALL(*handler, IsLastWindowOfProcess).WillRepeatedly(Return(true));
795 modifier.SetLifecycleManager(std::move(handler));
796
797 engine->lifecycle_manager()->BeginProcessingExit();
798
799 engine->Run();
800
801 engine->window_proc_delegate_manager()->OnTopLevelWindowProc(0, WM_CLOSE, 0,
802 0);
803
804 // The test will only succeed when this while loop exits. Otherwise it will
805 // timeout.
806 while (!finished) {
807 engine->task_runner()->ProcessTasks();
808 }
809}
810
812 FlutterWindowsEngineBuilder builder{GetContext()};
813 builder.SetDartEntrypoint("exitTestCancel");
814 bool did_call = false;
815
816 auto engine = builder.Build();
817 auto window_binding_handler =
818 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
819 MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler));
820
821 EngineModifier modifier(engine.get());
822 modifier.SetImplicitView(&view);
823 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
824 auto handler = std::make_unique<MockWindowsLifecycleManager>(engine.get());
825 EXPECT_CALL(*handler, SetLifecycleState(AppLifecycleState::kResumed));
826 EXPECT_CALL(*handler, IsLastWindowOfProcess).WillRepeatedly(Return(true));
827 EXPECT_CALL(*handler, Quit).Times(0);
828 modifier.SetLifecycleManager(std::move(handler));
829 engine->lifecycle_manager()->BeginProcessingExit();
830
831 auto binary_messenger =
832 std::make_unique<BinaryMessengerImpl>(engine->messenger());
833 binary_messenger->SetMessageHandler(
834 "flutter/platform", [&did_call](const uint8_t* message,
835 size_t message_size, BinaryReply reply) {
836 std::string contents(message, message + message_size);
837 EXPECT_NE(contents.find("\"method\":\"System.exitApplication\""),
838 std::string::npos);
839 EXPECT_NE(contents.find("\"type\":\"required\""), std::string::npos);
840 EXPECT_NE(contents.find("\"exitCode\":0"), std::string::npos);
841 did_call = true;
842 char response[] = "";
843 reply(reinterpret_cast<uint8_t*>(response), 0);
844 });
845
846 engine->Run();
847
848 engine->window_proc_delegate_manager()->OnTopLevelWindowProc(0, WM_CLOSE, 0,
849 0);
850
851 while (!did_call) {
852 engine->task_runner()->ProcessTasks();
853 }
854}
855
856// Flutter consumes the first WM_CLOSE message to allow the app to cancel the
857// exit. If the app does not cancel the exit, Flutter synthesizes a second
858// WM_CLOSE message.
859TEST_F(FlutterWindowsEngineTest, TestExitSecondCloseMessage) {
860 FlutterWindowsEngineBuilder builder{GetContext()};
861 builder.SetDartEntrypoint("exitTestExit");
862 bool second_close = false;
863
864 auto engine = builder.Build();
865 auto window_binding_handler =
866 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
867 MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler));
868
869 EngineModifier modifier(engine.get());
870 modifier.SetImplicitView(&view);
871 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
872 auto handler = std::make_unique<MockWindowsLifecycleManager>(engine.get());
873 EXPECT_CALL(*handler, SetLifecycleState(AppLifecycleState::kResumed));
874 EXPECT_CALL(*handler, IsLastWindowOfProcess).WillOnce(Return(true));
875 EXPECT_CALL(*handler, Quit)
876 .WillOnce([handler_ptr = handler.get()](
877 std::optional<HWND> hwnd, std::optional<WPARAM> wparam,
878 std::optional<LPARAM> lparam, UINT exit_code) {
879 handler_ptr->WindowsLifecycleManager::Quit(hwnd, wparam, lparam,
880 exit_code);
881 });
882 EXPECT_CALL(*handler, DispatchMessage)
883 .WillRepeatedly(
884 [&engine](HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
885 engine->window_proc_delegate_manager()->OnTopLevelWindowProc(
886 hwnd, msg, wparam, lparam);
887 });
888 modifier.SetLifecycleManager(std::move(handler));
889 engine->lifecycle_manager()->BeginProcessingExit();
890
891 engine->Run();
892
893 // This delegate will be registered after the lifecycle manager, so it will be
894 // called only when a message is not consumed by the lifecycle manager. This
895 // should be called on the second, synthesized WM_CLOSE message that the
896 // lifecycle manager posts.
897 engine->window_proc_delegate_manager()->RegisterTopLevelWindowProcDelegate(
898 [](HWND hwnd, UINT message, WPARAM wpar, LPARAM lpar, void* user_data,
899 LRESULT* result) {
900 switch (message) {
901 case WM_CLOSE: {
902 bool* called = reinterpret_cast<bool*>(user_data);
903 *called = true;
904 return true;
905 }
906 }
907 return false;
908 },
909 reinterpret_cast<void*>(&second_close));
910
911 engine->window_proc_delegate_manager()->OnTopLevelWindowProc(0, WM_CLOSE, 0,
912 0);
913
914 while (!second_close) {
915 engine->task_runner()->ProcessTasks();
916 }
917}
918
919TEST_F(FlutterWindowsEngineTest, TestExitCloseMultiWindow) {
920 FlutterWindowsEngineBuilder builder{GetContext()};
921 builder.SetDartEntrypoint("exitTestExit");
922 bool finished = false;
923
924 auto engine = builder.Build();
925 auto window_binding_handler =
926 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
927 MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler));
928
929 EngineModifier modifier(engine.get());
930 modifier.SetImplicitView(&view);
931 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
932 auto handler = std::make_unique<MockWindowsLifecycleManager>(engine.get());
933 EXPECT_CALL(*handler, SetLifecycleState(AppLifecycleState::kResumed));
934 EXPECT_CALL(*handler, IsLastWindowOfProcess).WillOnce([&finished]() {
935 finished = true;
936 return false;
937 });
938 // Quit should not be called when there is more than one window.
939 EXPECT_CALL(*handler, Quit).Times(0);
940 modifier.SetLifecycleManager(std::move(handler));
941 engine->lifecycle_manager()->BeginProcessingExit();
942
943 engine->Run();
944
945 engine->window_proc_delegate_manager()->OnTopLevelWindowProc(0, WM_CLOSE, 0,
946 0);
947
948 while (!finished) {
949 engine->task_runner()->ProcessTasks();
950 }
951}
952
953TEST_F(FlutterWindowsEngineTest, LifecycleManagerDisabledByDefault) {
954 FlutterWindowsEngineBuilder builder{GetContext()};
955
956 auto engine = builder.Build();
957 auto window_binding_handler =
958 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
959 MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler));
960
961 EngineModifier modifier(engine.get());
962 modifier.SetImplicitView(&view);
963 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
964 auto handler = std::make_unique<MockWindowsLifecycleManager>(engine.get());
965 EXPECT_CALL(*handler, IsLastWindowOfProcess).Times(0);
966 modifier.SetLifecycleManager(std::move(handler));
967
968 engine->window_proc_delegate_manager()->OnTopLevelWindowProc(0, WM_CLOSE, 0,
969 0);
970}
971
972TEST_F(FlutterWindowsEngineTest, EnableApplicationLifecycle) {
973 FlutterWindowsEngineBuilder builder{GetContext()};
974
975 auto engine = builder.Build();
976 auto window_binding_handler =
977 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
978 MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler));
979
980 EngineModifier modifier(engine.get());
981 modifier.SetImplicitView(&view);
982 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
983 auto handler = std::make_unique<MockWindowsLifecycleManager>(engine.get());
984 EXPECT_CALL(*handler, IsLastWindowOfProcess).WillOnce(Return(false));
985 modifier.SetLifecycleManager(std::move(handler));
986 engine->lifecycle_manager()->BeginProcessingExit();
987
988 engine->window_proc_delegate_manager()->OnTopLevelWindowProc(0, WM_CLOSE, 0,
989 0);
990}
991
992TEST_F(FlutterWindowsEngineTest, ApplicationLifecycleExternalWindow) {
993 FlutterWindowsEngineBuilder builder{GetContext()};
994
995 auto engine = builder.Build();
996 auto window_binding_handler =
997 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
998 MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler));
999
1000 EngineModifier modifier(engine.get());
1001 modifier.SetImplicitView(&view);
1002 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1003 auto handler = std::make_unique<MockWindowsLifecycleManager>(engine.get());
1004 EXPECT_CALL(*handler, IsLastWindowOfProcess).WillOnce(Return(false));
1005 modifier.SetLifecycleManager(std::move(handler));
1006 engine->lifecycle_manager()->BeginProcessingExit();
1007
1008 engine->lifecycle_manager()->ExternalWindowMessage(0, WM_CLOSE, 0, 0);
1009}
1010
1011TEST_F(FlutterWindowsEngineTest, AppStartsInResumedState) {
1012 FlutterWindowsEngineBuilder builder{GetContext()};
1013
1014 auto engine = builder.Build();
1015 auto window_binding_handler =
1016 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
1017 MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler));
1018
1019 EngineModifier modifier(engine.get());
1020 modifier.SetImplicitView(&view);
1021 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1022 auto handler = std::make_unique<MockWindowsLifecycleManager>(engine.get());
1023 EXPECT_CALL(*handler, SetLifecycleState(AppLifecycleState::kResumed))
1024 .Times(1);
1025 modifier.SetLifecycleManager(std::move(handler));
1026 engine->Run();
1027}
1028
1029TEST_F(FlutterWindowsEngineTest, LifecycleStateTransition) {
1030 FlutterWindowsEngineBuilder builder{GetContext()};
1031
1032 auto engine = builder.Build();
1033 auto window_binding_handler =
1034 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
1035 MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler));
1036
1037 EngineModifier modifier(engine.get());
1038 modifier.SetImplicitView(&view);
1039 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1040 engine->Run();
1041
1042 engine->window_proc_delegate_manager()->OnTopLevelWindowProc(
1043 (HWND)1, WM_SIZE, SIZE_RESTORED, 0);
1044 EXPECT_EQ(engine->lifecycle_manager()->GetLifecycleState(),
1046
1047 engine->window_proc_delegate_manager()->OnTopLevelWindowProc(
1048 (HWND)1, WM_SIZE, SIZE_MINIMIZED, 0);
1049 EXPECT_EQ(engine->lifecycle_manager()->GetLifecycleState(),
1051
1052 engine->window_proc_delegate_manager()->OnTopLevelWindowProc(
1053 (HWND)1, WM_SIZE, SIZE_RESTORED, 0);
1054 EXPECT_EQ(engine->lifecycle_manager()->GetLifecycleState(),
1056}
1057
1058TEST_F(FlutterWindowsEngineTest, ExternalWindowMessage) {
1059 FlutterWindowsEngineBuilder builder{GetContext()};
1060
1061 auto engine = builder.Build();
1062 auto window_binding_handler =
1063 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
1064 MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler));
1065
1066 EngineModifier modifier(engine.get());
1067 modifier.SetImplicitView(&view);
1068 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1069 // Sets lifecycle state to resumed.
1070 engine->Run();
1071
1072 // Ensure HWND(1) is in the set of visible windows before hiding it.
1073 engine->ProcessExternalWindowMessage(reinterpret_cast<HWND>(1), WM_SHOWWINDOW,
1074 TRUE, NULL);
1075 engine->ProcessExternalWindowMessage(reinterpret_cast<HWND>(1), WM_SHOWWINDOW,
1076 FALSE, NULL);
1077
1078 EXPECT_EQ(engine->lifecycle_manager()->GetLifecycleState(),
1080}
1081
1083 FlutterWindowsEngineBuilder builder{GetContext()};
1084 HWND outer = reinterpret_cast<HWND>(1);
1085 HWND inner = reinterpret_cast<HWND>(2);
1086
1087 auto engine = builder.Build();
1088 auto window_binding_handler =
1089 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
1090 MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler));
1091 ON_CALL(view, GetWindowHandle).WillByDefault([=]() { return inner; });
1092
1093 EngineModifier modifier(engine.get());
1094 modifier.SetImplicitView(&view);
1095 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1096 // Sets lifecycle state to resumed.
1097 engine->Run();
1098
1099 // Show both top-level and Flutter window.
1100 engine->window_proc_delegate_manager()->OnTopLevelWindowProc(
1101 outer, WM_SHOWWINDOW, TRUE, NULL);
1102 view.OnWindowStateEvent(inner, WindowStateEvent::kShow);
1103 view.OnWindowStateEvent(inner, WindowStateEvent::kFocus);
1104
1105 EXPECT_EQ(engine->lifecycle_manager()->GetLifecycleState(),
1107
1108 // Hide Flutter window, but not top level window.
1109 view.OnWindowStateEvent(inner, WindowStateEvent::kHide);
1110
1111 // The top-level window is still visible, so we ought not enter hidden state.
1112 EXPECT_EQ(engine->lifecycle_manager()->GetLifecycleState(),
1114}
1115
1116TEST_F(FlutterWindowsEngineTest, EnableLifecycleState) {
1117 FlutterWindowsEngineBuilder builder{GetContext()};
1118 builder.SetDartEntrypoint("enableLifecycleTest");
1119 bool finished = false;
1120
1121 auto engine = builder.Build();
1122 auto window_binding_handler =
1123 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
1124 MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler));
1125
1126 EngineModifier modifier(engine.get());
1127 modifier.SetImplicitView(&view);
1128 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1129 auto handler = std::make_unique<MockWindowsLifecycleManager>(engine.get());
1130 EXPECT_CALL(*handler, SetLifecycleState)
1131 .WillRepeatedly([handler_ptr = handler.get()](AppLifecycleState state) {
1132 handler_ptr->WindowsLifecycleManager::SetLifecycleState(state);
1133 });
1134 modifier.SetLifecycleManager(std::move(handler));
1135
1136 auto binary_messenger =
1137 std::make_unique<BinaryMessengerImpl>(engine->messenger());
1138 // Mark the test only as completed on receiving an inactive state message.
1139 binary_messenger->SetMessageHandler(
1140 "flutter/unittest", [&finished](const uint8_t* message,
1141 size_t message_size, BinaryReply reply) {
1142 std::string contents(message, message + message_size);
1143 EXPECT_NE(contents.find("AppLifecycleState.inactive"),
1144 std::string::npos);
1145 finished = true;
1146 char response[] = "";
1147 reply(reinterpret_cast<uint8_t*>(response), 0);
1148 });
1149
1150 engine->Run();
1151
1152 // Test that setting the state before enabling lifecycle does nothing.
1153 HWND hwnd = reinterpret_cast<HWND>(1);
1154 view.OnWindowStateEvent(hwnd, WindowStateEvent::kShow);
1155 view.OnWindowStateEvent(hwnd, WindowStateEvent::kHide);
1156 EXPECT_FALSE(finished);
1157
1158 // Test that we can set the state afterwards.
1159
1160 engine->lifecycle_manager()->BeginProcessingLifecycle();
1161 view.OnWindowStateEvent(hwnd, WindowStateEvent::kShow);
1162
1163 while (!finished) {
1164 engine->task_runner()->ProcessTasks();
1165 }
1166}
1167
1168TEST_F(FlutterWindowsEngineTest, LifecycleStateToFrom) {
1169 FlutterWindowsEngineBuilder builder{GetContext()};
1170 builder.SetDartEntrypoint("enableLifecycleToFrom");
1171 bool enabled_lifecycle = false;
1172 bool dart_responded = false;
1173
1174 auto engine = builder.Build();
1175 auto window_binding_handler =
1176 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
1177 MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler));
1178
1179 EngineModifier modifier(engine.get());
1180 modifier.SetImplicitView(&view);
1181 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1182 auto handler = std::make_unique<MockWindowsLifecycleManager>(engine.get());
1183 EXPECT_CALL(*handler, SetLifecycleState)
1184 .WillRepeatedly([handler_ptr = handler.get()](AppLifecycleState state) {
1185 handler_ptr->WindowsLifecycleManager::SetLifecycleState(state);
1186 });
1187 handler->begin_processing_callback = [&]() { enabled_lifecycle = true; };
1188 modifier.SetLifecycleManager(std::move(handler));
1189
1190 auto binary_messenger =
1191 std::make_unique<BinaryMessengerImpl>(engine->messenger());
1192 binary_messenger->SetMessageHandler(
1193 "flutter/unittest",
1194 [&](const uint8_t* message, size_t message_size, BinaryReply reply) {
1195 std::string contents(message, message + message_size);
1196 EXPECT_NE(contents.find("AppLifecycleState."), std::string::npos);
1197 dart_responded = true;
1198 char response[] = "";
1199 reply(reinterpret_cast<uint8_t*>(response), 0);
1200 });
1201
1202 engine->Run();
1203
1204 while (!enabled_lifecycle) {
1205 engine->task_runner()->ProcessTasks();
1206 }
1207
1208 HWND hwnd = reinterpret_cast<HWND>(1);
1209 view.OnWindowStateEvent(hwnd, WindowStateEvent::kShow);
1210 view.OnWindowStateEvent(hwnd, WindowStateEvent::kHide);
1211
1212 while (!dart_responded) {
1213 engine->task_runner()->ProcessTasks();
1214 }
1215}
1216
1218 FlutterWindowsEngineBuilder builder{GetContext()};
1219 builder.SetDartEntrypoint("enableLifecycleToFrom");
1220
1221 auto engine = builder.Build();
1222 auto window_binding_handler =
1223 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
1224 MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler));
1225
1226 EngineModifier modifier(engine.get());
1227 modifier.SetImplicitView(&view);
1228 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1229
1230 bool lifecycle_began = false;
1231 auto handler = std::make_unique<MockWindowsLifecycleManager>(engine.get());
1232 EXPECT_CALL(*handler, SetLifecycleState).Times(1);
1233 handler->begin_processing_callback = [&]() { lifecycle_began = true; };
1234 modifier.SetLifecycleManager(std::move(handler));
1235
1236 engine->Run();
1237
1238 while (!lifecycle_began) {
1239 engine->task_runner()->ProcessTasks();
1240 }
1241}
1242
1243TEST_F(FlutterWindowsEngineTest, ReceivePlatformViewMessage) {
1244 FlutterWindowsEngineBuilder builder{GetContext()};
1245 builder.SetDartEntrypoint("sendCreatePlatformViewMethod");
1246 auto engine = builder.Build();
1247
1248 EngineModifier modifier{engine.get()};
1249 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1250
1251 bool received_call = false;
1252
1253 auto manager = std::make_unique<MockPlatformViewManager>(engine.get());
1254 EXPECT_CALL(*manager, AddPlatformView)
1255 .WillOnce([&](PlatformViewId id, std::string_view type_name) {
1256 received_call = true;
1257 return true;
1258 });
1259 modifier.SetPlatformViewPlugin(std::move(manager));
1260
1261 engine->Run();
1262
1263 while (!received_call) {
1264 engine->task_runner()->ProcessTasks();
1265 }
1266}
1267
1268TEST_F(FlutterWindowsEngineTest, AddViewFailureDoesNotHang) {
1269 FlutterWindowsEngineBuilder builder{GetContext()};
1270 auto engine = builder.Build();
1271
1272 EngineModifier modifier{engine.get()};
1273
1274 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1275 modifier.embedder_api().AddView = MOCK_ENGINE_PROC(
1276 AddView,
1278 const FlutterAddViewInfo* info) { return kInternalInconsistency; });
1279
1280 ASSERT_TRUE(engine->Run());
1281
1282 // Create the first view. This is the implicit view and isn't added to the
1283 // engine.
1284 auto implicit_window = std::make_unique<NiceMock<MockWindowBindingHandler>>();
1285
1286 std::unique_ptr<FlutterWindowsView> implicit_view =
1287 engine->CreateView(std::move(implicit_window));
1288
1289 EXPECT_TRUE(implicit_view);
1290
1291 // Create a second view. The embedder attempts to add it to the engine.
1292 auto second_window = std::make_unique<NiceMock<MockWindowBindingHandler>>();
1293
1294 EXPECT_DEBUG_DEATH(engine->CreateView(std::move(second_window)),
1295 "FlutterEngineAddView returned an unexpected result");
1296}
1297
1298TEST_F(FlutterWindowsEngineTest, RemoveViewFailureDoesNotHang) {
1299 FlutterWindowsEngineBuilder builder{GetContext()};
1300 builder.SetDartEntrypoint("sendCreatePlatformViewMethod");
1301 auto engine = builder.Build();
1302
1303 EngineModifier modifier{engine.get()};
1304
1305 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1306 modifier.embedder_api().RemoveView = MOCK_ENGINE_PROC(
1307 RemoveView,
1310
1311 ASSERT_TRUE(engine->Run());
1312 EXPECT_DEBUG_DEATH(engine->RemoveView(123),
1313 "FlutterEngineRemoveView returned an unexpected result");
1314}
1315
1316} // namespace testing
1317} // namespace flutter
static void done(const char *config, const char *src, const char *srcOptions, const char *name)
Definition DM.cpp:263
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition DM.cpp:213
void SetLifecycleManager(std::unique_ptr< WindowsLifecycleManager > &&handler)
void SetFrameInterval(uint64_t frame_interval_nanos)
void SetEGLManager(std::unique_ptr< egl::Manager > egl_manager)
void SetStartTime(uint64_t start_time_nanos)
Reset the start_time field that is used to align vsync events.
FlutterEngineProcTable & embedder_api()
void SetImplicitView(FlutterWindowsView *view)
virtual void Quit(std::optional< HWND > window, std::optional< WPARAM > wparam, std::optional< LPARAM > lparam, UINT exit_code)
virtual void SetLifecycleState(AppLifecycleState state)
MOCK_METHOD(void, NotifyWinEventWrapper,(ui::AXPlatformNodeWin *, ax::mojom::Event),(override))
MockFlutterWindowsView(FlutterWindowsEngine *engine, std::unique_ptr< WindowBindingHandler > wbh)
MOCK_METHOD(HWND, GetWindowHandle,(),(const, override))
MOCK_METHOD(void, DispatchMessage,(HWND, UINT, WPARAM, LPARAM),(override))
MOCK_METHOD(void, Quit,(std::optional< HWND >, std::optional< WPARAM >, std::optional< LPARAM >, UINT),(override))
MOCK_METHOD(void, SetLifecycleState,(AppLifecycleState),(override))
MOCK_METHOD(bool, IsLastWindowOfProcess,(),(override))
static MallocMapping Copy(const T *begin, const T *end)
Definition mapping.h:162
struct _Dart_NativeArguments * Dart_NativeArguments
Definition dart_api.h:3010
#define FLUTTER_API_SYMBOL(symbol)
Definition embedder.h:67
@ kOpenGL
Definition embedder.h:80
FlutterAccessibilityFeature
Definition embedder.h:91
@ kFlutterAccessibilityFeatureHighContrast
Request that UI be rendered with darker colors.
Definition embedder.h:105
@ kInternalInconsistency
Definition embedder.h:76
FlutterEngineDisplaysUpdateType
Definition embedder.h:1998
@ kFlutterEngineDisplaysUpdateTypeStartup
Definition embedder.h:2004
@ kBackground
Suitable for threads that shouldn't disrupt high priority work.
Definition embedder.h:258
@ kDisplay
Suitable for threads which generate data for the display.
Definition embedder.h:262
@ kNormal
Default priority level.
Definition embedder.h:260
@ kRaster
Suitable for thread which raster data.
Definition embedder.h:264
@ kFlutterSemanticsActionDismiss
A request that the node should be dismissed.
Definition embedder.h:158
#define FLUTTER_ENGINE_VERSION
Definition embedder.h:70
FlutterEngine engine
Definition main.cc:68
AtkStateType state
FlutterSemanticsFlag flags
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
GAsyncResult * result
uint32_t * target
void(* FlutterDesktopBinaryReply)(const uint8_t *data, size_t data_size, void *user_data)
int64_t PlatformViewId
#define FML_DISALLOW_COPY_AND_ASSIGN(TypeName)
Definition macros.h:27
Win32Message message
return FALSE
TEST_F(DisplayListTest, Defaults)
std::unique_ptr< FlutterDesktopEngine, EngineDeleter > EnginePtr
std::unique_ptr< FlutterDesktopViewController, ViewControllerDeleter > ViewControllerPtr
void MockEmbedderApiForKeyboard(EngineModifier &modifier, std::shared_ptr< MockKeyResponseController > response_controller)
constexpr int64_t kImplicitViewId
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font manager
Definition switches.h:218
static void DispatchSemanticsAction(JNIEnv *env, jobject jcaller, jlong shell_holder, jint id, jint action, jobject args, jint args_position)
std::function< void(const uint8_t *reply, size_t reply_size)> BinaryReply
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot data
Definition switches.h:41
static void WindowsPlatformThreadPrioritySetter(FlutterThreadPriority priority)
static void ScheduleFrame(JNIEnv *env, jobject jcaller, jlong shell_holder)
Definition ref_ptr.h:256
#define MOCK_ENGINE_PROC(proc, mock_impl)
FlutterEngineDisplayId display_id
Definition embedder.h:1973
FlutterEngineScheduleFrameFnPtr ScheduleFrame
Definition embedder.h:3359
FlutterEnginePlatformMessageReleaseResponseHandleFnPtr PlatformMessageReleaseResponseHandle
Definition embedder.h:3335
FlutterEngineUpdateLocalesFnPtr UpdateLocales
Definition embedder.h:3352
FlutterEngineRunsAOTCompiledDartCodeFnPtr RunsAOTCompiledDartCode
Definition embedder.h:3353
FlutterEngineSetNextFrameCallbackFnPtr SetNextFrameCallback
Definition embedder.h:3360
FlutterEngineShutdownFnPtr Shutdown
Definition embedder.h:3324
FlutterEngineOnVsyncFnPtr OnVsync
Definition embedder.h:3344
FlutterEngineGetCurrentTimeFnPtr GetCurrentTime
Definition embedder.h:3350
FlutterEngineDispatchSemanticsActionFnPtr DispatchSemanticsAction
Definition embedder.h:3343
FlutterEngineNotifyDisplayUpdateFnPtr NotifyDisplayUpdate
Definition embedder.h:3358
FlutterEngineSendPlatformMessageFnPtr SendPlatformMessage
Definition embedder.h:3331
FlutterEnginePlatformMessageCreateResponseHandleFnPtr PlatformMessageCreateResponseHandle
Definition embedder.h:3333
FlutterEngineRunFnPtr Run
Definition embedder.h:3323
FlutterEngineUpdateAccessibilityFeaturesFnPtr UpdateAccessibilityFeatures
Definition embedder.h:3342
FlutterEnginePostRenderThreadTaskFnPtr PostRenderThreadTask
Definition embedder.h:3349
FlutterRendererType type
Definition embedder.h:825
std::string str() const
Definition logging.cc:122
FlutterDesktopEngineRef FlutterDesktopViewControllerGetEngine(FlutterDesktopViewControllerRef controller)
#define CREATE_NATIVE_ENTRY(native_entry)
#define EXPECT_TRUE(handle)
Definition unit_test.h:685
LONG_PTR LRESULT
unsigned int UINT
LONG_PTR LPARAM
#define GetCurrentTime()
UINT_PTR WPARAM
#define DispatchMessage