Flutter Engine
The Flutter Engine
FlutterRendererTest.java
Go to the documentation of this file.
1package io.flutter.embedding.engine.renderer;
2
3import static android.content.ComponentCallbacks2.TRIM_MEMORY_COMPLETE;
4import static org.junit.Assert.assertArrayEquals;
5import static org.junit.Assert.assertEquals;
6import static org.junit.Assert.assertNotNull;
7import static org.junit.Assert.assertNull;
8import static org.mockito.ArgumentMatchers.any;
9import static org.mockito.ArgumentMatchers.anyFloat;
10import static org.mockito.ArgumentMatchers.anyInt;
11import static org.mockito.ArgumentMatchers.eq;
12import static org.mockito.Mockito.mock;
13import static org.mockito.Mockito.never;
14import static org.mockito.Mockito.spy;
15import static org.mockito.Mockito.times;
16import static org.mockito.Mockito.verify;
17import static org.robolectric.Shadows.shadowOf;
18
19import android.graphics.Canvas;
20import android.graphics.Rect;
21import android.graphics.SurfaceTexture;
22import android.media.Image;
23import android.os.Looper;
24import android.view.Surface;
25import androidx.lifecycle.Lifecycle;
26import androidx.test.ext.junit.rules.ActivityScenarioRule;
27import androidx.test.ext.junit.runners.AndroidJUnit4;
28import io.flutter.embedding.android.FlutterActivity;
29import io.flutter.embedding.engine.FlutterJNI;
30import io.flutter.view.TextureRegistry;
31import java.util.concurrent.CountDownLatch;
32import java.util.concurrent.atomic.AtomicInteger;
33import org.junit.Before;
34import org.junit.Rule;
35import org.junit.Test;
36import org.junit.runner.RunWith;
37import org.mockito.ArgumentCaptor;
38import org.robolectric.annotation.Config;
39
40@Config(manifest = Config.NONE)
41@RunWith(AndroidJUnit4.class)
42public class FlutterRendererTest {
43 @Rule(order = 1)
44 public final FlutterEngineRule engineRule = new FlutterEngineRule();
45
46 @Rule(order = 2)
47 public final ActivityScenarioRule<FlutterActivity> scenarioRule =
48 new ActivityScenarioRule<>(engineRule.makeIntent());
49
50 private FlutterJNI fakeFlutterJNI;
51
52 @Before
53 public void init() {
54 // Uncomment the following line to enable logging output in test.
55 // ShadowLog.stream = System.out;
56 }
57
58 @Before
59 public void setup() {
60 fakeFlutterJNI = engineRule.getFlutterJNI();
61 }
62
63 @Test
65 // Setup the test.
66 Surface fakeSurface = mock(Surface.class);
67 FlutterRenderer flutterRenderer = engineRule.getFlutterEngine().getRenderer();
68
69 // Execute the behavior under test.
70 flutterRenderer.startRenderingToSurface(fakeSurface, false);
71
72 // Verify the behavior under test.
73 verify(fakeFlutterJNI, times(1)).onSurfaceCreated(eq(fakeSurface));
74 }
75
76 @Test
78 // Setup the test.
79 Surface fakeSurface = mock(Surface.class);
80 FlutterRenderer flutterRenderer = engineRule.getFlutterEngine().getRenderer();
81
82 flutterRenderer.startRenderingToSurface(fakeSurface, false);
83
84 // Execute the behavior under test.
85 flutterRenderer.surfaceChanged(100, 50);
86
87 // Verify the behavior under test.
88 verify(fakeFlutterJNI, times(1)).onSurfaceChanged(eq(100), eq(50));
89 }
90
91 @Test
93 // Setup the test.
94 Surface fakeSurface = mock(Surface.class);
95 FlutterRenderer flutterRenderer = engineRule.getFlutterEngine().getRenderer();
96
97 flutterRenderer.startRenderingToSurface(fakeSurface, false);
98
99 // Execute the behavior under test.
100 flutterRenderer.stopRenderingToSurface();
101
102 // Verify the behavior under test.
103 verify(fakeFlutterJNI, times(1)).onSurfaceDestroyed();
104 }
105
106 @Test
108 // Setup the test.
109 Surface fakeSurface = mock(Surface.class);
110 Surface fakeSurface2 = mock(Surface.class);
111 FlutterRenderer flutterRenderer = engineRule.getFlutterEngine().getRenderer();
112
113 flutterRenderer.startRenderingToSurface(fakeSurface, false);
114
115 // Execute behavior under test.
116 flutterRenderer.startRenderingToSurface(fakeSurface2, false);
117
118 // Verify behavior under test.
119 verify(fakeFlutterJNI, times(1)).onSurfaceDestroyed(); // notification of 1st surface's removal.
120 }
121
122 @Test
124 // Setup the test.
125 Surface fakeSurface = mock(Surface.class);
126 FlutterRenderer flutterRenderer = engineRule.getFlutterEngine().getRenderer();
127
128 flutterRenderer.startRenderingToSurface(fakeSurface, false);
129
130 // Execute the behavior under test.
131 flutterRenderer.stopRenderingToSurface();
132
133 // Verify behavior under test.
134 verify(fakeFlutterJNI, times(1)).onSurfaceDestroyed();
135 }
136
137 @Test
139 // Setup the test.
140 Surface fakeSurface = mock(Surface.class);
141 FlutterRenderer flutterRenderer = engineRule.getFlutterEngine().getRenderer();
142
143 flutterRenderer.startRenderingToSurface(fakeSurface, false);
144 flutterRenderer.startRenderingToSurface(fakeSurface, false);
145
146 // Verify behavior under test.
147 verify(fakeFlutterJNI, times(1)).onSurfaceDestroyed();
148 }
149
150 @Test
152 // Setup the test.
153 Surface fakeSurface = mock(Surface.class);
154 FlutterRenderer flutterRenderer = engineRule.getFlutterEngine().getRenderer();
155
156 flutterRenderer.startRenderingToSurface(fakeSurface, false);
157 flutterRenderer.startRenderingToSurface(fakeSurface, true);
158
159 // Verify behavior under test.
160 verify(fakeFlutterJNI, never()).onSurfaceDestroyed();
161 }
162
163 @Test
165 // Setup the test.
166 Surface fakeSurface = mock(Surface.class);
167 FlutterRenderer flutterRenderer = engineRule.getFlutterEngine().getRenderer();
168
169 FlutterRenderer.SurfaceTextureRegistryEntry entry =
171 flutterRenderer.startRenderingToSurface(fakeSurface, false);
172
173 // Execute the behavior under test.
174 flutterRenderer.stopRenderingToSurface();
175
176 // Verify behavior under test.
177 verify(fakeFlutterJNI, times(0)).markTextureFrameAvailable(eq(entry.id()));
178 }
179
180 @Test
182 // Setup the test.
183 Surface fakeSurface = mock(Surface.class);
184 FlutterRenderer flutterRenderer = engineRule.getFlutterEngine().getRenderer();
185
186 SurfaceTexture surfaceTexture = new SurfaceTexture(0);
187
188 // Execute the behavior under test.
189 FlutterRenderer.SurfaceTextureRegistryEntry entry =
191 flutterRenderer.registerSurfaceTexture(surfaceTexture);
192
193 flutterRenderer.startRenderingToSurface(fakeSurface, false);
194
195 // Verify behavior under test.
196 assertEquals(surfaceTexture, entry.surfaceTexture());
197
198 verify(fakeFlutterJNI, times(1)).registerTexture(eq(entry.id()), eq(entry.textureWrapper()));
199 }
200
201 @Test
203 // Setup the test.
204 Surface fakeSurface = mock(Surface.class);
205 FlutterRenderer flutterRenderer = engineRule.getFlutterEngine().getRenderer();
206
207 FlutterRenderer.SurfaceTextureRegistryEntry entry =
209 long id = entry.id();
210
211 flutterRenderer.startRenderingToSurface(fakeSurface, false);
212
213 // Execute the behavior under test.
214 runFinalization(entry);
215
216 shadowOf(Looper.getMainLooper()).idle();
217
218 flutterRenderer.stopRenderingToSurface();
219
220 // Verify behavior under test.
221 verify(fakeFlutterJNI, times(1)).unregisterTexture(eq(id));
222 }
223
224 @Test
226 // Setup the test.
227 Surface fakeSurface = mock(Surface.class);
228 engineRule.setJniIsAttached(false);
229 FlutterRenderer flutterRenderer = engineRule.getFlutterEngine().getRenderer();
230
231 FlutterRenderer.SurfaceTextureRegistryEntry entry =
233 long id = entry.id();
234
235 flutterRenderer.startRenderingToSurface(fakeSurface, false);
236 flutterRenderer.stopRenderingToSurface();
237
238 // Execute the behavior under test.
239 runFinalization(entry);
240
241 shadowOf(Looper.getMainLooper()).idle();
242
243 // Verify behavior under test.
244 verify(fakeFlutterJNI, times(0)).unregisterTexture(eq(id));
245 }
246
247 /** @noinspection FinalizeCalledExplicitly */
249 CountDownLatch latch = new CountDownLatch(1);
250 Thread fakeFinalizer =
251 new Thread(
252 () -> {
253 try {
254 entry.finalize();
255 latch.countDown();
256 } catch (Throwable e) {
257 // do nothing
258 }
259 });
260 fakeFinalizer.start();
261 try {
262 latch.await();
263 } catch (InterruptedException e) {
264 // do nothing
265 }
266 }
267
268 @Test
270 // Intentionally do not use 'engineRule' in this test, because we are testing a very narrow
271 // API (the side-effects of 'setViewportMetrics'). Under normal construction, the engine will
272 // invoke 'setViewportMetrics' a number of times automatically, making testing the side-effects
273 // of the method call more difficult than needed.
274 FlutterJNI fakeFlutterJNI = mock(FlutterJNI.class);
275 FlutterRenderer flutterRenderer = new FlutterRenderer(fakeFlutterJNI);
276
277 // Setup the test.
278 FlutterRenderer.ViewportMetrics metrics = new FlutterRenderer.ViewportMetrics();
279 metrics.width = 1000;
280 metrics.height = 1000;
281 metrics.devicePixelRatio = 2;
282 metrics.displayFeatures.add(
284 new Rect(10, 20, 30, 40),
287 metrics.displayFeatures.add(
289 new Rect(50, 60, 70, 80), FlutterRenderer.DisplayFeatureType.CUTOUT));
290
291 // Execute the behavior under test.
292 flutterRenderer.setViewportMetrics(metrics);
293
294 // Verify behavior under test.
295 ArgumentCaptor<int[]> boundsCaptor = ArgumentCaptor.forClass(int[].class);
296 ArgumentCaptor<int[]> typeCaptor = ArgumentCaptor.forClass(int[].class);
297 ArgumentCaptor<int[]> stateCaptor = ArgumentCaptor.forClass(int[].class);
298 verify(fakeFlutterJNI)
299 .setViewportMetrics(
300 anyFloat(),
301 anyInt(),
302 anyInt(),
303 anyInt(),
304 anyInt(),
305 anyInt(),
306 anyInt(),
307 anyInt(),
308 anyInt(),
309 anyInt(),
310 anyInt(),
311 anyInt(),
312 anyInt(),
313 anyInt(),
314 anyInt(),
315 anyInt(),
316 boundsCaptor.capture(),
317 typeCaptor.capture(),
318 stateCaptor.capture());
319
320 assertArrayEquals(new int[] {10, 20, 30, 40, 50, 60, 70, 80}, boundsCaptor.getValue());
321 assertArrayEquals(
322 new int[] {
324 FlutterRenderer.DisplayFeatureType.CUTOUT.encodedValue
325 },
326 typeCaptor.getValue());
327 assertArrayEquals(
328 new int[] {
330 FlutterRenderer.DisplayFeatureState.UNKNOWN.encodedValue
331 },
332 stateCaptor.getValue());
333 }
334
335 @Test
337 // Setup the test.
338 FlutterRenderer flutterRenderer = engineRule.getFlutterEngine().getRenderer();
339
340 AtomicInteger invocationCount = new AtomicInteger(0);
341 final TextureRegistry.OnFrameConsumedListener listener = invocationCount::incrementAndGet;
342
343 FlutterRenderer.SurfaceTextureRegistryEntry entry =
345 entry.setOnFrameConsumedListener(listener);
346
347 // Execute the behavior under test.
348 entry.textureWrapper().updateTexImage();
349
350 // Verify behavior under test.
351 assertEquals(1, invocationCount.get());
352 }
353
354 @Test
356 // Setup the test.
357 FlutterRenderer flutterRenderer = spy(engineRule.getFlutterEngine().getRenderer());
358
359 // Execute the behavior under test.
360 FlutterRenderer.SurfaceTextureRegistryEntry entry =
362
363 // Verify behavior under test.
364 verify(flutterRenderer, times(1)).addOnTrimMemoryListener(entry);
365 }
366
367 @Test
369 // Setup the test.
370 FlutterRenderer flutterRenderer = spy(engineRule.getFlutterEngine().getRenderer());
371 FlutterRenderer.SurfaceTextureRegistryEntry entry =
373
374 // Execute the behavior under test.
375 entry.release();
376
377 // Verify behavior under test.
378 verify(flutterRenderer, times(1)).removeOnTrimMemoryListener(entry);
379 }
380
381 @Test
383 // Setup the test.
384 FlutterRenderer flutterRenderer = engineRule.getFlutterEngine().getRenderer();
385
386 AtomicInteger invocationCount = new AtomicInteger(0);
387 final TextureRegistry.OnTrimMemoryListener listener =
388 level -> invocationCount.incrementAndGet();
389
390 FlutterRenderer.SurfaceTextureRegistryEntry entry =
392 entry.setOnTrimMemoryListener(listener);
393
394 // Execute the behavior under test.
395 flutterRenderer.onTrimMemory(TRIM_MEMORY_COMPLETE);
396
397 // Verify behavior under test.
398 assertEquals(1, invocationCount.get());
399 }
400
401 @Test
403 // Setup the test.
404 Surface fakeSurface = mock(Surface.class);
405 FlutterRenderer flutterRenderer = engineRule.getFlutterEngine().getRenderer();
406
407 flutterRenderer.startRenderingToSurface(fakeSurface, false);
408
409 // Execute the behavior under test.
410 // Simulate calling |FlutterRenderer#stopRenderingToSurface| twice with different code paths.
411 flutterRenderer.stopRenderingToSurface();
412 flutterRenderer.stopRenderingToSurface();
413
414 // Verify behavior under test.
415 verify(fakeFlutterJNI, times(1)).onSurfaceDestroyed();
416 }
417
418 @Test
420 Surface fakeSurface = mock(Surface.class);
421 FlutterRenderer flutterRenderer = engineRule.getFlutterEngine().getRenderer();
422
423 flutterRenderer.startRenderingToSurface(fakeSurface, false);
424 verify(fakeFlutterJNI, times(1)).onSurfaceCreated(eq(fakeSurface));
425 }
426
427 @Test
429 Surface fakeSurface = mock(Surface.class);
430 Surface fakeSurface2 = mock(Surface.class);
431 FlutterRenderer flutterRenderer = engineRule.getFlutterEngine().getRenderer();
432
433 // The following call sequence mimics the behaviour of FlutterView when it exits from hybrid
434 // composition mode.
435
436 // Install initial rendering surface.
437 flutterRenderer.startRenderingToSurface(fakeSurface, false);
438 verify(fakeFlutterJNI, times(1)).onSurfaceCreated(eq(fakeSurface));
439 verify(fakeFlutterJNI, times(0)).onSurfaceWindowChanged(eq(fakeSurface));
440
441 // Install the image view.
442 flutterRenderer.startRenderingToSurface(fakeSurface2, true);
443 verify(fakeFlutterJNI, times(1)).onSurfaceCreated(eq(fakeSurface));
444 verify(fakeFlutterJNI, times(0)).onSurfaceWindowChanged(eq(fakeSurface));
445 verify(fakeFlutterJNI, times(0)).onSurfaceCreated(eq(fakeSurface2));
446 verify(fakeFlutterJNI, times(1)).onSurfaceWindowChanged(eq(fakeSurface2));
447
448 flutterRenderer.startRenderingToSurface(fakeSurface, true);
449 verify(fakeFlutterJNI, times(1)).onSurfaceCreated(eq(fakeSurface));
450 verify(fakeFlutterJNI, times(1)).onSurfaceWindowChanged(eq(fakeSurface));
451 verify(fakeFlutterJNI, times(0)).onSurfaceCreated(eq(fakeSurface2));
452 verify(fakeFlutterJNI, times(1)).onSurfaceWindowChanged(eq(fakeSurface2));
453 }
454
455 @Test
457 FlutterRenderer flutterRenderer = engineRule.getFlutterEngine().getRenderer();
458 TextureRegistry.SurfaceProducer producer = flutterRenderer.createSurfaceProducer();
459 FlutterRenderer.ImageReaderSurfaceProducer texture =
461 texture.disableFenceForTest();
462
463 // Returns a null image when one hasn't been produced.
464 assertNull(texture.acquireLatestImage());
465
466 // Give the texture an initial size.
467 texture.setSize(1, 1);
468
469 // Render a frame.
470 Surface surface = texture.getSurface();
471 assertNotNull(surface);
472 Canvas canvas = surface.lockHardwareCanvas();
473 canvas.drawARGB(255, 255, 0, 0);
474 surface.unlockCanvasAndPost(canvas);
475
476 // Let callbacks run.
477 shadowOf(Looper.getMainLooper()).idle();
478
479 // Extract the image and check its size.
480 Image image = texture.acquireLatestImage();
481 assert image != null;
482 assertEquals(1, image.getWidth());
483 assertEquals(1, image.getHeight());
484 image.close();
485
486 // Resize the texture.
487 texture.setSize(5, 5);
488
489 // Render a frame.
490 surface = texture.getSurface();
491 assertNotNull(surface);
492 canvas = surface.lockHardwareCanvas();
493 canvas.drawARGB(255, 255, 0, 0);
494 surface.unlockCanvasAndPost(canvas);
495
496 // Let callbacks run.
497 shadowOf(Looper.getMainLooper()).idle();
498
499 // Extract the image and check its size.
500 image = texture.acquireLatestImage();
501 assert image != null;
502 assertEquals(5, image.getWidth());
503 assertEquals(5, image.getHeight());
504 image.close();
505
506 assertNull(texture.acquireLatestImage());
507
508 texture.release();
509 }
510
511 @Test
513 FlutterRenderer flutterRenderer = engineRule.getFlutterEngine().getRenderer();
514 TextureRegistry.SurfaceProducer producer = flutterRenderer.createSurfaceProducer();
515 FlutterRenderer.ImageReaderSurfaceProducer texture =
517 texture.disableFenceForTest();
518
519 // Returns a null image when one hasn't been produced.
520 assertNull(texture.acquireLatestImage());
521
522 // Give the texture an initial size.
523 texture.setSize(1, 1);
524
525 // Render a frame.
526 Surface surface = texture.getSurface();
527 assertNotNull(surface);
528 Canvas canvas = surface.lockHardwareCanvas();
529 canvas.drawARGB(255, 255, 0, 0);
530 surface.unlockCanvasAndPost(canvas);
531
532 // Resize.
533 texture.setSize(4, 4);
534
535 // Let callbacks run. The rendered frame will manifest here.
536 shadowOf(Looper.getMainLooper()).idle();
537
538 // We acquired the frame produced above.
539 assertNotNull(texture.acquireLatestImage());
540 }
541
542 @Test
544 FlutterRenderer flutterRenderer = engineRule.getFlutterEngine().getRenderer();
545 TextureRegistry.SurfaceProducer producer = flutterRenderer.createSurfaceProducer();
546 FlutterRenderer.ImageReaderSurfaceProducer texture =
548 texture.disableFenceForTest();
549
550 // Returns a null image when one hasn't been produced.
551 assertNull(texture.acquireLatestImage());
552
553 // Give the texture an initial size.
554 texture.setSize(1, 1);
555
556 // Grab the surface so we can render a frame at 1x1 after resizing.
557 Surface surface = texture.getSurface();
558 assertNotNull(surface);
559 Canvas canvas = surface.lockHardwareCanvas();
560 canvas.drawARGB(255, 255, 0, 0);
561 surface.unlockCanvasAndPost(canvas);
562
563 // Let callbacks run, this will produce a single frame.
564 shadowOf(Looper.getMainLooper()).idle();
565
566 assertEquals(1, texture.numImageReaders());
567 assertEquals(1, texture.numImages());
568
569 // Resize.
570 texture.setSize(4, 4);
571
572 // Render a frame at the old size (by using the pre-resized Surface)
573 canvas = surface.lockHardwareCanvas();
574 canvas.drawARGB(255, 255, 0, 0);
575 surface.unlockCanvasAndPost(canvas);
576
577 // Let callbacks run.
578 shadowOf(Looper.getMainLooper()).idle();
579
580 assertEquals(1, texture.numImageReaders());
581 assertEquals(2, texture.numImages());
582
583 // Render a new frame with the current size.
584 surface = texture.getSurface();
585 assertNotNull(surface);
586 canvas = surface.lockHardwareCanvas();
587 canvas.drawARGB(255, 255, 0, 0);
588 surface.unlockCanvasAndPost(canvas);
589
590 // Let callbacks run.
591 shadowOf(Looper.getMainLooper()).idle();
592
593 assertEquals(2, texture.numImageReaders());
594 assertEquals(3, texture.numImages());
595
596 // Acquire first frame.
597 Image produced = texture.acquireLatestImage();
598 assertNotNull(produced);
599 assertEquals(1, produced.getWidth());
600 assertEquals(1, produced.getHeight());
601 assertEquals(2, texture.numImageReaders());
602 assertEquals(2, texture.numImages());
603 // Acquire second frame. This won't result in the first reader being closed because it has
604 // an active image from it.
605 produced = texture.acquireLatestImage();
606 assertNotNull(produced);
607 assertEquals(1, produced.getWidth());
608 assertEquals(1, produced.getHeight());
609 assertEquals(2, texture.numImageReaders());
610 assertEquals(1, texture.numImages());
611 // Acquire third frame. We will now close the first reader.
612 produced = texture.acquireLatestImage();
613 assertNotNull(produced);
614 assertEquals(4, produced.getWidth());
615 assertEquals(4, produced.getHeight());
616 assertEquals(1, texture.numImageReaders());
617 assertEquals(0, texture.numImages());
618
619 // Returns null image when no more images are queued.
620 assertNull(texture.acquireLatestImage());
621 assertEquals(1, texture.numImageReaders());
622 assertEquals(0, texture.numImages());
623 }
624
625 @Test
627 FlutterRenderer flutterRenderer = engineRule.getFlutterEngine().getRenderer();
628 TextureRegistry.SurfaceProducer producer = flutterRenderer.createSurfaceProducer();
629 FlutterRenderer.ImageReaderSurfaceProducer texture =
631
632 texture.disableFenceForTest();
633
634 // Returns a null image when one hasn't been produced.
635 assertNull(texture.acquireLatestImage());
636
637 // Give the texture an initial size.
638 texture.setSize(1, 1);
639
640 // Grab the surface so we can render a frame at 1x1 after resizing.
641 Surface surface = texture.getSurface();
642 assertNotNull(surface);
643 Canvas canvas = surface.lockHardwareCanvas();
644 canvas.drawARGB(255, 255, 0, 0);
645 surface.unlockCanvasAndPost(canvas);
646
647 // Let callbacks run, this will produce a single frame.
648 shadowOf(Looper.getMainLooper()).idle();
649
650 assertEquals(1, texture.numImageReaders());
651 assertEquals(1, texture.numImages());
652
653 // Invoke the onTrimMemory callback with level 0.
654 // This should do nothing.
655 texture.onTrimMemory(0);
656 shadowOf(Looper.getMainLooper()).idle();
657
658 assertEquals(1, texture.numImageReaders());
659 assertEquals(1, texture.numImages());
660 assertEquals(0, texture.numTrims());
661
662 // Invoke the onTrimMemory callback with level 40.
663 // This should result in a trim.
664 texture.onTrimMemory(40);
665 shadowOf(Looper.getMainLooper()).idle();
666
667 assertEquals(0, texture.numImageReaders());
668 assertEquals(0, texture.numImages());
669 assertEquals(1, texture.numTrims());
670
671 // Request the surface, this should result in a new image reader.
672 surface = texture.getSurface();
673 assertEquals(1, texture.numImageReaders());
674 assertEquals(0, texture.numImages());
675 assertEquals(1, texture.numTrims());
676
677 // Render an image.
678 canvas = surface.lockHardwareCanvas();
679 canvas.drawARGB(255, 255, 0, 0);
680 surface.unlockCanvasAndPost(canvas);
681
682 // Let callbacks run, this will produce a single frame.
683 shadowOf(Looper.getMainLooper()).idle();
684
685 assertEquals(1, texture.numImageReaders());
686 assertEquals(1, texture.numImages());
687 assertEquals(1, texture.numTrims());
688 }
689
690 // A 0x0 ImageReader is a runtime error.
691 @Test
693 FlutterRenderer flutterRenderer = engineRule.getFlutterEngine().getRenderer();
694 TextureRegistry.SurfaceProducer producer = flutterRenderer.createSurfaceProducer();
695
696 // Default values.
697 assertEquals(producer.getWidth(), 1);
698 assertEquals(producer.getHeight(), 1);
699
700 // Try setting width and height to 0.
701 producer.setSize(0, 0);
702
703 // Ensure we can still create/get a surface without an exception being raised.
704 assertNotNull(producer.getSurface());
705
706 // Expect clamp to 1.
707 assertEquals(producer.getWidth(), 1);
708 assertEquals(producer.getHeight(), 1);
709 }
710
711 @Test
713 // Force creating a SurfaceTextureSurfaceProducer regardless of Android API version.
714 Surface fakeSurface = mock(Surface.class);
715 try {
716 FlutterRenderer.debugForceSurfaceProducerGlTextures = true;
717 FlutterRenderer flutterRenderer = engineRule.getFlutterEngine().getRenderer();
718 TextureRegistry.SurfaceProducer producer = flutterRenderer.createSurfaceProducer();
719
720 flutterRenderer.startRenderingToSurface(fakeSurface, false);
721
722 // Verify behavior under test.
723 assertEquals(producer.id(), 0);
724 verify(fakeFlutterJNI, times(1)).registerTexture(eq(producer.id()), any());
725 } finally {
726 FlutterRenderer.debugForceSurfaceProducerGlTextures = false;
727 }
728 }
729
730 @Test
732 // This is a placeholder test that will be used to test lifecycle events w/ SurfaceProducer.
733 scenarioRule.getScenario().moveToState(Lifecycle.State.RESUMED);
734 }
735}
static SkISize times(const SkISize &size, float factor)
static bool eq(const SkM44 &a, const SkM44 &b, float tol)
Definition: M44Test.cpp:18
void runFinalization(FlutterRenderer.SurfaceTextureRegistryEntry entry)
SurfaceTextureEntry registerSurfaceTexture(@NonNull SurfaceTexture surfaceTexture)
void startRenderingToSurface(@NonNull Surface surface, boolean onlySwap)
void setViewportMetrics(@NonNull ViewportMetrics viewportMetrics)
VkSurfaceKHR surface
Definition: main.cc:49
default void setOnFrameConsumedListener(@Nullable OnFrameConsumedListener listener)
default void setOnTrimMemoryListener(@Nullable OnTrimMemoryListener listener)
FlTexture * texture
static bool init()
sk_sp< const SkImage > image
Definition: SkRecords.h:269
CanvasImage Image
Definition: dart_ui.cc:55
TRect< Scalar > Rect
Definition: rect.h:769
SIT bool any(const Vec< 1, T > &x)
Definition: SkVx.h:530