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