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