1package io.flutter.embedding.engine.renderer;
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.mockito.Mockito.when;
18import static org.robolectric.Shadows.shadowOf;
22import android.graphics.SurfaceTexture;
26import androidx.test.ext.junit.runners.AndroidJUnit4;
27import io.flutter.embedding.engine.FlutterJNI;
28import io.flutter.view.TextureRegistry;
29import java.util.concurrent.CountDownLatch;
30import java.util.concurrent.atomic.AtomicInteger;
31import org.junit.Before;
33import org.junit.runner.RunWith;
34import org.mockito.ArgumentCaptor;
35import org.robolectric.annotation.Config;
38@RunWith(AndroidJUnit4.class)
54 fakeSurface = mock(
Surface.class);
55 fakeSurface2 = mock(
Surface.class);
68 verify(fakeFlutterJNI,
times(1)).onSurfaceCreated(
eq(fakeSurface));
83 verify(fakeFlutterJNI,
times(1)).onSurfaceChanged(
eq(100),
eq(50));
98 verify(fakeFlutterJNI,
times(1)).onSurfaceDestroyed();
113 verify(fakeFlutterJNI,
times(1)).onSurfaceDestroyed();
127 verify(fakeFlutterJNI,
times(1)).onSurfaceDestroyed();
140 verify(fakeFlutterJNI,
times(1)).onSurfaceDestroyed();
153 verify(fakeFlutterJNI, never()).onSurfaceDestroyed();
163 FlutterRenderer.SurfaceTextureRegistryEntry entry =
172 verify(fakeFlutterJNI,
times(0)).markTextureFrameAvailable(
eq(entry.id()));
182 SurfaceTexture surfaceTexture =
new SurfaceTexture(0);
185 FlutterRenderer.SurfaceTextureRegistryEntry entry =
192 assertEquals(surfaceTexture, entry.surfaceTexture());
194 verify(fakeFlutterJNI,
times(1)).registerTexture(
eq(entry.id()),
eq(entry.textureWrapper()));
201 when(fakeFlutterJNI.
isAttached()).thenReturn(
true);
206 FlutterRenderer.SurfaceTextureRegistryEntry entry =
208 long id = entry.id();
213 runFinalization(entry);
215 shadowOf(Looper.getMainLooper()).idle();
220 verify(fakeFlutterJNI,
times(1)).unregisterTexture(
eq(
id));
227 when(fakeFlutterJNI.
isAttached()).thenReturn(
false);
232 FlutterRenderer.SurfaceTextureRegistryEntry entry =
234 long id = entry.id();
241 runFinalization(entry);
243 shadowOf(Looper.getMainLooper()).idle();
246 verify(fakeFlutterJNI,
times(0)).unregisterTexture(
eq(
id));
250 CountDownLatch latch =
new CountDownLatch(1);
251 Thread fakeFinalizer =
258 }
catch (Throwable e) {
263 fakeFinalizer.start();
266 }
catch (InterruptedException e) {
276 metrics.width = 1000;
277 metrics.height = 1000;
278 metrics.devicePixelRatio = 2;
281 new Rect(10, 20, 30, 40),
284 metrics.displayFeatures.add(
292 ArgumentCaptor<int[]> boundsCaptor = ArgumentCaptor.forClass(
int[].
class);
293 ArgumentCaptor<int[]> typeCaptor = ArgumentCaptor.forClass(
int[].
class);
294 ArgumentCaptor<int[]> stateCaptor = ArgumentCaptor.forClass(
int[].
class);
295 verify(fakeFlutterJNI)
313 boundsCaptor.capture(),
314 typeCaptor.capture(),
315 stateCaptor.capture());
317 assertArrayEquals(
new int[] {10, 20, 30, 40, 50, 60, 70, 80}, boundsCaptor.getValue());
321 FlutterRenderer.DisplayFeatureType.CUTOUT.encodedValue
323 typeCaptor.getValue());
327 FlutterRenderer.DisplayFeatureState.UNKNOWN.encodedValue
329 stateCaptor.getValue());
337 AtomicInteger invocationCount =
new AtomicInteger(0);
338 final TextureRegistry.OnFrameConsumedListener listener =
339 new TextureRegistry.OnFrameConsumedListener() {
341 public void onFrameConsumed() {
342 invocationCount.incrementAndGet();
346 FlutterRenderer.SurfaceTextureRegistryEntry entry =
348 entry.setOnFrameConsumedListener(listener);
351 entry.textureWrapper().updateTexImage();
354 assertEquals(1, invocationCount.get());
363 FlutterRenderer.SurfaceTextureRegistryEntry entry =
367 verify(flutterRenderer,
times(1)).addOnTrimMemoryListener(entry);
374 FlutterRenderer.SurfaceTextureRegistryEntry entry =
381 verify(flutterRenderer,
times(1)).removeOnTrimMemoryListener(entry);
389 AtomicInteger invocationCount =
new AtomicInteger(0);
390 final TextureRegistry.OnTrimMemoryListener listener =
391 new TextureRegistry.OnTrimMemoryListener() {
393 public void onTrimMemory(
int level) {
394 invocationCount.incrementAndGet();
398 FlutterRenderer.SurfaceTextureRegistryEntry entry =
400 entry.setOnTrimMemoryListener(listener);
406 assertEquals(1, invocationCount.get());
422 verify(fakeFlutterJNI,
times(1)).onSurfaceDestroyed();
430 verify(fakeFlutterJNI,
times(1)).onSurfaceCreated(
eq(fakeSurface));
442 verify(fakeFlutterJNI,
times(1)).onSurfaceCreated(
eq(fakeSurface));
443 verify(fakeFlutterJNI,
times(0)).onSurfaceWindowChanged(
eq(fakeSurface));
447 verify(fakeFlutterJNI,
times(1)).onSurfaceCreated(
eq(fakeSurface));
448 verify(fakeFlutterJNI,
times(0)).onSurfaceWindowChanged(
eq(fakeSurface));
449 verify(fakeFlutterJNI,
times(0)).onSurfaceCreated(
eq(fakeSurface2));
450 verify(fakeFlutterJNI,
times(1)).onSurfaceWindowChanged(
eq(fakeSurface2));
453 verify(fakeFlutterJNI,
times(1)).onSurfaceCreated(
eq(fakeSurface));
454 verify(fakeFlutterJNI,
times(1)).onSurfaceWindowChanged(
eq(fakeSurface));
455 verify(fakeFlutterJNI,
times(0)).onSurfaceCreated(
eq(fakeSurface2));
456 verify(fakeFlutterJNI,
times(1)).onSurfaceWindowChanged(
eq(fakeSurface2));
462 FlutterRenderer.ImageReaderSurfaceProducer
texture =
463 flutterRenderer.new ImageReaderSurfaceProducer(0);
467 assertNull(
texture.acquireLatestImage());
475 Canvas canvas =
surface.lockHardwareCanvas();
476 canvas.drawARGB(255, 255, 0, 0);
477 surface.unlockCanvasAndPost(canvas);
480 shadowOf(Looper.getMainLooper()).idle();
484 assertEquals(1,
image.getWidth());
485 assertEquals(1,
image.getHeight());
494 canvas =
surface.lockHardwareCanvas();
495 canvas.drawARGB(255, 255, 0, 0);
496 surface.unlockCanvasAndPost(canvas);
499 shadowOf(Looper.getMainLooper()).idle();
503 assertEquals(5,
image.getWidth());
504 assertEquals(5,
image.getHeight());
507 assertNull(
texture.acquireLatestImage());
515 FlutterRenderer.ImageReaderSurfaceProducer
texture =
516 flutterRenderer.new ImageReaderSurfaceProducer(0);
520 assertNull(
texture.acquireLatestImage());
528 Canvas canvas =
surface.lockHardwareCanvas();
529 canvas.drawARGB(255, 255, 0, 0);
530 surface.unlockCanvasAndPost(canvas);
536 shadowOf(Looper.getMainLooper()).idle();
539 assertNotNull(
texture.acquireLatestImage());
545 FlutterRenderer.ImageReaderSurfaceProducer
texture =
546 flutterRenderer.new ImageReaderSurfaceProducer(0);
550 assertNull(
texture.acquireLatestImage());
558 Canvas canvas =
surface.lockHardwareCanvas();
559 canvas.drawARGB(255, 255, 0, 0);
560 surface.unlockCanvasAndPost(canvas);
563 shadowOf(Looper.getMainLooper()).idle();
565 assertEquals(1,
texture.numImageReaders());
566 assertEquals(1,
texture.numImages());
572 canvas =
surface.lockHardwareCanvas();
573 canvas.drawARGB(255, 255, 0, 0);
574 surface.unlockCanvasAndPost(canvas);
577 shadowOf(Looper.getMainLooper()).idle();
579 assertEquals(1,
texture.numImageReaders());
580 assertEquals(2,
texture.numImages());
585 canvas =
surface.lockHardwareCanvas();
586 canvas.drawARGB(255, 255, 0, 0);
587 surface.unlockCanvasAndPost(canvas);
590 shadowOf(Looper.getMainLooper()).idle();
592 assertEquals(2,
texture.numImageReaders());
593 assertEquals(3,
texture.numImages());
596 Image produced =
texture.acquireLatestImage();
597 assertNotNull(produced);
598 assertEquals(1, produced.getWidth());
599 assertEquals(1, produced.getHeight());
600 assertEquals(2,
texture.numImageReaders());
601 assertEquals(2,
texture.numImages());
604 produced =
texture.acquireLatestImage();
605 assertNotNull(produced);
606 assertEquals(1, produced.getWidth());
607 assertEquals(1, produced.getHeight());
608 assertEquals(2,
texture.numImageReaders());
609 assertEquals(1,
texture.numImages());
611 produced =
texture.acquireLatestImage();
612 assertNotNull(produced);
613 assertEquals(4, produced.getWidth());
614 assertEquals(4, produced.getHeight());
615 assertEquals(1,
texture.numImageReaders());
616 assertEquals(0,
texture.numImages());
619 assertNull(
texture.acquireLatestImage());
620 assertEquals(1,
texture.numImageReaders());
621 assertEquals(0,
texture.numImages());
627 FlutterRenderer.ImageReaderSurfaceProducer
texture =
628 flutterRenderer.new ImageReaderSurfaceProducer(0);
632 assertNull(
texture.acquireLatestImage());
640 Canvas canvas =
surface.lockHardwareCanvas();
641 canvas.drawARGB(255, 255, 0, 0);
642 surface.unlockCanvasAndPost(canvas);
645 shadowOf(Looper.getMainLooper()).idle();
647 assertEquals(1,
texture.numImageReaders());
648 assertEquals(1,
texture.numImages());
653 shadowOf(Looper.getMainLooper()).idle();
655 assertEquals(1,
texture.numImageReaders());
656 assertEquals(1,
texture.numImages());
663 FlutterRenderer.ImageReaderSurfaceProducer
texture =
664 flutterRenderer.new ImageReaderSurfaceProducer(0);
667 assertEquals(
texture.getWidth(), 1);
668 assertEquals(
texture.getHeight(), 1);
674 assertNotNull(
texture.getSurface());
677 assertEquals(
texture.getWidth(), 1);
678 assertEquals(
texture.getHeight(), 1);
684 FlutterRenderer.debugForceSurfaceProducerGlTextures =
true;
692 assertEquals(producer.id(), 0);
693 verify(fakeFlutterJNI,
times(1)).registerTexture(
eq(producer.id()), any());
static SkISize times(const SkISize &size, float factor)
static bool eq(const SkM44 &a, const SkM44 &b, float tol)
void detachFromNativeAndReleaseResources()
void iStopsRenderingToSurfaceWhenSurfaceAlreadySet()
void itAddsListenerWhenSurfaceTextureEntryCreated()
void itDoesNotInvokeCreatesSurfaceWhenResumingRendering()
void ImageReaderSurfaceProducerTrimMemoryCallback()
void itStopsUnregisteringTextureWhenDetached()
void itStopsSurfaceTextureCallbackWhenDetached()
void itNeverStopsRenderingToSurfaceWhenRequested()
void ImageReaderSurfaceProducerImageReadersAndImagesCount()
void itConvertsDisplayFeatureArrayToPrimitiveArrays()
void ImageReaderSurfaceProducerClampsWidthAndHeightTo1()
void itForwardsSurfaceDestructionNotificationToFlutterJNI()
void itNotifyImageFrameListener()
void itForwardsSurfaceChangeNotificationToFlutterJNI()
void itDoesDispatchSurfaceDestructionNotificationOnlyOnce()
void ImageReaderSurfaceProducerDoesNotDropFramesWhenResizeInflight()
void runFinalization(FlutterRenderer.SurfaceTextureRegistryEntry entry)
void SurfaceTextureSurfaceProducerCreatesAConnectedTexture()
void itStopsRenderingToSurfaceWhenRequested()
void itStopsRenderingToOneSurfaceBeforeRenderingToANewSurface()
void itNotifySurfaceTextureEntryWhenMemoryPressureWarning()
void itRemovesListenerWhenSurfaceTextureEntryReleased()
void itForwardsSurfaceCreationNotificationToFlutterJNI()
void itRegistersExistingSurfaceTexture()
void itInvokesCreatesSurfaceWhenStartingRendering()
void ImageReaderSurfaceProducerProducesImageOfCorrectSize()
void itUnregistersTextureWhenSurfaceTextureFinalized()
List< DisplayFeature > displayFeatures
SurfaceProducer createSurfaceProducer()
SurfaceTextureEntry registerSurfaceTexture(@NonNull SurfaceTexture surfaceTexture)
void stopRenderingToSurface()
void surfaceChanged(int width, int height)
void startRenderingToSurface(@NonNull Surface surface, boolean onlySwap)
SurfaceTextureEntry createSurfaceTexture()
void onTrimMemory(int level)
void setViewportMetrics(@NonNull ViewportMetrics viewportMetrics)