Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 7498f79

Browse files
author
Emmanuel Garcia
committed
Unit tests
1 parent 47476f8 commit 7498f79

File tree

6 files changed

+202
-26
lines changed

6 files changed

+202
-26
lines changed

flow/surface_frame.cc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ bool SurfaceFrame::PerformSubmit() {
6161
if (submit_callback_ == nullptr) {
6262
return false;
6363
}
64-
6564
if (submit_callback_(*this, SkiaCanvas())) {
6665
return true;
6766
}

shell/platform/android/external_view_embedder/external_view_embedder.cc

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ bool AndroidExternalViewEmbedder::SubmitFrame(
9898
picture_recorders_.at(view_id)->finishRecordingAsPicture();
9999
FML_CHECK(picture);
100100
pictures.insert({view_id, picture});
101+
101102
overlay_layers.insert({view_id, {}});
102103

103104
sk_sp<RTree> rtree = view_rtrees_.at(view_id);
@@ -168,11 +169,12 @@ bool AndroidExternalViewEmbedder::SubmitFrame(
168169
params.mutatorsStack() //
169170
);
170171
for (const SkRect& overlay_rect : overlay_layers.at(view_id)) {
171-
auto frame = CreateSurfaceIfNeeded(context, //
172-
view_id, //
173-
pictures.at(view_id), //
174-
overlay_rect //
175-
);
172+
std::unique_ptr<SurfaceFrame> frame =
173+
CreateSurfaceIfNeeded(context, //
174+
view_id, //
175+
pictures.at(view_id), //
176+
overlay_rect //
177+
);
176178
if (should_submit_current_frame) {
177179
frame->Submit();
178180
}

shell/platform/android/external_view_embedder/external_view_embedder_unittests.cc

Lines changed: 120 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ TEST(AndroidExternalViewEmbedder, PlatformViewRect__ChangedParams) {
250250
ASSERT_EQ(SkRect::MakeXYWH(75, 90, 105, 120), embedder->GetViewRect(view_id));
251251
}
252252

253-
TEST(AndroidExternalViewEmbedder, SubmitFrame__RecycleSurfaces) {
253+
TEST(AndroidExternalViewEmbedder, SubmitFrame) {
254254
auto jni_mock = std::make_shared<JNIMock>();
255255
auto android_context =
256256
std::make_shared<AndroidContext>(AndroidRenderingAPI::kSoftware);
@@ -294,6 +294,27 @@ TEST(AndroidExternalViewEmbedder, SubmitFrame__RecycleSurfaces) {
294294
auto raster_thread_merger = GetThreadMergerFromPlatformThread();
295295

296296
// ------------------ First frame ------------------ //
297+
{
298+
auto did_submit_frame = false;
299+
auto surface_frame = std::make_unique<SurfaceFrame>(
300+
SkSurface::MakeNull(1000, 1000), false,
301+
[&did_submit_frame](const SurfaceFrame& surface_frame,
302+
SkCanvas* canvas) mutable {
303+
if (canvas != nullptr) {
304+
did_submit_frame = true;
305+
}
306+
return true;
307+
});
308+
309+
embedder->SubmitFrame(gr_context.get(), std::move(surface_frame));
310+
// Submits frame if no Android view in the current frame.
311+
EXPECT_TRUE(did_submit_frame);
312+
313+
EXPECT_CALL(*jni_mock, FlutterViewEndFrame());
314+
embedder->EndFrame(/*should_resubmit_frame=*/false, raster_thread_merger);
315+
}
316+
317+
// ------------------ Second frame ------------------ //
297318
{
298319
EXPECT_CALL(*jni_mock, FlutterViewBeginFrame());
299320
embedder->BeginFrame(frame_size, nullptr, 1.5, raster_thread_merger);
@@ -338,18 +359,26 @@ TEST(AndroidExternalViewEmbedder, SubmitFrame__RecycleSurfaces) {
338359
EXPECT_CALL(*jni_mock,
339360
FlutterViewDisplayOverlaySurface(0, 50, 50, 200, 200));
340361

341-
auto surface_frame =
342-
std::make_unique<SurfaceFrame>(SkSurface::MakeNull(1000, 1000), false,
343-
[](const SurfaceFrame& surface_frame,
344-
SkCanvas* canvas) { return true; });
362+
auto did_submit_frame = false;
363+
auto surface_frame = std::make_unique<SurfaceFrame>(
364+
SkSurface::MakeNull(1000, 1000), false,
365+
[&did_submit_frame](const SurfaceFrame& surface_frame,
366+
SkCanvas* canvas) mutable {
367+
if (canvas != nullptr) {
368+
did_submit_frame = true;
369+
}
370+
return true;
371+
});
345372

346373
embedder->SubmitFrame(gr_context.get(), std::move(surface_frame));
374+
// Doesn't submit frame if there aren't Android views in the previous frame.
375+
EXPECT_FALSE(did_submit_frame);
347376

348377
EXPECT_CALL(*jni_mock, FlutterViewEndFrame());
349378
embedder->EndFrame(/*should_resubmit_frame=*/false, raster_thread_merger);
350379
}
351380

352-
// ------------------ Second frame ------------------ //
381+
// ------------------ Third frame ------------------ //
353382
{
354383
EXPECT_CALL(*jni_mock, FlutterViewBeginFrame());
355384
embedder->BeginFrame(frame_size, nullptr, 1.5, raster_thread_merger);
@@ -392,11 +421,19 @@ TEST(AndroidExternalViewEmbedder, SubmitFrame__RecycleSurfaces) {
392421
EXPECT_CALL(*jni_mock,
393422
FlutterViewDisplayOverlaySurface(0, 50, 50, 200, 200));
394423

395-
auto surface_frame =
396-
std::make_unique<SurfaceFrame>(SkSurface::MakeNull(1000, 1000), false,
397-
[](const SurfaceFrame& surface_frame,
398-
SkCanvas* canvas) { return true; });
424+
auto did_submit_frame = false;
425+
auto surface_frame = std::make_unique<SurfaceFrame>(
426+
SkSurface::MakeNull(1000, 1000), false,
427+
[&did_submit_frame](const SurfaceFrame& surface_frame,
428+
SkCanvas* canvas) mutable {
429+
if (canvas != nullptr) {
430+
did_submit_frame = true;
431+
}
432+
return true;
433+
});
399434
embedder->SubmitFrame(gr_context.get(), std::move(surface_frame));
435+
// Submits frame if there are Android views in the previous frame.
436+
EXPECT_TRUE(did_submit_frame);
400437

401438
EXPECT_CALL(*jni_mock, FlutterViewEndFrame());
402439
embedder->EndFrame(/*should_resubmit_frame=*/false, raster_thread_merger);
@@ -423,15 +460,83 @@ TEST(AndroidExternalViewEmbedder, DoesNotCallJNIPlatformThreadOnlyMethods) {
423460

424461
TEST(AndroidExternalViewEmbedder, DestroyOverlayLayersOnSizeChange) {
425462
auto jni_mock = std::make_shared<JNIMock>();
426-
auto embedder =
427-
std::make_unique<AndroidExternalViewEmbedder>(nullptr, jni_mock, nullptr);
463+
auto android_context =
464+
std::make_shared<AndroidContext>(AndroidRenderingAPI::kSoftware);
428465

466+
auto window = fml::MakeRefCounted<AndroidNativeWindow>(nullptr);
467+
auto gr_context = GrContext::MakeMock(nullptr);
468+
auto frame_size = SkISize::Make(1000, 1000);
469+
auto surface_factory =
470+
[gr_context, window, frame_size](
471+
std::shared_ptr<AndroidContext> android_context,
472+
std::shared_ptr<PlatformViewAndroidJNI> jni_facade) {
473+
auto surface_frame_1 = std::make_unique<SurfaceFrame>(
474+
SkSurface::MakeNull(1000, 1000), false,
475+
[](const SurfaceFrame& surface_frame, SkCanvas* canvas) {
476+
return true;
477+
});
478+
479+
auto surface_mock = std::make_unique<SurfaceMock>();
480+
EXPECT_CALL(*surface_mock, AcquireFrame(frame_size))
481+
.WillOnce(Return(ByMove(std::move(surface_frame_1))));
482+
483+
auto android_surface_mock = std::make_unique<AndroidSurfaceMock>();
484+
EXPECT_CALL(*android_surface_mock, IsValid()).WillOnce(Return(true));
485+
486+
EXPECT_CALL(*android_surface_mock, CreateGPUSurface(gr_context.get()))
487+
.WillOnce(Return(ByMove(std::move(surface_mock))));
488+
489+
EXPECT_CALL(*android_surface_mock, SetNativeWindow(window));
490+
491+
return android_surface_mock;
492+
};
493+
494+
auto embedder = std::make_unique<AndroidExternalViewEmbedder>(
495+
android_context, jni_mock, surface_factory);
429496
auto raster_thread_merger = GetThreadMergerFromPlatformThread();
430-
ASSERT_FALSE(raster_thread_merger->IsMerged());
431497

432-
embedder->BeginFrame(SkISize::Make(10, 20), nullptr, 1.0,
433-
raster_thread_merger);
498+
// ------------------ First frame ------------------ //
499+
{
500+
EXPECT_CALL(*jni_mock, FlutterViewBeginFrame());
501+
embedder->BeginFrame(frame_size, nullptr, 1.5, raster_thread_merger);
502+
503+
// Add an Android view.
504+
MutatorsStack stack1;
505+
// TODO(egarciad): Investigate why Flow applies the device pixel ratio to
506+
// the offsetPixels, but not the sizePoints.
507+
auto view_params_1 = std::make_unique<EmbeddedViewParams>(
508+
SkMatrix(), SkSize::Make(200, 200), stack1);
509+
510+
embedder->PrerollCompositeEmbeddedView(0, std::move(view_params_1));
511+
512+
// This simulates Flutter UI that intersects with the Android view.
513+
embedder->CompositeEmbeddedView(0)->drawRect(
514+
SkRect::MakeXYWH(50, 50, 200, 200), SkPaint());
515+
516+
// Create a new overlay surface.
517+
EXPECT_CALL(*jni_mock, FlutterViewCreateOverlaySurface())
518+
.WillOnce(Return(
519+
ByMove(std::make_unique<PlatformViewAndroidJNI::OverlayMetadata>(
520+
0, window))));
521+
// The JNI call to display the Android view.
522+
EXPECT_CALL(*jni_mock, FlutterViewOnDisplayPlatformView(0, 0, 0, 200, 200,
523+
300, 300, stack1));
524+
EXPECT_CALL(*jni_mock,
525+
FlutterViewDisplayOverlaySurface(0, 50, 50, 200, 200));
526+
527+
auto surface_frame =
528+
std::make_unique<SurfaceFrame>(SkSurface::MakeNull(1000, 1000), false,
529+
[](const SurfaceFrame& surface_frame,
530+
SkCanvas* canvas) { return true; });
531+
embedder->SubmitFrame(gr_context.get(), std::move(surface_frame));
532+
533+
EXPECT_CALL(*jni_mock, FlutterViewEndFrame());
534+
embedder->EndFrame(/*should_resubmit_frame=*/false, raster_thread_merger);
535+
}
536+
434537
EXPECT_CALL(*jni_mock, FlutterViewDestroyOverlaySurfaces());
538+
EXPECT_CALL(*jni_mock, FlutterViewBeginFrame());
539+
// Change the frame size.
435540
embedder->BeginFrame(SkISize::Make(30, 40), nullptr, 1.0,
436541
raster_thread_merger);
437542
}

shell/platform/android/external_view_embedder/surface_pool.cc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,11 @@ void SurfacePool::RecycleLayers() {
7272

7373
void SurfacePool::DestroyLayers(
7474
std::shared_ptr<PlatformViewAndroidJNI> jni_facade) {
75+
if (layers_.size() > 0) {
76+
jni_facade->FlutterViewDestroyOverlaySurfaces();
77+
}
7578
layers_.clear();
7679
available_layer_index_ = 0;
77-
jni_facade->FlutterViewDestroyOverlaySurfaces();
7880
}
7981

8082
std::vector<std::shared_ptr<OverlayLayer>> SurfacePool::GetUnusedLayers() {

shell/platform/android/external_view_embedder/surface_pool_unittests.cc

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,5 +164,41 @@ TEST(SurfacePool, GetLayer__AllocateTwoLayers) {
164164
ASSERT_EQ(1, layer_2->id);
165165
}
166166

167+
TEST(SurfacePool, DestroyLayers) {
168+
auto pool = std::make_unique<SurfacePool>();
169+
auto jni_mock = std::make_shared<JNIMock>();
170+
171+
EXPECT_CALL(*jni_mock, FlutterViewDestroyOverlaySurfaces()).Times(0);
172+
pool->DestroyLayers(jni_mock);
173+
174+
auto gr_context = GrContext::MakeMock(nullptr);
175+
auto android_context =
176+
std::make_shared<AndroidContext>(AndroidRenderingAPI::kSoftware);
177+
178+
auto window = fml::MakeRefCounted<AndroidNativeWindow>(nullptr);
179+
EXPECT_CALL(*jni_mock, FlutterViewCreateOverlaySurface())
180+
.Times(1)
181+
.WillOnce(Return(
182+
ByMove(std::make_unique<PlatformViewAndroidJNI::OverlayMetadata>(
183+
0, window))));
184+
185+
auto surface_factory =
186+
[gr_context, window](std::shared_ptr<AndroidContext> android_context,
187+
std::shared_ptr<PlatformViewAndroidJNI> jni_facade) {
188+
auto android_surface_mock = std::make_unique<AndroidSurfaceMock>();
189+
EXPECT_CALL(*android_surface_mock, CreateGPUSurface(gr_context.get()));
190+
EXPECT_CALL(*android_surface_mock, SetNativeWindow(window));
191+
EXPECT_CALL(*android_surface_mock, IsValid()).WillOnce(Return(true));
192+
return android_surface_mock;
193+
};
194+
pool->GetLayer(gr_context.get(), android_context, jni_mock, surface_factory);
195+
196+
EXPECT_CALL(*jni_mock, FlutterViewDestroyOverlaySurfaces());
197+
pool->DestroyLayers(jni_mock);
198+
199+
pool->RecycleLayers();
200+
ASSERT_TRUE(pool->GetUnusedLayers().empty());
201+
}
202+
167203
} // namespace testing
168204
} // namespace flutter

shell/platform/android/test/io/flutter/embedding/android/FlutterViewTest.java

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package io.flutter.embedding.android;
22

33
import static junit.framework.TestCase.assertEquals;
4+
import static junit.framework.TestCase.assertFalse;
5+
import static junit.framework.TestCase.assertTrue;
46
import static org.mockito.Matchers.any;
57
import static org.mockito.Mockito.doNothing;
68
import static org.mockito.Mockito.mock;
@@ -385,11 +387,38 @@ public void flutterImageView_acquiresImageAndInvalidates() {
385387
mockReader,
386388
FlutterImageView.SurfaceKind.background));
387389

388-
imageView.acquireLatestImage();
390+
final FlutterJNI jni = mock(FlutterJNI.class);
391+
imageView.attachToRenderer(new FlutterRenderer(jni));
392+
393+
final Image mockImage = mock(Image.class);
394+
when(mockReader.acquireLatestImage()).thenReturn(mockImage);
395+
396+
assertTrue(imageView.acquireLatestImage());
389397
verify(mockReader, times(1)).acquireLatestImage();
390398
verify(imageView, times(1)).invalidate();
391399
}
392400

401+
@Test
402+
public void flutterImageView_acquireLatestImageReturnsFalse() {
403+
final ImageReader mockReader = mock(ImageReader.class);
404+
when(mockReader.getMaxImages()).thenReturn(2);
405+
406+
final FlutterImageView imageView =
407+
spy(
408+
new FlutterImageView(
409+
RuntimeEnvironment.application,
410+
mockReader,
411+
FlutterImageView.SurfaceKind.background));
412+
413+
assertFalse(imageView.acquireLatestImage());
414+
415+
final FlutterJNI jni = mock(FlutterJNI.class);
416+
imageView.attachToRenderer(new FlutterRenderer(jni));
417+
418+
when(mockReader.acquireLatestImage()).thenReturn(null);
419+
assertFalse(imageView.acquireLatestImage());
420+
}
421+
393422
@Test
394423
public void flutterImageView_acquiresMaxImagesAtMost() {
395424
final ImageReader mockReader = mock(ImageReader.class);
@@ -405,10 +434,13 @@ public void flutterImageView_acquiresMaxImagesAtMost() {
405434
mockReader,
406435
FlutterImageView.SurfaceKind.background));
407436

437+
final FlutterJNI jni = mock(FlutterJNI.class);
438+
imageView.attachToRenderer(new FlutterRenderer(jni));
439+
408440
doNothing().when(imageView).invalidate();
409-
imageView.acquireLatestImage();
410-
imageView.acquireLatestImage();
411-
imageView.acquireLatestImage();
441+
assertTrue(imageView.acquireLatestImage());
442+
assertTrue(imageView.acquireLatestImage());
443+
assertTrue(imageView.acquireLatestImage());
412444

413445
verify(mockReader, times(2)).acquireLatestImage();
414446
}

0 commit comments

Comments
 (0)