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 <memory>
6 #include "flutter/shell/platform/android/external_view_embedder/external_view_embedder.h"
7 
8 #include "flutter/flow/embedded_views.h"
9 #include "flutter/flow/surface.h"
10 #include "flutter/fml/raster_thread_merger.h"
11 #include "flutter/fml/thread.h"
12 #include "flutter/shell/platform/android/jni/jni_mock.h"
13 #include "flutter/shell/platform/android/surface/android_surface.h"
14 #include "flutter/shell/platform/android/surface/android_surface_mock.h"
15 #include "gmock/gmock.h"
16 #include "gtest/gtest.h"
17 #include "third_party/skia/include/gpu/GrDirectContext.h"
18 
19 namespace flutter {
20 namespace testing {
21 
22 using ::testing::ByMove;
23 using ::testing::Return;
24 
26  public:
27  using TestSurfaceProducer =
28  std::function<std::unique_ptr<AndroidSurface>(void)>;
29  explicit TestAndroidSurfaceFactory(TestSurfaceProducer&& surface_producer) {
30  surface_producer_ = surface_producer;
31  }
32 
33  ~TestAndroidSurfaceFactory() override = default;
34 
35  std::unique_ptr<AndroidSurface> CreateSurface() override {
36  return surface_producer_();
37  }
38 
39  private:
40  TestSurfaceProducer surface_producer_;
41 };
42 
43 class SurfaceMock : public Surface {
44  public:
45  MOCK_METHOD(bool, IsValid, (), (override));
46 
47  MOCK_METHOD(std::unique_ptr<SurfaceFrame>,
48  AcquireFrame,
49  (const SkISize& size),
50  (override));
51 
52  MOCK_METHOD(SkMatrix, GetRootTransformation, (), (const, override));
53 
54  MOCK_METHOD(GrDirectContext*, GetContext, (), (override));
55 
56  MOCK_METHOD(std::unique_ptr<GLContextResult>,
57  MakeRenderContextCurrent,
58  (),
59  (override));
60 };
61 
63  fml::Thread* rasterizer_thread = nullptr) {
64  // Assume the current thread is the platform thread.
66  auto platform_queue_id = fml::MessageLoop::GetCurrentTaskQueueId();
67 
68  if (!rasterizer_thread) {
69  return fml::MakeRefCounted<fml::RasterThreadMerger>(platform_queue_id,
70  platform_queue_id);
71  }
72  auto rasterizer_queue_id =
73  rasterizer_thread->GetTaskRunner()->GetTaskQueueId();
74  return fml::MakeRefCounted<fml::RasterThreadMerger>(platform_queue_id,
75  rasterizer_queue_id);
76 }
77 
79  fml::Thread* platform_thread) {
80  auto platform_queue_id = platform_thread->GetTaskRunner()->GetTaskQueueId();
81 
82  // Assume the current thread is the raster thread.
84  auto rasterizer_queue_id = fml::MessageLoop::GetCurrentTaskQueueId();
85 
86  return fml::MakeRefCounted<fml::RasterThreadMerger>(platform_queue_id,
87  rasterizer_queue_id);
88 }
89 
90 TEST(AndroidExternalViewEmbedder, GetCurrentCanvases) {
91  auto jni_mock = std::make_shared<JNIMock>();
92 
93  auto android_context = AndroidContext(AndroidRenderingAPI::kSoftware);
94  auto embedder = std::make_unique<AndroidExternalViewEmbedder>(
95  android_context, jni_mock, nullptr);
96  fml::Thread rasterizer_thread("rasterizer");
97  auto raster_thread_merger =
98  GetThreadMergerFromPlatformThread(&rasterizer_thread);
99 
100  EXPECT_CALL(*jni_mock, FlutterViewBeginFrame());
101  embedder->BeginFrame(SkISize::Make(10, 20), nullptr, 1.0,
102  raster_thread_merger);
103 
104  embedder->PrerollCompositeEmbeddedView(
105  0, std::make_unique<EmbeddedViewParams>());
106  embedder->PrerollCompositeEmbeddedView(
107  1, std::make_unique<EmbeddedViewParams>());
108 
109  auto canvases = embedder->GetCurrentCanvases();
110  ASSERT_EQ(2UL, canvases.size());
111  ASSERT_EQ(SkISize::Make(10, 20), canvases[0]->getBaseLayerSize());
112  ASSERT_EQ(SkISize::Make(10, 20), canvases[1]->getBaseLayerSize());
113 }
114 
115 TEST(AndroidExternalViewEmbedder, GetCurrentCanvases__CompositeOrder) {
116  auto jni_mock = std::make_shared<JNIMock>();
117 
118  auto android_context = AndroidContext(AndroidRenderingAPI::kSoftware);
119  auto embedder = std::make_unique<AndroidExternalViewEmbedder>(
120  android_context, jni_mock, nullptr);
121  fml::Thread rasterizer_thread("rasterizer");
122  auto raster_thread_merger =
123  GetThreadMergerFromPlatformThread(&rasterizer_thread);
124 
125  EXPECT_CALL(*jni_mock, FlutterViewBeginFrame());
126  embedder->BeginFrame(SkISize::Make(10, 20), nullptr, 1.0,
127  raster_thread_merger);
128 
129  embedder->PrerollCompositeEmbeddedView(
130  0, std::make_unique<EmbeddedViewParams>());
131  embedder->PrerollCompositeEmbeddedView(
132  1, std::make_unique<EmbeddedViewParams>());
133 
134  auto canvases = embedder->GetCurrentCanvases();
135  ASSERT_EQ(2UL, canvases.size());
136  ASSERT_EQ(embedder->CompositeEmbeddedView(0), canvases[0]);
137  ASSERT_EQ(embedder->CompositeEmbeddedView(1), canvases[1]);
138 }
139 
140 TEST(AndroidExternalViewEmbedder, CompositeEmbeddedView) {
141  auto android_context = AndroidContext(AndroidRenderingAPI::kSoftware);
142  auto embedder = std::make_unique<AndroidExternalViewEmbedder>(
143  android_context, nullptr, nullptr);
144 
145  ASSERT_EQ(nullptr, embedder->CompositeEmbeddedView(0));
146  embedder->PrerollCompositeEmbeddedView(
147  0, std::make_unique<EmbeddedViewParams>());
148  ASSERT_NE(nullptr, embedder->CompositeEmbeddedView(0));
149 
150  ASSERT_EQ(nullptr, embedder->CompositeEmbeddedView(1));
151  embedder->PrerollCompositeEmbeddedView(
152  1, std::make_unique<EmbeddedViewParams>());
153  ASSERT_NE(nullptr, embedder->CompositeEmbeddedView(1));
154 }
155 
157  auto android_context = AndroidContext(AndroidRenderingAPI::kSoftware);
158  auto embedder = std::make_unique<AndroidExternalViewEmbedder>(
159  android_context, nullptr, nullptr);
160 
161  embedder->PrerollCompositeEmbeddedView(
162  0, std::make_unique<EmbeddedViewParams>());
163  embedder->CancelFrame();
164 
165  auto canvases = embedder->GetCurrentCanvases();
166  ASSERT_EQ(0UL, canvases.size());
167 }
168 
169 TEST(AndroidExternalViewEmbedder, RasterizerRunsOnPlatformThread) {
170  auto jni_mock = std::make_shared<JNIMock>();
171  auto android_context = AndroidContext(AndroidRenderingAPI::kSoftware);
172  auto embedder = std::make_unique<AndroidExternalViewEmbedder>(
173  android_context, jni_mock, nullptr);
174 
175  fml::Thread rasterizer_thread("rasterizer");
176  auto raster_thread_merger =
177  GetThreadMergerFromPlatformThread(&rasterizer_thread);
178  ASSERT_FALSE(raster_thread_merger->IsMerged());
179 
180  EXPECT_CALL(*jni_mock, FlutterViewBeginFrame());
181  embedder->BeginFrame(SkISize::Make(10, 20), nullptr, 1.0,
182  raster_thread_merger);
183  // Push a platform view.
184  embedder->PrerollCompositeEmbeddedView(
185  0, std::make_unique<EmbeddedViewParams>());
186 
187  auto postpreroll_result = embedder->PostPrerollAction(raster_thread_merger);
188  ASSERT_EQ(PostPrerollResult::kSkipAndRetryFrame, postpreroll_result);
189 
190  EXPECT_CALL(*jni_mock, FlutterViewEndFrame());
191  embedder->EndFrame(/*should_resubmit_frame=*/true, raster_thread_merger);
192 
193  ASSERT_TRUE(raster_thread_merger->IsMerged());
194 
195  int pending_frames = 0;
196  while (raster_thread_merger->IsMerged()) {
197  raster_thread_merger->DecrementLease();
198  pending_frames++;
199  }
200  ASSERT_EQ(10, pending_frames); // kDefaultMergedLeaseDuration
201 }
202 
203 TEST(AndroidExternalViewEmbedder, RasterizerRunsOnRasterizerThread) {
204  auto jni_mock = std::make_shared<JNIMock>();
205  auto android_context = AndroidContext(AndroidRenderingAPI::kSoftware);
206  auto embedder = std::make_unique<AndroidExternalViewEmbedder>(
207  android_context, jni_mock, nullptr);
208 
209  fml::Thread rasterizer_thread("rasterizer");
210  auto raster_thread_merger =
211  GetThreadMergerFromPlatformThread(&rasterizer_thread);
212  ASSERT_FALSE(raster_thread_merger->IsMerged());
213 
214  PostPrerollResult result = embedder->PostPrerollAction(raster_thread_merger);
215  ASSERT_EQ(PostPrerollResult::kSuccess, result);
216 
217  EXPECT_CALL(*jni_mock, FlutterViewEndFrame());
218  embedder->EndFrame(/*should_resubmit_frame=*/true, raster_thread_merger);
219 
220  ASSERT_FALSE(raster_thread_merger->IsMerged());
221 }
222 
223 TEST(AndroidExternalViewEmbedder, PlatformViewRect) {
224  auto jni_mock = std::make_shared<JNIMock>();
225 
226  auto android_context = AndroidContext(AndroidRenderingAPI::kSoftware);
227  auto embedder = std::make_unique<AndroidExternalViewEmbedder>(
228  android_context, jni_mock, nullptr);
229  fml::Thread rasterizer_thread("rasterizer");
230  auto raster_thread_merger =
231  GetThreadMergerFromPlatformThread(&rasterizer_thread);
232 
233  EXPECT_CALL(*jni_mock, FlutterViewBeginFrame());
234  embedder->BeginFrame(SkISize::Make(100, 100), nullptr, 1.5,
235  raster_thread_merger);
236 
237  MutatorsStack stack;
238  SkMatrix matrix;
239  matrix.setIdentity();
240  // The framework always push a scale matrix based on the screen ratio.
241  matrix.setConcat(matrix, SkMatrix::Scale(1.5, 1.5));
242  matrix.setConcat(matrix, SkMatrix::Translate(10, 20));
243  auto view_params =
244  std::make_unique<EmbeddedViewParams>(matrix, SkSize::Make(30, 40), stack);
245 
246  auto view_id = 0;
247  embedder->PrerollCompositeEmbeddedView(view_id, std::move(view_params));
248  ASSERT_EQ(SkRect::MakeXYWH(15, 30, 45, 60), embedder->GetViewRect(view_id));
249 }
250 
251 TEST(AndroidExternalViewEmbedder, PlatformViewRect__ChangedParams) {
252  auto jni_mock = std::make_shared<JNIMock>();
253 
254  auto android_context = AndroidContext(AndroidRenderingAPI::kSoftware);
255  auto embedder = std::make_unique<AndroidExternalViewEmbedder>(
256  android_context, jni_mock, nullptr);
257  fml::Thread rasterizer_thread("rasterizer");
258  auto raster_thread_merger =
259  GetThreadMergerFromPlatformThread(&rasterizer_thread);
260 
261  EXPECT_CALL(*jni_mock, FlutterViewBeginFrame());
262  embedder->BeginFrame(SkISize::Make(100, 100), nullptr, 1.5,
263  raster_thread_merger);
264 
265  auto view_id = 0;
266 
267  MutatorsStack stack1;
268  SkMatrix matrix1;
269  matrix1.setIdentity();
270  // The framework always push a scale matrix based on the screen ratio.
271  matrix1.setConcat(SkMatrix::Scale(1.5, 1.5), SkMatrix::Translate(10, 20));
272  auto view_params_1 = std::make_unique<EmbeddedViewParams>(
273  matrix1, SkSize::Make(30, 40), stack1);
274 
275  embedder->PrerollCompositeEmbeddedView(view_id, std::move(view_params_1));
276 
277  MutatorsStack stack2;
278  SkMatrix matrix2;
279  matrix2.setIdentity();
280  // The framework always push a scale matrix based on the screen ratio.
281  matrix2.setConcat(matrix2, SkMatrix::Scale(1.5, 1.5));
282  matrix2.setConcat(matrix2, SkMatrix::Translate(50, 60));
283  auto view_params_2 = std::make_unique<EmbeddedViewParams>(
284  matrix2, SkSize::Make(70, 80), stack2);
285 
286  embedder->PrerollCompositeEmbeddedView(view_id, std::move(view_params_2));
287 
288  ASSERT_EQ(SkRect::MakeXYWH(75, 90, 105, 120), embedder->GetViewRect(view_id));
289 }
290 
292  auto jni_mock = std::make_shared<JNIMock>();
293  auto android_context =
294  std::make_shared<AndroidContext>(AndroidRenderingAPI::kSoftware);
295 
296  auto window = fml::MakeRefCounted<AndroidNativeWindow>(nullptr);
297  auto gr_context = GrDirectContext::MakeMock(nullptr);
298  auto frame_size = SkISize::Make(1000, 1000);
299  auto surface_factory = std::make_shared<TestAndroidSurfaceFactory>(
300  [&android_context, gr_context, window, frame_size]() {
301  auto surface_frame_1 = std::make_unique<SurfaceFrame>(
302  SkSurface::MakeNull(1000, 1000), false,
303  [](const SurfaceFrame& surface_frame, SkCanvas* canvas) {
304  return true;
305  });
306  auto surface_frame_2 = std::make_unique<SurfaceFrame>(
307  SkSurface::MakeNull(1000, 1000), false,
308  [](const SurfaceFrame& surface_frame, SkCanvas* canvas) {
309  return true;
310  });
311 
312  auto surface_mock = std::make_unique<SurfaceMock>();
313  EXPECT_CALL(*surface_mock, AcquireFrame(frame_size))
314  .Times(2 /* frames */)
315  .WillOnce(Return(ByMove(std::move(surface_frame_1))))
316  .WillOnce(Return(ByMove(std::move(surface_frame_2))));
317 
318  auto android_surface_mock =
319  std::make_unique<AndroidSurfaceMock>(android_context);
320  EXPECT_CALL(*android_surface_mock, IsValid()).WillOnce(Return(true));
321 
322  EXPECT_CALL(*android_surface_mock, CreateGPUSurface(gr_context.get()))
323  .WillOnce(Return(ByMove(std::move(surface_mock))));
324 
325  EXPECT_CALL(*android_surface_mock, SetNativeWindow(window));
326 
327  return android_surface_mock;
328  });
329  auto embedder = std::make_unique<AndroidExternalViewEmbedder>(
330  *android_context, jni_mock, surface_factory);
331 
332  auto raster_thread_merger = GetThreadMergerFromPlatformThread();
333 
334  // ------------------ First frame ------------------ //
335  {
336  auto did_submit_frame = false;
337  auto surface_frame = std::make_unique<SurfaceFrame>(
338  SkSurface::MakeNull(1000, 1000), false,
339  [&did_submit_frame](const SurfaceFrame& surface_frame,
340  SkCanvas* canvas) mutable {
341  if (canvas != nullptr) {
342  did_submit_frame = true;
343  }
344  return true;
345  });
346 
347  embedder->SubmitFrame(gr_context.get(), std::move(surface_frame));
348  // Submits frame if no Android view in the current frame.
349  EXPECT_TRUE(did_submit_frame);
350  // Doesn't resubmit frame.
351  auto postpreroll_result = embedder->PostPrerollAction(raster_thread_merger);
352  ASSERT_EQ(PostPrerollResult::kSuccess, postpreroll_result);
353 
354  EXPECT_CALL(*jni_mock, FlutterViewEndFrame());
355  embedder->EndFrame(/*should_resubmit_frame=*/false, raster_thread_merger);
356  }
357 
358  // ------------------ Second frame ------------------ //
359  {
360  EXPECT_CALL(*jni_mock, FlutterViewBeginFrame());
361  embedder->BeginFrame(frame_size, nullptr, 1.5, raster_thread_merger);
362 
363  // Add an Android view.
364  MutatorsStack stack1;
365  SkMatrix matrix1;
366  matrix1.setIdentity();
367  SkMatrix scale = SkMatrix::Scale(1.5, 1.5);
368  SkMatrix trans = SkMatrix::Translate(100, 100);
369  matrix1.setConcat(scale, trans);
370  stack1.PushTransform(scale);
371  stack1.PushTransform(trans);
372  // TODO(egarciad): Investigate why Flow applies the device pixel ratio to
373  // the offsetPixels, but not the sizePoints.
374  auto view_params_1 = std::make_unique<EmbeddedViewParams>(
375  matrix1, SkSize::Make(200, 200), stack1);
376 
377  embedder->PrerollCompositeEmbeddedView(0, std::move(view_params_1));
378  // This is the recording canvas flow writes to.
379  auto canvas_1 = embedder->CompositeEmbeddedView(0);
380 
381  auto rect_paint = SkPaint();
382  rect_paint.setColor(SkColors::kCyan);
383  rect_paint.setStyle(SkPaint::Style::kFill_Style);
384 
385  // This simulates Flutter UI that doesn't intersect with the Android view.
386  canvas_1->drawRect(SkRect::MakeXYWH(0, 0, 50, 50), rect_paint);
387  // This simulates Flutter UI that intersects with the Android view.
388  canvas_1->drawRect(SkRect::MakeXYWH(50, 50, 200, 200), rect_paint);
389  canvas_1->drawRect(SkRect::MakeXYWH(150, 150, 100, 100), rect_paint);
390 
391  // Create a new overlay surface.
392  EXPECT_CALL(*jni_mock, FlutterViewCreateOverlaySurface())
393  .WillOnce(Return(
394  ByMove(std::make_unique<PlatformViewAndroidJNI::OverlayMetadata>(
395  0, window))));
396  // The JNI call to display the Android view.
397  EXPECT_CALL(*jni_mock, FlutterViewOnDisplayPlatformView(
398  0, 150, 150, 300, 300, 300, 300, stack1));
399  // The JNI call to display the overlay surface.
400  EXPECT_CALL(*jni_mock,
401  FlutterViewDisplayOverlaySurface(0, 50, 50, 200, 200));
402 
403  auto did_submit_frame = false;
404  auto surface_frame = std::make_unique<SurfaceFrame>(
405  SkSurface::MakeNull(1000, 1000), false,
406  [&did_submit_frame](const SurfaceFrame& surface_frame,
407  SkCanvas* canvas) mutable {
408  if (canvas != nullptr) {
409  did_submit_frame = true;
410  }
411  return true;
412  });
413 
414  embedder->SubmitFrame(gr_context.get(), std::move(surface_frame));
415  // Doesn't submit frame if there aren't Android views in the previous frame.
416  EXPECT_FALSE(did_submit_frame);
417  // Resubmits frame.
418  auto postpreroll_result = embedder->PostPrerollAction(raster_thread_merger);
419  ASSERT_EQ(PostPrerollResult::kResubmitFrame, postpreroll_result);
420 
421  EXPECT_CALL(*jni_mock, FlutterViewEndFrame());
422  embedder->EndFrame(/*should_resubmit_frame=*/false, raster_thread_merger);
423  }
424 
425  // ------------------ Third frame ------------------ //
426  {
427  EXPECT_CALL(*jni_mock, FlutterViewBeginFrame());
428  embedder->BeginFrame(frame_size, nullptr, 1.5, raster_thread_merger);
429 
430  // Add an Android view.
431  MutatorsStack stack1;
432  SkMatrix matrix1;
433  matrix1.setIdentity();
434  SkMatrix scale = SkMatrix::Scale(1.5, 1.5);
435  SkMatrix trans = SkMatrix::Translate(100, 100);
436  matrix1.setConcat(scale, trans);
437  stack1.PushTransform(scale);
438  stack1.PushTransform(trans);
439  // TODO(egarciad): Investigate why Flow applies the device pixel ratio to
440  // the offsetPixels, but not the sizePoints.
441  auto view_params_1 = std::make_unique<EmbeddedViewParams>(
442  matrix1, SkSize::Make(200, 200), stack1);
443 
444  embedder->PrerollCompositeEmbeddedView(0, std::move(view_params_1));
445  // This is the recording canvas flow writes to.
446  auto canvas_1 = embedder->CompositeEmbeddedView(0);
447 
448  auto rect_paint = SkPaint();
449  rect_paint.setColor(SkColors::kCyan);
450  rect_paint.setStyle(SkPaint::Style::kFill_Style);
451 
452  // This simulates Flutter UI that doesn't intersect with the Android view.
453  canvas_1->drawRect(SkRect::MakeXYWH(0, 0, 50, 50), rect_paint);
454  // This simulates Flutter UI that intersects with the Android view.
455  canvas_1->drawRect(SkRect::MakeXYWH(50, 50, 200, 200), rect_paint);
456  canvas_1->drawRect(SkRect::MakeXYWH(150, 150, 100, 100), rect_paint);
457 
458  // Don't create a new overlay surface since it's recycled from the first
459  // frame.
460  EXPECT_CALL(*jni_mock, FlutterViewCreateOverlaySurface()).Times(0);
461  // The JNI call to display the Android view.
462  EXPECT_CALL(*jni_mock, FlutterViewOnDisplayPlatformView(
463  0, 150, 150, 300, 300, 300, 300, stack1));
464  // The JNI call to display the overlay surface.
465  EXPECT_CALL(*jni_mock,
466  FlutterViewDisplayOverlaySurface(0, 50, 50, 200, 200));
467 
468  auto did_submit_frame = false;
469  auto surface_frame = std::make_unique<SurfaceFrame>(
470  SkSurface::MakeNull(1000, 1000), false,
471  [&did_submit_frame](const SurfaceFrame& surface_frame,
472  SkCanvas* canvas) mutable {
473  if (canvas != nullptr) {
474  did_submit_frame = true;
475  }
476  return true;
477  });
478  embedder->SubmitFrame(gr_context.get(), std::move(surface_frame));
479  // Submits frame if there are Android views in the previous frame.
480  EXPECT_TRUE(did_submit_frame);
481  // Doesn't resubmit frame.
482  auto postpreroll_result = embedder->PostPrerollAction(raster_thread_merger);
483  ASSERT_EQ(PostPrerollResult::kSuccess, postpreroll_result);
484 
485  EXPECT_CALL(*jni_mock, FlutterViewEndFrame());
486  embedder->EndFrame(/*should_resubmit_frame=*/false, raster_thread_merger);
487  }
488 }
489 
490 TEST(AndroidExternalViewEmbedder, SubmitFrame__overlayComposition) {
491  auto jni_mock = std::make_shared<JNIMock>();
492  auto android_context =
493  std::make_shared<AndroidContext>(AndroidRenderingAPI::kSoftware);
494 
495  auto window = fml::MakeRefCounted<AndroidNativeWindow>(nullptr);
496  auto gr_context = GrDirectContext::MakeMock(nullptr);
497  auto frame_size = SkISize::Make(1000, 1000);
498  auto surface_factory = std::make_shared<TestAndroidSurfaceFactory>(
499  [&android_context, gr_context, window, frame_size]() {
500  auto surface_frame_1 = std::make_unique<SurfaceFrame>(
501  SkSurface::MakeNull(1000, 1000), false,
502  [](const SurfaceFrame& surface_frame, SkCanvas* canvas) {
503  return true;
504  });
505 
506  auto surface_mock = std::make_unique<SurfaceMock>();
507  EXPECT_CALL(*surface_mock, AcquireFrame(frame_size))
508  .Times(1 /* frames */)
509  .WillOnce(Return(ByMove(std::move(surface_frame_1))));
510 
511  auto android_surface_mock =
512  std::make_unique<AndroidSurfaceMock>(android_context);
513  EXPECT_CALL(*android_surface_mock, IsValid()).WillOnce(Return(true));
514 
515  EXPECT_CALL(*android_surface_mock, CreateGPUSurface(gr_context.get()))
516  .WillOnce(Return(ByMove(std::move(surface_mock))));
517 
518  EXPECT_CALL(*android_surface_mock, SetNativeWindow(window));
519  return android_surface_mock;
520  });
521  auto embedder = std::make_unique<AndroidExternalViewEmbedder>(
522  *android_context, jni_mock, surface_factory);
523 
524  auto raster_thread_merger = GetThreadMergerFromPlatformThread();
525 
526  EXPECT_CALL(*jni_mock, FlutterViewBeginFrame());
527  embedder->BeginFrame(frame_size, nullptr, 1.5, raster_thread_merger);
528 
529  {
530  // Add first Android view.
531  SkMatrix matrix;
532  MutatorsStack stack;
533  stack.PushTransform(SkMatrix::Translate(0, 0));
534 
535  embedder->PrerollCompositeEmbeddedView(
536  0, std::make_unique<EmbeddedViewParams>(matrix, SkSize::Make(200, 200),
537  stack));
538  EXPECT_CALL(*jni_mock, FlutterViewOnDisplayPlatformView(0, 0, 0, 200, 200,
539  300, 300, stack));
540  }
541 
542  auto rect_paint = SkPaint();
543  rect_paint.setColor(SkColors::kCyan);
544  rect_paint.setStyle(SkPaint::Style::kFill_Style);
545 
546  // This simulates Flutter UI that intersects with the first Android view.
547  embedder->CompositeEmbeddedView(0)->drawRect(
548  SkRect::MakeXYWH(25, 25, 80, 150), rect_paint);
549 
550  {
551  // Add second Android view.
552  SkMatrix matrix;
553  MutatorsStack stack;
554  stack.PushTransform(SkMatrix::Translate(0, 100));
555 
556  embedder->PrerollCompositeEmbeddedView(
557  1, std::make_unique<EmbeddedViewParams>(matrix, SkSize::Make(100, 100),
558  stack));
559  EXPECT_CALL(*jni_mock, FlutterViewOnDisplayPlatformView(1, 0, 0, 100, 100,
560  150, 150, stack));
561  }
562  // This simulates Flutter UI that intersects with the first and second Android
563  // views.
564  embedder->CompositeEmbeddedView(1)->drawRect(SkRect::MakeXYWH(25, 25, 80, 50),
565  rect_paint);
566 
567  embedder->CompositeEmbeddedView(1)->drawRect(
568  SkRect::MakeXYWH(75, 75, 30, 100), rect_paint);
569 
570  EXPECT_CALL(*jni_mock, FlutterViewCreateOverlaySurface())
571  .WillRepeatedly([&]() {
572  return std::make_unique<PlatformViewAndroidJNI::OverlayMetadata>(
573  1, window);
574  });
575 
576  EXPECT_CALL(*jni_mock, FlutterViewDisplayOverlaySurface(1, 25, 25, 80, 150))
577  .Times(2);
578 
579  auto surface_frame = std::make_unique<SurfaceFrame>(
580  SkSurface::MakeNull(1000, 1000), false,
581  [](const SurfaceFrame& surface_frame, SkCanvas* canvas) mutable {
582  return true;
583  });
584 
585  embedder->SubmitFrame(gr_context.get(), std::move(surface_frame));
586 
587  EXPECT_CALL(*jni_mock, FlutterViewEndFrame());
588  embedder->EndFrame(/*should_resubmit_frame=*/false, raster_thread_merger);
589 }
590 
591 TEST(AndroidExternalViewEmbedder, SubmitFrame__platformViewWithoutAnyOverlay) {
592  auto jni_mock = std::make_shared<JNIMock>();
593  auto android_context =
594  std::make_shared<AndroidContext>(AndroidRenderingAPI::kSoftware);
595 
596  auto window = fml::MakeRefCounted<AndroidNativeWindow>(nullptr);
597  auto gr_context = GrDirectContext::MakeMock(nullptr);
598  auto frame_size = SkISize::Make(1000, 1000);
599  auto surface_factory = std::make_shared<TestAndroidSurfaceFactory>(
600  [&android_context, gr_context, window, frame_size]() {
601  auto surface_frame_1 = std::make_unique<SurfaceFrame>(
602  SkSurface::MakeNull(1000, 1000), false,
603  [](const SurfaceFrame& surface_frame, SkCanvas* canvas) {
604  return true;
605  });
606 
607  auto surface_mock = std::make_unique<SurfaceMock>();
608  EXPECT_CALL(*surface_mock, AcquireFrame(frame_size))
609  .Times(1 /* frames */)
610  .WillOnce(Return(ByMove(std::move(surface_frame_1))));
611 
612  auto android_surface_mock =
613  std::make_unique<AndroidSurfaceMock>(android_context);
614  EXPECT_CALL(*android_surface_mock, IsValid()).WillOnce(Return(true));
615 
616  EXPECT_CALL(*android_surface_mock, CreateGPUSurface(gr_context.get()))
617  .WillOnce(Return(ByMove(std::move(surface_mock))));
618 
619  EXPECT_CALL(*android_surface_mock, SetNativeWindow(window));
620  return android_surface_mock;
621  });
622  auto embedder = std::make_unique<AndroidExternalViewEmbedder>(
623  *android_context, jni_mock, surface_factory);
624 
625  auto raster_thread_merger = GetThreadMergerFromPlatformThread();
626 
627  EXPECT_CALL(*jni_mock, FlutterViewBeginFrame());
628  embedder->BeginFrame(frame_size, nullptr, 1.5, raster_thread_merger);
629 
630  {
631  // Add Android view.
632  SkMatrix matrix;
633  MutatorsStack stack;
634  stack.PushTransform(SkMatrix::Translate(0, 0));
635 
636  embedder->PrerollCompositeEmbeddedView(
637  0, std::make_unique<EmbeddedViewParams>(matrix, SkSize::Make(200, 200),
638  stack));
639  EXPECT_CALL(*jni_mock, FlutterViewOnDisplayPlatformView(0, 0, 0, 200, 200,
640  300, 300, stack));
641  }
642 
643  EXPECT_CALL(*jni_mock, FlutterViewCreateOverlaySurface()).Times(0);
644 
645  auto surface_frame = std::make_unique<SurfaceFrame>(
646  SkSurface::MakeNull(1000, 1000), false,
647  [](const SurfaceFrame& surface_frame, SkCanvas* canvas) mutable {
648  return true;
649  });
650 
651  embedder->SubmitFrame(gr_context.get(), std::move(surface_frame));
652 
653  EXPECT_CALL(*jni_mock, FlutterViewEndFrame());
654  embedder->EndFrame(/*should_resubmit_frame=*/false, raster_thread_merger);
655 }
656 
657 TEST(AndroidExternalViewEmbedder, DoesNotCallJNIPlatformThreadOnlyMethods) {
658  auto jni_mock = std::make_shared<JNIMock>();
659 
660  auto android_context = AndroidContext(AndroidRenderingAPI::kSoftware);
661  auto embedder = std::make_unique<AndroidExternalViewEmbedder>(
662  android_context, jni_mock, nullptr);
663 
664  // While on the raster thread, don't make JNI calls as these methods can only
665  // run on the platform thread.
666  fml::Thread platform_thread("platform");
667  auto raster_thread_merger = GetThreadMergerFromRasterThread(&platform_thread);
668 
669  EXPECT_CALL(*jni_mock, FlutterViewBeginFrame()).Times(0);
670  embedder->BeginFrame(SkISize::Make(10, 20), nullptr, 1.0,
671  raster_thread_merger);
672 
673  EXPECT_CALL(*jni_mock, FlutterViewEndFrame()).Times(0);
674  embedder->EndFrame(/*should_resubmit_frame=*/false, raster_thread_merger);
675 }
676 
677 TEST(AndroidExternalViewEmbedder, DestroyOverlayLayersOnSizeChange) {
678  auto jni_mock = std::make_shared<JNIMock>();
679 
680  auto android_context =
681  std::make_shared<AndroidContext>(AndroidRenderingAPI::kSoftware);
682  auto window = fml::MakeRefCounted<AndroidNativeWindow>(nullptr);
683  auto gr_context = GrDirectContext::MakeMock(nullptr);
684  auto frame_size = SkISize::Make(1000, 1000);
685  auto surface_factory = std::make_shared<TestAndroidSurfaceFactory>(
686  [&android_context, gr_context, window, frame_size]() {
687  auto surface_frame_1 = std::make_unique<SurfaceFrame>(
688  SkSurface::MakeNull(1000, 1000), false,
689  [](const SurfaceFrame& surface_frame, SkCanvas* canvas) {
690  return true;
691  });
692 
693  auto surface_mock = std::make_unique<SurfaceMock>();
694  EXPECT_CALL(*surface_mock, AcquireFrame(frame_size))
695  .WillOnce(Return(ByMove(std::move(surface_frame_1))));
696 
697  auto android_surface_mock =
698  std::make_unique<AndroidSurfaceMock>(android_context);
699  EXPECT_CALL(*android_surface_mock, IsValid()).WillOnce(Return(true));
700 
701  EXPECT_CALL(*android_surface_mock, CreateGPUSurface(gr_context.get()))
702  .WillOnce(Return(ByMove(std::move(surface_mock))));
703 
704  EXPECT_CALL(*android_surface_mock, SetNativeWindow(window));
705 
706  return android_surface_mock;
707  });
708 
709  auto embedder = std::make_unique<AndroidExternalViewEmbedder>(
710  *android_context, jni_mock, surface_factory);
711  fml::Thread rasterizer_thread("rasterizer");
712  auto raster_thread_merger =
713  GetThreadMergerFromPlatformThread(&rasterizer_thread);
714 
715  // ------------------ First frame ------------------ //
716  {
717  EXPECT_CALL(*jni_mock, FlutterViewBeginFrame());
718  embedder->BeginFrame(frame_size, nullptr, 1.5, raster_thread_merger);
719 
720  // Add an Android view.
721  MutatorsStack stack1;
722  // TODO(egarciad): Investigate why Flow applies the device pixel ratio to
723  // the offsetPixels, but not the sizePoints.
724  auto view_params_1 = std::make_unique<EmbeddedViewParams>(
725  SkMatrix(), SkSize::Make(200, 200), stack1);
726 
727  embedder->PrerollCompositeEmbeddedView(0, std::move(view_params_1));
728 
729  // This simulates Flutter UI that intersects with the Android view.
730  embedder->CompositeEmbeddedView(0)->drawRect(
731  SkRect::MakeXYWH(50, 50, 200, 200), SkPaint());
732 
733  // Create a new overlay surface.
734  EXPECT_CALL(*jni_mock, FlutterViewCreateOverlaySurface())
735  .WillOnce(Return(
736  ByMove(std::make_unique<PlatformViewAndroidJNI::OverlayMetadata>(
737  0, window))));
738  // The JNI call to display the Android view.
739  EXPECT_CALL(*jni_mock, FlutterViewOnDisplayPlatformView(0, 0, 0, 200, 200,
740  300, 300, stack1));
741  EXPECT_CALL(*jni_mock,
742  FlutterViewDisplayOverlaySurface(0, 50, 50, 200, 200));
743 
744  auto surface_frame =
745  std::make_unique<SurfaceFrame>(SkSurface::MakeNull(1000, 1000), false,
746  [](const SurfaceFrame& surface_frame,
747  SkCanvas* canvas) { return true; });
748  embedder->SubmitFrame(gr_context.get(), std::move(surface_frame));
749 
750  EXPECT_CALL(*jni_mock, FlutterViewEndFrame());
751  embedder->EndFrame(/*should_resubmit_frame=*/false, raster_thread_merger);
752  }
753 
754  EXPECT_CALL(*jni_mock, FlutterViewDestroyOverlaySurfaces());
755  EXPECT_CALL(*jni_mock, FlutterViewBeginFrame());
756  // Change the frame size.
757  embedder->BeginFrame(SkISize::Make(30, 40), nullptr, 1.0,
758  raster_thread_merger);
759 }
760 
761 TEST(AndroidExternalViewEmbedder, DoesNotDestroyOverlayLayersOnSizeChange) {
762  auto jni_mock = std::make_shared<JNIMock>();
763  auto android_context =
764  std::make_shared<AndroidContext>(AndroidRenderingAPI::kSoftware);
765 
766  auto window = fml::MakeRefCounted<AndroidNativeWindow>(nullptr);
767  auto gr_context = GrDirectContext::MakeMock(nullptr);
768  auto frame_size = SkISize::Make(1000, 1000);
769  auto surface_factory = std::make_shared<TestAndroidSurfaceFactory>(
770  [&android_context, gr_context, window, frame_size]() {
771  auto surface_frame_1 = std::make_unique<SurfaceFrame>(
772  SkSurface::MakeNull(1000, 1000), false,
773  [](const SurfaceFrame& surface_frame, SkCanvas* canvas) {
774  return true;
775  });
776 
777  auto surface_mock = std::make_unique<SurfaceMock>();
778  EXPECT_CALL(*surface_mock, AcquireFrame(frame_size))
779  .WillOnce(Return(ByMove(std::move(surface_frame_1))));
780 
781  auto android_surface_mock =
782  std::make_unique<AndroidSurfaceMock>(android_context);
783  EXPECT_CALL(*android_surface_mock, IsValid()).WillOnce(Return(true));
784 
785  EXPECT_CALL(*android_surface_mock, CreateGPUSurface(gr_context.get()))
786  .WillOnce(Return(ByMove(std::move(surface_mock))));
787 
788  EXPECT_CALL(*android_surface_mock, SetNativeWindow(window));
789 
790  return android_surface_mock;
791  });
792 
793  auto embedder = std::make_unique<AndroidExternalViewEmbedder>(
794  *android_context, jni_mock, surface_factory);
795 
796  // ------------------ First frame ------------------ //
797  {
798  fml::Thread rasterizer_thread("rasterizer");
799  auto raster_thread_merger =
800  GetThreadMergerFromPlatformThread(&rasterizer_thread);
801  EXPECT_CALL(*jni_mock, FlutterViewBeginFrame());
802  embedder->BeginFrame(frame_size, nullptr, 1.5, raster_thread_merger);
803 
804  // Add an Android view.
805  MutatorsStack stack1;
806  // TODO(egarciad): Investigate why Flow applies the device pixel ratio to
807  // the offsetPixels, but not the sizePoints.
808  auto view_params_1 = std::make_unique<EmbeddedViewParams>(
809  SkMatrix(), SkSize::Make(200, 200), stack1);
810 
811  embedder->PrerollCompositeEmbeddedView(0, std::move(view_params_1));
812 
813  // This simulates Flutter UI that intersects with the Android view.
814  embedder->CompositeEmbeddedView(0)->drawRect(
815  SkRect::MakeXYWH(50, 50, 200, 200), SkPaint());
816 
817  // Create a new overlay surface.
818  EXPECT_CALL(*jni_mock, FlutterViewCreateOverlaySurface())
819  .WillOnce(Return(
820  ByMove(std::make_unique<PlatformViewAndroidJNI::OverlayMetadata>(
821  0, window))));
822  // The JNI call to display the Android view.
823  EXPECT_CALL(*jni_mock, FlutterViewOnDisplayPlatformView(0, 0, 0, 200, 200,
824  300, 300, stack1));
825  EXPECT_CALL(*jni_mock,
826  FlutterViewDisplayOverlaySurface(0, 50, 50, 200, 200));
827 
828  auto surface_frame =
829  std::make_unique<SurfaceFrame>(SkSurface::MakeNull(1000, 1000), false,
830  [](const SurfaceFrame& surface_frame,
831  SkCanvas* canvas) { return true; });
832  embedder->SubmitFrame(gr_context.get(), std::move(surface_frame));
833 
834  EXPECT_CALL(*jni_mock, FlutterViewEndFrame());
835  embedder->EndFrame(/*should_resubmit_frame=*/false, raster_thread_merger);
836  }
837 
838  // Changing the frame size from the raster thread does not make JNI calls.
839 
840  EXPECT_CALL(*jni_mock, FlutterViewDestroyOverlaySurfaces()).Times(0);
841  EXPECT_CALL(*jni_mock, FlutterViewBeginFrame()).Times(0);
842 
843  fml::Thread platform_thread("platform");
844  embedder->BeginFrame(SkISize::Make(30, 40), nullptr, 1.0,
845  GetThreadMergerFromRasterThread(&platform_thread));
846 }
847 
848 TEST(AndroidExternalViewEmbedder, SupportsDynamicThreadMerging) {
849  auto jni_mock = std::make_shared<JNIMock>();
850  auto android_context = AndroidContext(AndroidRenderingAPI::kSoftware);
851  auto embedder = std::make_unique<AndroidExternalViewEmbedder>(
852  android_context, jni_mock, nullptr);
853  ASSERT_TRUE(embedder->SupportsDynamicThreadMerging());
854 }
855 
856 TEST(AndroidExternalViewEmbedder, DisableThreadMerger) {
857  auto jni_mock = std::make_shared<JNIMock>();
858  auto android_context = AndroidContext(AndroidRenderingAPI::kSoftware);
859  auto embedder = std::make_unique<AndroidExternalViewEmbedder>(
860  android_context, jni_mock, nullptr);
861 
862  fml::Thread platform_thread("platform");
863  auto raster_thread_merger = GetThreadMergerFromRasterThread(&platform_thread);
864  ASSERT_FALSE(raster_thread_merger->IsMerged());
865 
866  // The shell may disable the thread merger during `OnPlatformViewDestroyed`.
867  raster_thread_merger->Disable();
868 
869  EXPECT_CALL(*jni_mock, FlutterViewBeginFrame()).Times(0);
870 
871  embedder->BeginFrame(SkISize::Make(10, 20), nullptr, 1.0,
872  raster_thread_merger);
873  // Push a platform view.
874  embedder->PrerollCompositeEmbeddedView(
875  0, std::make_unique<EmbeddedViewParams>());
876 
877  auto postpreroll_result = embedder->PostPrerollAction(raster_thread_merger);
878  ASSERT_EQ(PostPrerollResult::kSkipAndRetryFrame, postpreroll_result);
879 
880  EXPECT_CALL(*jni_mock, FlutterViewEndFrame()).Times(0);
881  embedder->EndFrame(/*should_resubmit_frame=*/true, raster_thread_merger);
882 
883  ASSERT_FALSE(raster_thread_merger->IsMerged());
884 }
885 
887  auto jni_mock = std::make_shared<JNIMock>();
888  auto android_context =
889  std::make_shared<AndroidContext>(AndroidRenderingAPI::kSoftware);
890  auto window = fml::MakeRefCounted<AndroidNativeWindow>(nullptr);
891  auto gr_context = GrDirectContext::MakeMock(nullptr);
892  auto frame_size = SkISize::Make(1000, 1000);
893  auto surface_factory = std::make_shared<TestAndroidSurfaceFactory>(
894  [&android_context, gr_context, window, frame_size]() {
895  auto surface_frame_1 = std::make_unique<SurfaceFrame>(
896  SkSurface::MakeNull(1000, 1000), false,
897  [](const SurfaceFrame& surface_frame, SkCanvas* canvas) {
898  return true;
899  });
900 
901  auto surface_mock = std::make_unique<SurfaceMock>();
902  EXPECT_CALL(*surface_mock, AcquireFrame(frame_size))
903  .WillOnce(Return(ByMove(std::move(surface_frame_1))));
904 
905  auto android_surface_mock =
906  std::make_unique<AndroidSurfaceMock>(android_context);
907  EXPECT_CALL(*android_surface_mock, IsValid()).WillOnce(Return(true));
908  EXPECT_CALL(*android_surface_mock, CreateGPUSurface(gr_context.get()))
909  .WillOnce(Return(ByMove(std::move(surface_mock))));
910 
911  return android_surface_mock;
912  });
913 
914  auto embedder = std::make_unique<AndroidExternalViewEmbedder>(
915  *android_context, jni_mock, surface_factory);
916  fml::Thread rasterizer_thread("rasterizer");
917  auto raster_thread_merger =
918  GetThreadMergerFromPlatformThread(&rasterizer_thread);
919 
920  embedder->BeginFrame(frame_size, nullptr, 1.5, raster_thread_merger);
921 
922  // Add an Android view.
923  MutatorsStack stack;
924  auto view_params = std::make_unique<EmbeddedViewParams>(
925  SkMatrix(), SkSize::Make(200, 200), stack);
926 
927  embedder->PrerollCompositeEmbeddedView(0, std::move(view_params));
928 
929  // This simulates Flutter UI that intersects with the Android view.
930  embedder->CompositeEmbeddedView(0)->drawRect(
931  SkRect::MakeXYWH(50, 50, 200, 200), SkPaint());
932 
933  // Create a new overlay surface.
934  EXPECT_CALL(*jni_mock, FlutterViewCreateOverlaySurface())
935  .WillOnce(Return(
936  ByMove(std::make_unique<PlatformViewAndroidJNI::OverlayMetadata>(
937  0, window))));
938 
939  auto surface_frame = std::make_unique<SurfaceFrame>(
940  SkSurface::MakeNull(1000, 1000), false,
941  [](const SurfaceFrame& surface_frame, SkCanvas* canvas) { return true; });
942  embedder->SubmitFrame(gr_context.get(), std::move(surface_frame));
943 
944  embedder->EndFrame(/*should_resubmit_frame=*/false, raster_thread_merger);
945 
946  EXPECT_CALL(*jni_mock, FlutterViewDestroyOverlaySurfaces());
947  // Teardown.
948  embedder->Teardown();
949 }
950 
951 } // namespace testing
952 } // namespace flutter
virtual TaskQueueId GetTaskQueueId()
Definition: task_runner.cc:38
Holds state that is shared across Android surfaces.
fml::RefPtr< fml::TaskRunner > GetTaskRunner() const
Definition: thread.cc:45
fml::RefPtr< fml::RasterThreadMerger > GetThreadMergerFromPlatformThread(fml::Thread *rasterizer_thread=nullptr)
std::unique_ptr< AndroidSurface > CreateSurface() override
void PushTransform(const SkMatrix &matrix)
static void EnsureInitializedForCurrentThread()
Definition: message_loop.cc:27
GAsyncResult * result
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
static bool IsValid(double value)
Abstract Base Class that represents where we will be rendering content.
Definition: surface.h:18
fml::RefPtr< fml::RasterThreadMerger > GetThreadMergerFromRasterThread(fml::Thread *platform_thread)
TEST(DisplayListCanvas, DrawPaint)