Flutter Engine
external_view_embedder_unittests.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "flutter/shell/platform/android/external_view_embedder/external_view_embedder.h"
6 
7 #include "flutter/flow/embedded_views.h"
8 #include "flutter/flow/surface.h"
9 #include "flutter/fml/raster_thread_merger.h"
10 #include "flutter/fml/thread.h"
11 #include "flutter/shell/platform/android/jni/jni_mock.h"
12 #include "flutter/shell/platform/android/surface/android_surface.h"
13 #include "flutter/shell/platform/android/surface/android_surface_mock.h"
14 #include "gmock/gmock.h"
15 #include "gtest/gtest.h"
16 #include "third_party/skia/include/gpu/GrDirectContext.h"
17 
18 namespace flutter {
19 namespace testing {
20 
21 using ::testing::ByMove;
22 using ::testing::Return;
23 
25  public:
26  using TestSurfaceProducer =
27  std::function<std::unique_ptr<AndroidSurface>(void)>;
28  explicit TestAndroidSurfaceFactory(TestSurfaceProducer&& surface_producer) {
29  surface_producer_ = surface_producer;
30  }
31 
32  ~TestAndroidSurfaceFactory() override = default;
33 
34  std::unique_ptr<AndroidSurface> CreateSurface() override {
35  return surface_producer_();
36  }
37 
38  private:
39  TestSurfaceProducer surface_producer_;
40 };
41 
42 class SurfaceMock : public Surface {
43  public:
44  MOCK_METHOD(bool, IsValid, (), (override));
45 
46  MOCK_METHOD(std::unique_ptr<SurfaceFrame>,
47  AcquireFrame,
48  (const SkISize& size),
49  (override));
50 
51  MOCK_METHOD(SkMatrix, GetRootTransformation, (), (const, override));
52 
53  MOCK_METHOD(GrDirectContext*, GetContext, (), (override));
54 
55  MOCK_METHOD(flutter::ExternalViewEmbedder*,
56  GetExternalViewEmbedder,
57  (),
58  (override));
59 
60  MOCK_METHOD(std::unique_ptr<GLContextResult>,
61  MakeRenderContextCurrent,
62  (),
63  (override));
64 };
65 
67  bool merged = false) {
68  // Assume the current thread is the platform thread.
70  auto platform_queue_id = fml::MessageLoop::GetCurrentTaskQueueId();
71 
72  if (merged) {
73  return fml::MakeRefCounted<fml::RasterThreadMerger>(platform_queue_id,
74  platform_queue_id);
75  }
76  auto rasterizer_thread = new fml::Thread("rasterizer");
77  auto rasterizer_queue_id =
78  rasterizer_thread->GetTaskRunner()->GetTaskQueueId();
79  return fml::MakeRefCounted<fml::RasterThreadMerger>(platform_queue_id,
80  rasterizer_queue_id);
81 }
82 
84  auto platform_thread = new fml::Thread("rasterizer");
85  auto platform_queue_id = platform_thread->GetTaskRunner()->GetTaskQueueId();
86 
87  // Assume the current thread is the raster thread.
89  auto rasterizer_queue_id = fml::MessageLoop::GetCurrentTaskQueueId();
90 
91  return fml::MakeRefCounted<fml::RasterThreadMerger>(platform_queue_id,
92  rasterizer_queue_id);
93 }
94 
95 TEST(AndroidExternalViewEmbedder, GetCurrentCanvases) {
96  auto jni_mock = std::make_shared<JNIMock>();
97 
98  auto embedder =
99  std::make_unique<AndroidExternalViewEmbedder>(nullptr, jni_mock, nullptr);
100  auto raster_thread_merger = GetThreadMergerFromPlatformThread();
101 
102  EXPECT_CALL(*jni_mock, FlutterViewBeginFrame());
103  embedder->BeginFrame(SkISize::Make(10, 20), nullptr, 1.0,
104  raster_thread_merger);
105 
106  embedder->PrerollCompositeEmbeddedView(
107  0, std::make_unique<EmbeddedViewParams>());
108  embedder->PrerollCompositeEmbeddedView(
109  1, std::make_unique<EmbeddedViewParams>());
110 
111  auto canvases = embedder->GetCurrentCanvases();
112  ASSERT_EQ(2UL, canvases.size());
113  ASSERT_EQ(SkISize::Make(10, 20), canvases[0]->getBaseLayerSize());
114  ASSERT_EQ(SkISize::Make(10, 20), canvases[1]->getBaseLayerSize());
115 }
116 
117 TEST(AndroidExternalViewEmbedder, GetCurrentCanvases__CompositeOrder) {
118  auto jni_mock = std::make_shared<JNIMock>();
119 
120  auto embedder =
121  std::make_unique<AndroidExternalViewEmbedder>(nullptr, jni_mock, nullptr);
122  auto raster_thread_merger = GetThreadMergerFromPlatformThread();
123 
124  EXPECT_CALL(*jni_mock, FlutterViewBeginFrame());
125  embedder->BeginFrame(SkISize::Make(10, 20), nullptr, 1.0,
126  raster_thread_merger);
127 
128  embedder->PrerollCompositeEmbeddedView(
129  0, std::make_unique<EmbeddedViewParams>());
130  embedder->PrerollCompositeEmbeddedView(
131  1, std::make_unique<EmbeddedViewParams>());
132 
133  auto canvases = embedder->GetCurrentCanvases();
134  ASSERT_EQ(2UL, canvases.size());
135  ASSERT_EQ(embedder->CompositeEmbeddedView(0), canvases[0]);
136  ASSERT_EQ(embedder->CompositeEmbeddedView(1), canvases[1]);
137 }
138 
139 TEST(AndroidExternalViewEmbedder, CompositeEmbeddedView) {
140  auto embedder =
141  std::make_unique<AndroidExternalViewEmbedder>(nullptr, nullptr, nullptr);
142 
143  ASSERT_EQ(nullptr, embedder->CompositeEmbeddedView(0));
144  embedder->PrerollCompositeEmbeddedView(
145  0, std::make_unique<EmbeddedViewParams>());
146  ASSERT_NE(nullptr, embedder->CompositeEmbeddedView(0));
147 
148  ASSERT_EQ(nullptr, embedder->CompositeEmbeddedView(1));
149  embedder->PrerollCompositeEmbeddedView(
150  1, std::make_unique<EmbeddedViewParams>());
151  ASSERT_NE(nullptr, embedder->CompositeEmbeddedView(1));
152 }
153 
155  auto embedder =
156  std::make_unique<AndroidExternalViewEmbedder>(nullptr, nullptr, nullptr);
157 
158  embedder->PrerollCompositeEmbeddedView(
159  0, std::make_unique<EmbeddedViewParams>());
160  embedder->CancelFrame();
161 
162  auto canvases = embedder->GetCurrentCanvases();
163  ASSERT_EQ(0UL, canvases.size());
164 }
165 
166 TEST(AndroidExternalViewEmbedder, RasterizerRunsOnPlatformThread) {
167  auto jni_mock = std::make_shared<JNIMock>();
168  auto embedder =
169  std::make_unique<AndroidExternalViewEmbedder>(nullptr, jni_mock, nullptr);
170 
171  auto raster_thread_merger = GetThreadMergerFromPlatformThread();
172  ASSERT_FALSE(raster_thread_merger->IsMerged());
173 
174  EXPECT_CALL(*jni_mock, FlutterViewBeginFrame());
175  embedder->BeginFrame(SkISize::Make(10, 20), nullptr, 1.0,
176  raster_thread_merger);
177  // Push a platform view.
178  embedder->PrerollCompositeEmbeddedView(
179  0, std::make_unique<EmbeddedViewParams>());
180 
181  auto postpreroll_result = embedder->PostPrerollAction(raster_thread_merger);
182  ASSERT_EQ(PostPrerollResult::kSkipAndRetryFrame, postpreroll_result);
183 
184  EXPECT_CALL(*jni_mock, FlutterViewEndFrame());
185  embedder->EndFrame(/*should_resubmit_frame=*/true, raster_thread_merger);
186 
187  ASSERT_TRUE(raster_thread_merger->IsMerged());
188 
189  int pending_frames = 0;
190  while (raster_thread_merger->IsMerged()) {
191  raster_thread_merger->DecrementLease();
192  pending_frames++;
193  }
194  ASSERT_EQ(10, pending_frames); // kDefaultMergedLeaseDuration
195 }
196 
197 TEST(AndroidExternalViewEmbedder, RasterizerRunsOnRasterizerThread) {
198  auto jni_mock = std::make_shared<JNIMock>();
199  auto embedder =
200  std::make_unique<AndroidExternalViewEmbedder>(nullptr, jni_mock, nullptr);
201 
202  auto raster_thread_merger = GetThreadMergerFromPlatformThread();
203  ASSERT_FALSE(raster_thread_merger->IsMerged());
204 
205  PostPrerollResult result = embedder->PostPrerollAction(raster_thread_merger);
206  ASSERT_EQ(PostPrerollResult::kSuccess, result);
207 
208  EXPECT_CALL(*jni_mock, FlutterViewEndFrame());
209  embedder->EndFrame(/*should_resubmit_frame=*/true, raster_thread_merger);
210 
211  ASSERT_FALSE(raster_thread_merger->IsMerged());
212 }
213 
214 TEST(AndroidExternalViewEmbedder, PlatformViewRect) {
215  auto jni_mock = std::make_shared<JNIMock>();
216 
217  auto embedder =
218  std::make_unique<AndroidExternalViewEmbedder>(nullptr, jni_mock, nullptr);
219  auto raster_thread_merger = GetThreadMergerFromPlatformThread();
220 
221  EXPECT_CALL(*jni_mock, FlutterViewBeginFrame());
222  embedder->BeginFrame(SkISize::Make(100, 100), nullptr, 1.5,
223  raster_thread_merger);
224 
225  MutatorsStack stack;
226  SkMatrix matrix;
227  matrix.setIdentity();
228  // The framework always push a scale matrix based on the screen ratio.
229  matrix.setConcat(matrix, SkMatrix::MakeScale(1.5, 1.5));
230  matrix.setConcat(matrix, SkMatrix::MakeTrans(10, 20));
231  auto view_params =
232  std::make_unique<EmbeddedViewParams>(matrix, SkSize::Make(30, 40), stack);
233 
234  auto view_id = 0;
235  embedder->PrerollCompositeEmbeddedView(view_id, std::move(view_params));
236  ASSERT_EQ(SkRect::MakeXYWH(15, 30, 45, 60), embedder->GetViewRect(view_id));
237 }
238 
239 TEST(AndroidExternalViewEmbedder, PlatformViewRect__ChangedParams) {
240  auto jni_mock = std::make_shared<JNIMock>();
241 
242  auto embedder =
243  std::make_unique<AndroidExternalViewEmbedder>(nullptr, jni_mock, nullptr);
244  auto raster_thread_merger = GetThreadMergerFromPlatformThread();
245 
246  EXPECT_CALL(*jni_mock, FlutterViewBeginFrame());
247  embedder->BeginFrame(SkISize::Make(100, 100), nullptr, 1.5,
248  raster_thread_merger);
249 
250  auto view_id = 0;
251 
252  MutatorsStack stack1;
253  SkMatrix matrix1;
254  matrix1.setIdentity();
255  // The framework always push a scale matrix based on the screen ratio.
256  matrix1.setConcat(SkMatrix::MakeScale(1.5, 1.5), SkMatrix::MakeTrans(10, 20));
257  auto view_params_1 = std::make_unique<EmbeddedViewParams>(
258  matrix1, SkSize::Make(30, 40), stack1);
259 
260  embedder->PrerollCompositeEmbeddedView(view_id, std::move(view_params_1));
261 
262  MutatorsStack stack2;
263  SkMatrix matrix2;
264  matrix2.setIdentity();
265  // The framework always push a scale matrix based on the screen ratio.
266  matrix2.setConcat(matrix2, SkMatrix::MakeScale(1.5, 1.5));
267  matrix2.setConcat(matrix2, SkMatrix::MakeTrans(50, 60));
268  auto view_params_2 = std::make_unique<EmbeddedViewParams>(
269  matrix2, SkSize::Make(70, 80), stack2);
270 
271  embedder->PrerollCompositeEmbeddedView(view_id, std::move(view_params_2));
272 
273  ASSERT_EQ(SkRect::MakeXYWH(75, 90, 105, 120), embedder->GetViewRect(view_id));
274 }
275 
277  auto jni_mock = std::make_shared<JNIMock>();
278  auto android_context =
279  std::make_shared<AndroidContext>(AndroidRenderingAPI::kSoftware);
280 
281  auto window = fml::MakeRefCounted<AndroidNativeWindow>(nullptr);
282  auto gr_context = GrDirectContext::MakeMock(nullptr);
283  auto frame_size = SkISize::Make(1000, 1000);
284  auto surface_factory = std::make_shared<TestAndroidSurfaceFactory>(
285  [gr_context, window, frame_size]() {
286  auto surface_frame_1 = std::make_unique<SurfaceFrame>(
287  SkSurface::MakeNull(1000, 1000), false,
288  [](const SurfaceFrame& surface_frame, SkCanvas* canvas) {
289  return true;
290  });
291  auto surface_frame_2 = std::make_unique<SurfaceFrame>(
292  SkSurface::MakeNull(1000, 1000), false,
293  [](const SurfaceFrame& surface_frame, SkCanvas* canvas) {
294  return true;
295  });
296 
297  auto surface_mock = std::make_unique<SurfaceMock>();
298  EXPECT_CALL(*surface_mock, AcquireFrame(frame_size))
299  .Times(2 /* frames */)
300  .WillOnce(Return(ByMove(std::move(surface_frame_1))))
301  .WillOnce(Return(ByMove(std::move(surface_frame_2))));
302 
303  auto android_surface_mock = std::make_unique<AndroidSurfaceMock>();
304  EXPECT_CALL(*android_surface_mock, IsValid()).WillOnce(Return(true));
305 
306  EXPECT_CALL(*android_surface_mock, CreateGPUSurface(gr_context.get()))
307  .WillOnce(Return(ByMove(std::move(surface_mock))));
308 
309  EXPECT_CALL(*android_surface_mock, SetNativeWindow(window));
310 
311  return android_surface_mock;
312  });
313  auto embedder = std::make_unique<AndroidExternalViewEmbedder>(
314  android_context, jni_mock, surface_factory);
315 
316  auto raster_thread_merger =
317  GetThreadMergerFromPlatformThread(/*merged=*/true);
318 
319  // ------------------ First frame ------------------ //
320  {
321  auto did_submit_frame = false;
322  auto surface_frame = std::make_unique<SurfaceFrame>(
323  SkSurface::MakeNull(1000, 1000), false,
324  [&did_submit_frame](const SurfaceFrame& surface_frame,
325  SkCanvas* canvas) mutable {
326  if (canvas != nullptr) {
327  did_submit_frame = true;
328  }
329  return true;
330  });
331 
332  embedder->SubmitFrame(gr_context.get(), std::move(surface_frame));
333  // Submits frame if no Android view in the current frame.
334  EXPECT_TRUE(did_submit_frame);
335  // Doesn't resubmit frame.
336  auto postpreroll_result = embedder->PostPrerollAction(raster_thread_merger);
337  ASSERT_EQ(PostPrerollResult::kSuccess, postpreroll_result);
338 
339  EXPECT_CALL(*jni_mock, FlutterViewEndFrame());
340  embedder->EndFrame(/*should_resubmit_frame=*/false, raster_thread_merger);
341  }
342 
343  // ------------------ Second frame ------------------ //
344  {
345  EXPECT_CALL(*jni_mock, FlutterViewBeginFrame());
346  embedder->BeginFrame(frame_size, nullptr, 1.5, raster_thread_merger);
347 
348  // Add an Android view.
349  MutatorsStack stack1;
350  SkMatrix matrix1;
351  matrix1.setIdentity();
352  SkMatrix scale = SkMatrix::MakeScale(1.5, 1.5);
353  SkMatrix trans = SkMatrix::MakeTrans(100, 100);
354  matrix1.setConcat(scale, trans);
355  stack1.PushTransform(scale);
356  stack1.PushTransform(trans);
357  // TODO(egarciad): Investigate why Flow applies the device pixel ratio to
358  // the offsetPixels, but not the sizePoints.
359  auto view_params_1 = std::make_unique<EmbeddedViewParams>(
360  matrix1, SkSize::Make(200, 200), stack1);
361 
362  embedder->PrerollCompositeEmbeddedView(0, std::move(view_params_1));
363  // This is the recording canvas flow writes to.
364  auto canvas_1 = embedder->CompositeEmbeddedView(0);
365 
366  auto rect_paint = SkPaint();
367  rect_paint.setColor(SkColors::kCyan);
368  rect_paint.setStyle(SkPaint::Style::kFill_Style);
369 
370  // This simulates Flutter UI that doesn't intersect with the Android view.
371  canvas_1->drawRect(SkRect::MakeXYWH(0, 0, 50, 50), rect_paint);
372  // This simulates Flutter UI that intersects with the Android view.
373  canvas_1->drawRect(SkRect::MakeXYWH(50, 50, 200, 200), rect_paint);
374  canvas_1->drawRect(SkRect::MakeXYWH(150, 150, 100, 100), rect_paint);
375 
376  // Create a new overlay surface.
377  EXPECT_CALL(*jni_mock, FlutterViewCreateOverlaySurface())
378  .WillOnce(Return(
379  ByMove(std::make_unique<PlatformViewAndroidJNI::OverlayMetadata>(
380  0, window))));
381  // The JNI call to display the Android view.
382  EXPECT_CALL(*jni_mock, FlutterViewOnDisplayPlatformView(
383  0, 150, 150, 300, 300, 300, 300, stack1));
384  // The JNI call to display the overlay surface.
385  EXPECT_CALL(*jni_mock,
386  FlutterViewDisplayOverlaySurface(0, 50, 50, 200, 200));
387 
388  auto did_submit_frame = false;
389  auto surface_frame = std::make_unique<SurfaceFrame>(
390  SkSurface::MakeNull(1000, 1000), false,
391  [&did_submit_frame](const SurfaceFrame& surface_frame,
392  SkCanvas* canvas) mutable {
393  if (canvas != nullptr) {
394  did_submit_frame = true;
395  }
396  return true;
397  });
398 
399  embedder->SubmitFrame(gr_context.get(), std::move(surface_frame));
400  // Doesn't submit frame if there aren't Android views in the previous frame.
401  EXPECT_FALSE(did_submit_frame);
402  // Resubmits frame.
403  auto postpreroll_result = embedder->PostPrerollAction(raster_thread_merger);
404  ASSERT_EQ(PostPrerollResult::kResubmitFrame, postpreroll_result);
405 
406  EXPECT_CALL(*jni_mock, FlutterViewEndFrame());
407  embedder->EndFrame(/*should_resubmit_frame=*/false, raster_thread_merger);
408  }
409 
410  // ------------------ Third frame ------------------ //
411  {
412  EXPECT_CALL(*jni_mock, FlutterViewBeginFrame());
413  embedder->BeginFrame(frame_size, nullptr, 1.5, raster_thread_merger);
414 
415  // Add an Android view.
416  MutatorsStack stack1;
417  SkMatrix matrix1;
418  matrix1.setIdentity();
419  SkMatrix scale = SkMatrix::MakeScale(1.5, 1.5);
420  SkMatrix trans = SkMatrix::MakeTrans(100, 100);
421  matrix1.setConcat(scale, trans);
422  stack1.PushTransform(scale);
423  stack1.PushTransform(trans);
424  // TODO(egarciad): Investigate why Flow applies the device pixel ratio to
425  // the offsetPixels, but not the sizePoints.
426  auto view_params_1 = std::make_unique<EmbeddedViewParams>(
427  matrix1, SkSize::Make(200, 200), stack1);
428 
429  embedder->PrerollCompositeEmbeddedView(0, std::move(view_params_1));
430  // This is the recording canvas flow writes to.
431  auto canvas_1 = embedder->CompositeEmbeddedView(0);
432 
433  auto rect_paint = SkPaint();
434  rect_paint.setColor(SkColors::kCyan);
435  rect_paint.setStyle(SkPaint::Style::kFill_Style);
436 
437  // This simulates Flutter UI that doesn't intersect with the Android view.
438  canvas_1->drawRect(SkRect::MakeXYWH(0, 0, 50, 50), rect_paint);
439  // This simulates Flutter UI that intersects with the Android view.
440  canvas_1->drawRect(SkRect::MakeXYWH(50, 50, 200, 200), rect_paint);
441  canvas_1->drawRect(SkRect::MakeXYWH(150, 150, 100, 100), rect_paint);
442 
443  // Don't create a new overlay surface since it's recycled from the first
444  // frame.
445  EXPECT_CALL(*jni_mock, FlutterViewCreateOverlaySurface()).Times(0);
446  // The JNI call to display the Android view.
447  EXPECT_CALL(*jni_mock, FlutterViewOnDisplayPlatformView(
448  0, 150, 150, 300, 300, 300, 300, stack1));
449  // The JNI call to display the overlay surface.
450  EXPECT_CALL(*jni_mock,
451  FlutterViewDisplayOverlaySurface(0, 50, 50, 200, 200));
452 
453  auto did_submit_frame = false;
454  auto surface_frame = std::make_unique<SurfaceFrame>(
455  SkSurface::MakeNull(1000, 1000), false,
456  [&did_submit_frame](const SurfaceFrame& surface_frame,
457  SkCanvas* canvas) mutable {
458  if (canvas != nullptr) {
459  did_submit_frame = true;
460  }
461  return true;
462  });
463  embedder->SubmitFrame(gr_context.get(), std::move(surface_frame));
464  // Submits frame if there are Android views in the previous frame.
465  EXPECT_TRUE(did_submit_frame);
466  // Doesn't resubmit frame.
467  auto postpreroll_result = embedder->PostPrerollAction(raster_thread_merger);
468  ASSERT_EQ(PostPrerollResult::kSuccess, postpreroll_result);
469 
470  EXPECT_CALL(*jni_mock, FlutterViewEndFrame());
471  embedder->EndFrame(/*should_resubmit_frame=*/false, raster_thread_merger);
472  }
473 }
474 
475 TEST(AndroidExternalViewEmbedder, DoesNotCallJNIPlatformThreadOnlyMethods) {
476  auto jni_mock = std::make_shared<JNIMock>();
477 
478  auto embedder =
479  std::make_unique<AndroidExternalViewEmbedder>(nullptr, jni_mock, nullptr);
480 
481  // While on the raster thread, don't make JNI calls as these methods can only
482  // run on the platform thread.
483  auto raster_thread_merger = GetThreadMergerFromRasterThread();
484 
485  EXPECT_CALL(*jni_mock, FlutterViewBeginFrame()).Times(0);
486  embedder->BeginFrame(SkISize::Make(10, 20), nullptr, 1.0,
487  raster_thread_merger);
488 
489  EXPECT_CALL(*jni_mock, FlutterViewEndFrame()).Times(0);
490  embedder->EndFrame(/*should_resubmit_frame=*/false, raster_thread_merger);
491 }
492 
493 TEST(AndroidExternalViewEmbedder, DestroyOverlayLayersOnSizeChange) {
494  auto jni_mock = std::make_shared<JNIMock>();
495  auto android_context =
496  std::make_shared<AndroidContext>(AndroidRenderingAPI::kSoftware);
497 
498  auto window = fml::MakeRefCounted<AndroidNativeWindow>(nullptr);
499  auto gr_context = GrDirectContext::MakeMock(nullptr);
500  auto frame_size = SkISize::Make(1000, 1000);
501  auto surface_factory = std::make_shared<TestAndroidSurfaceFactory>(
502  [gr_context, window, frame_size]() {
503  auto surface_frame_1 = std::make_unique<SurfaceFrame>(
504  SkSurface::MakeNull(1000, 1000), false,
505  [](const SurfaceFrame& surface_frame, SkCanvas* canvas) {
506  return true;
507  });
508 
509  auto surface_mock = std::make_unique<SurfaceMock>();
510  EXPECT_CALL(*surface_mock, AcquireFrame(frame_size))
511  .WillOnce(Return(ByMove(std::move(surface_frame_1))));
512 
513  auto android_surface_mock = std::make_unique<AndroidSurfaceMock>();
514  EXPECT_CALL(*android_surface_mock, IsValid()).WillOnce(Return(true));
515 
516  EXPECT_CALL(*android_surface_mock, CreateGPUSurface(gr_context.get()))
517  .WillOnce(Return(ByMove(std::move(surface_mock))));
518 
519  EXPECT_CALL(*android_surface_mock, SetNativeWindow(window));
520 
521  return android_surface_mock;
522  });
523 
524  auto embedder = std::make_unique<AndroidExternalViewEmbedder>(
525  android_context, jni_mock, surface_factory);
526  auto raster_thread_merger = GetThreadMergerFromPlatformThread();
527 
528  // ------------------ First frame ------------------ //
529  {
530  EXPECT_CALL(*jni_mock, FlutterViewBeginFrame());
531  embedder->BeginFrame(frame_size, nullptr, 1.5, raster_thread_merger);
532 
533  // Add an Android view.
534  MutatorsStack stack1;
535  // TODO(egarciad): Investigate why Flow applies the device pixel ratio to
536  // the offsetPixels, but not the sizePoints.
537  auto view_params_1 = std::make_unique<EmbeddedViewParams>(
538  SkMatrix(), SkSize::Make(200, 200), stack1);
539 
540  embedder->PrerollCompositeEmbeddedView(0, std::move(view_params_1));
541 
542  // This simulates Flutter UI that intersects with the Android view.
543  embedder->CompositeEmbeddedView(0)->drawRect(
544  SkRect::MakeXYWH(50, 50, 200, 200), SkPaint());
545 
546  // Create a new overlay surface.
547  EXPECT_CALL(*jni_mock, FlutterViewCreateOverlaySurface())
548  .WillOnce(Return(
549  ByMove(std::make_unique<PlatformViewAndroidJNI::OverlayMetadata>(
550  0, window))));
551  // The JNI call to display the Android view.
552  EXPECT_CALL(*jni_mock, FlutterViewOnDisplayPlatformView(0, 0, 0, 200, 200,
553  300, 300, stack1));
554  EXPECT_CALL(*jni_mock,
555  FlutterViewDisplayOverlaySurface(0, 50, 50, 200, 200));
556 
557  auto surface_frame =
558  std::make_unique<SurfaceFrame>(SkSurface::MakeNull(1000, 1000), false,
559  [](const SurfaceFrame& surface_frame,
560  SkCanvas* canvas) { return true; });
561  embedder->SubmitFrame(gr_context.get(), std::move(surface_frame));
562 
563  EXPECT_CALL(*jni_mock, FlutterViewEndFrame());
564  embedder->EndFrame(/*should_resubmit_frame=*/false, raster_thread_merger);
565  }
566 
567  EXPECT_CALL(*jni_mock, FlutterViewDestroyOverlaySurfaces());
568  EXPECT_CALL(*jni_mock, FlutterViewBeginFrame());
569  // Change the frame size.
570  embedder->BeginFrame(SkISize::Make(30, 40), nullptr, 1.0,
571  raster_thread_merger);
572 }
573 
574 TEST(AndroidExternalViewEmbedder, DoesNotDestroyOverlayLayersOnSizeChange) {
575  auto jni_mock = std::make_shared<JNIMock>();
576  auto android_context =
577  std::make_shared<AndroidContext>(AndroidRenderingAPI::kSoftware);
578 
579  auto window = fml::MakeRefCounted<AndroidNativeWindow>(nullptr);
580  auto gr_context = GrDirectContext::MakeMock(nullptr);
581  auto frame_size = SkISize::Make(1000, 1000);
582  auto surface_factory = std::make_shared<TestAndroidSurfaceFactory>(
583  [gr_context, window, frame_size]() {
584  auto surface_frame_1 = std::make_unique<SurfaceFrame>(
585  SkSurface::MakeNull(1000, 1000), false,
586  [](const SurfaceFrame& surface_frame, SkCanvas* canvas) {
587  return true;
588  });
589 
590  auto surface_mock = std::make_unique<SurfaceMock>();
591  EXPECT_CALL(*surface_mock, AcquireFrame(frame_size))
592  .WillOnce(Return(ByMove(std::move(surface_frame_1))));
593 
594  auto android_surface_mock = std::make_unique<AndroidSurfaceMock>();
595  EXPECT_CALL(*android_surface_mock, IsValid()).WillOnce(Return(true));
596 
597  EXPECT_CALL(*android_surface_mock, CreateGPUSurface(gr_context.get()))
598  .WillOnce(Return(ByMove(std::move(surface_mock))));
599 
600  EXPECT_CALL(*android_surface_mock, SetNativeWindow(window));
601 
602  return android_surface_mock;
603  });
604 
605  auto embedder = std::make_unique<AndroidExternalViewEmbedder>(
606  android_context, jni_mock, surface_factory);
607 
608  // ------------------ First frame ------------------ //
609  {
610  auto raster_thread_merger = GetThreadMergerFromPlatformThread();
611  EXPECT_CALL(*jni_mock, FlutterViewBeginFrame());
612  embedder->BeginFrame(frame_size, nullptr, 1.5, raster_thread_merger);
613 
614  // Add an Android view.
615  MutatorsStack stack1;
616  // TODO(egarciad): Investigate why Flow applies the device pixel ratio to
617  // the offsetPixels, but not the sizePoints.
618  auto view_params_1 = std::make_unique<EmbeddedViewParams>(
619  SkMatrix(), SkSize::Make(200, 200), stack1);
620 
621  embedder->PrerollCompositeEmbeddedView(0, std::move(view_params_1));
622 
623  // This simulates Flutter UI that intersects with the Android view.
624  embedder->CompositeEmbeddedView(0)->drawRect(
625  SkRect::MakeXYWH(50, 50, 200, 200), SkPaint());
626 
627  // Create a new overlay surface.
628  EXPECT_CALL(*jni_mock, FlutterViewCreateOverlaySurface())
629  .WillOnce(Return(
630  ByMove(std::make_unique<PlatformViewAndroidJNI::OverlayMetadata>(
631  0, window))));
632  // The JNI call to display the Android view.
633  EXPECT_CALL(*jni_mock, FlutterViewOnDisplayPlatformView(0, 0, 0, 200, 200,
634  300, 300, stack1));
635  EXPECT_CALL(*jni_mock,
636  FlutterViewDisplayOverlaySurface(0, 50, 50, 200, 200));
637 
638  auto surface_frame =
639  std::make_unique<SurfaceFrame>(SkSurface::MakeNull(1000, 1000), false,
640  [](const SurfaceFrame& surface_frame,
641  SkCanvas* canvas) { return true; });
642  embedder->SubmitFrame(gr_context.get(), std::move(surface_frame));
643 
644  EXPECT_CALL(*jni_mock, FlutterViewEndFrame());
645  embedder->EndFrame(/*should_resubmit_frame=*/false, raster_thread_merger);
646  }
647 
648  // Changing the frame size from the raster thread does not make JNI calls.
649 
650  EXPECT_CALL(*jni_mock, FlutterViewDestroyOverlaySurfaces()).Times(0);
651  EXPECT_CALL(*jni_mock, FlutterViewBeginFrame()).Times(0);
652 
653  embedder->BeginFrame(SkISize::Make(30, 40), nullptr, 1.0,
655 }
656 
657 TEST(AndroidExternalViewEmbedder, SupportsDynamicThreadMerging) {
658  auto jni_mock = std::make_shared<JNIMock>();
659 
660  auto embedder =
661  std::make_unique<AndroidExternalViewEmbedder>(nullptr, jni_mock, nullptr);
662  ASSERT_TRUE(embedder->SupportsDynamicThreadMerging());
663 }
664 
665 TEST(AndroidExternalViewEmbedder, DisableThreadMerger) {
666  auto jni_mock = std::make_shared<JNIMock>();
667  auto embedder =
668  std::make_unique<AndroidExternalViewEmbedder>(nullptr, jni_mock, nullptr);
669 
670  auto raster_thread_merger = GetThreadMergerFromRasterThread();
671  ASSERT_FALSE(raster_thread_merger->IsMerged());
672 
673  // The shell may disable the thread merger during `OnPlatformViewDestroyed`.
674  raster_thread_merger->Disable();
675 
676  EXPECT_CALL(*jni_mock, FlutterViewBeginFrame()).Times(0);
677 
678  embedder->BeginFrame(SkISize::Make(10, 20), nullptr, 1.0,
679  raster_thread_merger);
680  // Push a platform view.
681  embedder->PrerollCompositeEmbeddedView(
682  0, std::make_unique<EmbeddedViewParams>());
683 
684  auto postpreroll_result = embedder->PostPrerollAction(raster_thread_merger);
685  ASSERT_EQ(PostPrerollResult::kSkipAndRetryFrame, postpreroll_result);
686 
687  EXPECT_CALL(*jni_mock, FlutterViewEndFrame()).Times(0);
688  embedder->EndFrame(/*should_resubmit_frame=*/true, raster_thread_merger);
689 
690  ASSERT_FALSE(raster_thread_merger->IsMerged());
691 }
692 
693 } // namespace testing
694 } // namespace flutter
fml::RefPtr< fml::RasterThreadMerger > GetThreadMergerFromPlatformThread(bool merged=false)
fml::RefPtr< fml::RasterThreadMerger > GetThreadMergerFromRasterThread()
std::unique_ptr< AndroidSurface > CreateSurface() override
void PushTransform(const SkMatrix &matrix)
static void EnsureInitializedForCurrentThread()
Definition: message_loop.cc:27
constexpr std::size_t size(T(&array)[N])
Definition: size.h:13
TestAndroidSurfaceFactory(TestSurfaceProducer &&surface_producer)
static TaskQueueId GetCurrentTaskQueueId()
Definition: message_loop.cc:76
std::function< std::unique_ptr< AndroidSurface >(void)> TestSurfaceProducer
Abstract Base Class that represents where we will be rendering content.
Definition: surface.h:18
TEST(EmbeddedViewParams, GetBoundingRectAfterMutationsWithNoMutations)