From 5300aafdb528a01717b44c0ad2df532a9070d949 Mon Sep 17 00:00:00 2001 From: Matan Lurey Date: Thu, 13 Jun 2024 16:22:54 -0700 Subject: [PATCH] Add a `FlutterEngineRule` (JUnit `TestRule`) and use it in `FlutterRendererTest` (flutter/engine#53361) In https://github.com/flutter/engine/pull/53280, I'm adding lifecycle-aware methods to `SurfaceProducer`. That means, in order to test that it WAI, we'll need to be running in a simulated activity, and be able to switch scenario states (i.e. to `RESUMED`). This was mentioned as well in https://github.com/flutter/flutter/issues/133151 as being something we want to do. This PR adds a `FlutterEngineRule`, which allows the creation of a "real" `FlutterEngine` and an `Intent` that can power `AndroidScenarioRule`. I felt bad doing all of this work for a single `@Test`, so I also refactored the rest of the file and cleaned things up a bit. That said, I'm happy to revert or make changes if we liked how things were setup before. --- .../engine/renderer/FlutterEngineRule.java | 84 ++++++++ .../engine/renderer/FlutterRendererTest.java | 186 ++++++++++-------- .../test_runner/src/main/AndroidManifest.xml | 2 + 3 files changed, 185 insertions(+), 87 deletions(-) create mode 100644 engine/src/flutter/shell/platform/android/test/io/flutter/embedding/engine/renderer/FlutterEngineRule.java diff --git a/engine/src/flutter/shell/platform/android/test/io/flutter/embedding/engine/renderer/FlutterEngineRule.java b/engine/src/flutter/shell/platform/android/test/io/flutter/embedding/engine/renderer/FlutterEngineRule.java new file mode 100644 index 0000000000..56a8955445 --- /dev/null +++ b/engine/src/flutter/shell/platform/android/test/io/flutter/embedding/engine/renderer/FlutterEngineRule.java @@ -0,0 +1,84 @@ +package io.flutter.embedding.engine.renderer; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.content.Intent; +import androidx.test.core.app.ApplicationProvider; +import io.flutter.embedding.android.FlutterActivity; +import io.flutter.embedding.engine.FlutterEngine; +import io.flutter.embedding.engine.FlutterEngineCache; +import io.flutter.embedding.engine.FlutterJNI; +import io.flutter.embedding.engine.loader.FlutterLoader; +import org.junit.rules.TestWatcher; +import org.junit.runner.Description; + +/** + * Prepares and returns a {@link FlutterEngine} and {@link Intent} primed with an engine for tests. + */ +public final class FlutterEngineRule extends TestWatcher { + private static final String cachedEngineId = "flutter_engine_rule_cached_engine"; + private final Context ctx = ApplicationProvider.getApplicationContext(); + private FlutterJNI flutterJNI; + private FlutterEngine flutterEngine; + private boolean jniIsAttached = true; + + @Override + protected void starting(Description description) { + // Setup mock JNI. + flutterJNI = mock(FlutterJNI.class); + when(flutterJNI.isAttached()).thenAnswer(i -> jniIsAttached); + + // We will not try to load plugins in these tests. + FlutterLoader mockFlutterLoader = mock(FlutterLoader.class); + when(mockFlutterLoader.automaticallyRegisterPlugins()).thenReturn(false); + + // Create an engine. + flutterEngine = new FlutterEngine(ctx, mockFlutterLoader, flutterJNI); + + // Place it in the engine cache. + FlutterEngineCache.getInstance().put(cachedEngineId, flutterEngine); + } + + @Override + protected void finished(Description description) { + FlutterEngineCache.getInstance().clear(); + } + + /** + * Returns a Mockito-mocked version of {@link FlutterJNI}. + * + * @return an instance that is already considered attached. + */ + FlutterJNI getFlutterJNI() { + return this.flutterJNI; + } + + /** + * Returns a pre-configured engine. + * + * @return flutter engine using the mock provided by {{@link #getFlutterJNI()}}. + */ + FlutterEngine getFlutterEngine() { + return this.flutterEngine; + } + + /** + * Sets what {@link FlutterJNI#isAttached()} returns. If not invoked, defaults to true. + * + * @param isAttached whether to consider JNI attached. + */ + void setJniIsAttached(boolean isAttached) { + this.jniIsAttached = isAttached; + } + + /** + * Creates an intent with {@link FlutterEngine} instance already provided. + * + * @return intent, i.e. to use with {@link androidx.test.ext.junit.rules.ActivityScenarioRule}. + */ + Intent makeIntent() { + return FlutterActivity.withCachedEngine(cachedEngineId).build(ctx); + } +} diff --git a/engine/src/flutter/shell/platform/android/test/io/flutter/embedding/engine/renderer/FlutterRendererTest.java b/engine/src/flutter/shell/platform/android/test/io/flutter/embedding/engine/renderer/FlutterRendererTest.java index f19da788d3..ed79d7b6a0 100644 --- a/engine/src/flutter/shell/platform/android/test/io/flutter/embedding/engine/renderer/FlutterRendererTest.java +++ b/engine/src/flutter/shell/platform/android/test/io/flutter/embedding/engine/renderer/FlutterRendererTest.java @@ -14,7 +14,6 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; import static org.robolectric.Shadows.shadowOf; import android.graphics.Canvas; @@ -23,12 +22,16 @@ import android.graphics.SurfaceTexture; import android.media.Image; import android.os.Looper; import android.view.Surface; +import androidx.lifecycle.Lifecycle; +import androidx.test.ext.junit.rules.ActivityScenarioRule; import androidx.test.ext.junit.runners.AndroidJUnit4; +import io.flutter.embedding.android.FlutterActivity; import io.flutter.embedding.engine.FlutterJNI; import io.flutter.view.TextureRegistry; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicInteger; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; @@ -37,10 +40,14 @@ import org.robolectric.annotation.Config; @Config(manifest = Config.NONE) @RunWith(AndroidJUnit4.class) public class FlutterRendererTest { + @Rule(order = 1) + public final FlutterEngineRule engineRule = new FlutterEngineRule(); + + @Rule(order = 2) + public final ActivityScenarioRule scenarioRule = + new ActivityScenarioRule<>(engineRule.makeIntent()); private FlutterJNI fakeFlutterJNI; - private Surface fakeSurface; - private Surface fakeSurface2; @Before public void init() { @@ -50,16 +57,14 @@ public class FlutterRendererTest { @Before public void setup() { - fakeFlutterJNI = mock(FlutterJNI.class); - fakeSurface = mock(Surface.class); - fakeSurface2 = mock(Surface.class); + fakeFlutterJNI = engineRule.getFlutterJNI(); } @Test public void itForwardsSurfaceCreationNotificationToFlutterJNI() { // Setup the test. Surface fakeSurface = mock(Surface.class); - FlutterRenderer flutterRenderer = new FlutterRenderer(fakeFlutterJNI); + FlutterRenderer flutterRenderer = engineRule.getFlutterEngine().getRenderer(); // Execute the behavior under test. flutterRenderer.startRenderingToSurface(fakeSurface, false); @@ -72,7 +77,7 @@ public class FlutterRendererTest { public void itForwardsSurfaceChangeNotificationToFlutterJNI() { // Setup the test. Surface fakeSurface = mock(Surface.class); - FlutterRenderer flutterRenderer = new FlutterRenderer(fakeFlutterJNI); + FlutterRenderer flutterRenderer = engineRule.getFlutterEngine().getRenderer(); flutterRenderer.startRenderingToSurface(fakeSurface, false); @@ -87,7 +92,7 @@ public class FlutterRendererTest { public void itForwardsSurfaceDestructionNotificationToFlutterJNI() { // Setup the test. Surface fakeSurface = mock(Surface.class); - FlutterRenderer flutterRenderer = new FlutterRenderer(fakeFlutterJNI); + FlutterRenderer flutterRenderer = engineRule.getFlutterEngine().getRenderer(); flutterRenderer.startRenderingToSurface(fakeSurface, false); @@ -101,8 +106,9 @@ public class FlutterRendererTest { @Test public void itStopsRenderingToOneSurfaceBeforeRenderingToANewSurface() { // Setup the test. + Surface fakeSurface = mock(Surface.class); Surface fakeSurface2 = mock(Surface.class); - FlutterRenderer flutterRenderer = new FlutterRenderer(fakeFlutterJNI); + FlutterRenderer flutterRenderer = engineRule.getFlutterEngine().getRenderer(); flutterRenderer.startRenderingToSurface(fakeSurface, false); @@ -116,7 +122,8 @@ public class FlutterRendererTest { @Test public void itStopsRenderingToSurfaceWhenRequested() { // Setup the test. - FlutterRenderer flutterRenderer = new FlutterRenderer(fakeFlutterJNI); + Surface fakeSurface = mock(Surface.class); + FlutterRenderer flutterRenderer = engineRule.getFlutterEngine().getRenderer(); flutterRenderer.startRenderingToSurface(fakeSurface, false); @@ -130,10 +137,10 @@ public class FlutterRendererTest { @Test public void iStopsRenderingToSurfaceWhenSurfaceAlreadySet() { // Setup the test. - FlutterRenderer flutterRenderer = new FlutterRenderer(fakeFlutterJNI); + Surface fakeSurface = mock(Surface.class); + FlutterRenderer flutterRenderer = engineRule.getFlutterEngine().getRenderer(); flutterRenderer.startRenderingToSurface(fakeSurface, false); - flutterRenderer.startRenderingToSurface(fakeSurface, false); // Verify behavior under test. @@ -143,10 +150,10 @@ public class FlutterRendererTest { @Test public void itNeverStopsRenderingToSurfaceWhenRequested() { // Setup the test. - FlutterRenderer flutterRenderer = new FlutterRenderer(fakeFlutterJNI); + Surface fakeSurface = mock(Surface.class); + FlutterRenderer flutterRenderer = engineRule.getFlutterEngine().getRenderer(); flutterRenderer.startRenderingToSurface(fakeSurface, false); - flutterRenderer.startRenderingToSurface(fakeSurface, true); // Verify behavior under test. @@ -156,13 +163,11 @@ public class FlutterRendererTest { @Test public void itStopsSurfaceTextureCallbackWhenDetached() { // Setup the test. - FlutterRenderer flutterRenderer = new FlutterRenderer(fakeFlutterJNI); - - fakeFlutterJNI.detachFromNativeAndReleaseResources(); + Surface fakeSurface = mock(Surface.class); + FlutterRenderer flutterRenderer = engineRule.getFlutterEngine().getRenderer(); FlutterRenderer.SurfaceTextureRegistryEntry entry = (FlutterRenderer.SurfaceTextureRegistryEntry) flutterRenderer.createSurfaceTexture(); - flutterRenderer.startRenderingToSurface(fakeSurface, false); // Execute the behavior under test. @@ -175,9 +180,8 @@ public class FlutterRendererTest { @Test public void itRegistersExistingSurfaceTexture() { // Setup the test. - FlutterRenderer flutterRenderer = new FlutterRenderer(fakeFlutterJNI); - - fakeFlutterJNI.detachFromNativeAndReleaseResources(); + Surface fakeSurface = mock(Surface.class); + FlutterRenderer flutterRenderer = engineRule.getFlutterEngine().getRenderer(); SurfaceTexture surfaceTexture = new SurfaceTexture(0); @@ -197,11 +201,8 @@ public class FlutterRendererTest { @Test public void itUnregistersTextureWhenSurfaceTextureFinalized() { // Setup the test. - FlutterJNI fakeFlutterJNI = mock(FlutterJNI.class); - when(fakeFlutterJNI.isAttached()).thenReturn(true); - FlutterRenderer flutterRenderer = new FlutterRenderer(fakeFlutterJNI); - - fakeFlutterJNI.detachFromNativeAndReleaseResources(); + Surface fakeSurface = mock(Surface.class); + FlutterRenderer flutterRenderer = engineRule.getFlutterEngine().getRenderer(); FlutterRenderer.SurfaceTextureRegistryEntry entry = (FlutterRenderer.SurfaceTextureRegistryEntry) flutterRenderer.createSurfaceTexture(); @@ -223,18 +224,15 @@ public class FlutterRendererTest { @Test public void itStopsUnregisteringTextureWhenDetached() { // Setup the test. - FlutterJNI fakeFlutterJNI = mock(FlutterJNI.class); - when(fakeFlutterJNI.isAttached()).thenReturn(false); - FlutterRenderer flutterRenderer = new FlutterRenderer(fakeFlutterJNI); - - fakeFlutterJNI.detachFromNativeAndReleaseResources(); + Surface fakeSurface = mock(Surface.class); + engineRule.setJniIsAttached(false); + FlutterRenderer flutterRenderer = engineRule.getFlutterEngine().getRenderer(); FlutterRenderer.SurfaceTextureRegistryEntry entry = (FlutterRenderer.SurfaceTextureRegistryEntry) flutterRenderer.createSurfaceTexture(); long id = entry.id(); flutterRenderer.startRenderingToSurface(fakeSurface, false); - flutterRenderer.stopRenderingToSurface(); // Execute the behavior under test. @@ -246,18 +244,17 @@ public class FlutterRendererTest { verify(fakeFlutterJNI, times(0)).unregisterTexture(eq(id)); } + /** @noinspection FinalizeCalledExplicitly */ void runFinalization(FlutterRenderer.SurfaceTextureRegistryEntry entry) { CountDownLatch latch = new CountDownLatch(1); Thread fakeFinalizer = new Thread( - new Runnable() { - public void run() { - try { - entry.finalize(); - latch.countDown(); - } catch (Throwable e) { - // do nothing - } + () -> { + try { + entry.finalize(); + latch.countDown(); + } catch (Throwable e) { + // do nothing } }); fakeFinalizer.start(); @@ -270,8 +267,14 @@ public class FlutterRendererTest { @Test public void itConvertsDisplayFeatureArrayToPrimitiveArrays() { - // Setup the test. + // Intentionally do not use 'engineRule' in this test, because we are testing a very narrow + // API (the side-effects of 'setViewportMetrics'). Under normal construction, the engine will + // invoke 'setViewportMetrics' a number of times automatically, making testing the side-effects + // of the method call more difficult than needed. + FlutterJNI fakeFlutterJNI = mock(FlutterJNI.class); FlutterRenderer flutterRenderer = new FlutterRenderer(fakeFlutterJNI); + + // Setup the test. FlutterRenderer.ViewportMetrics metrics = new FlutterRenderer.ViewportMetrics(); metrics.width = 1000; metrics.height = 1000; @@ -332,16 +335,10 @@ public class FlutterRendererTest { @Test public void itNotifyImageFrameListener() { // Setup the test. - FlutterRenderer flutterRenderer = new FlutterRenderer(fakeFlutterJNI); + FlutterRenderer flutterRenderer = engineRule.getFlutterEngine().getRenderer(); AtomicInteger invocationCount = new AtomicInteger(0); - final TextureRegistry.OnFrameConsumedListener listener = - new TextureRegistry.OnFrameConsumedListener() { - @Override - public void onFrameConsumed() { - invocationCount.incrementAndGet(); - } - }; + final TextureRegistry.OnFrameConsumedListener listener = invocationCount::incrementAndGet; FlutterRenderer.SurfaceTextureRegistryEntry entry = (FlutterRenderer.SurfaceTextureRegistryEntry) flutterRenderer.createSurfaceTexture(); @@ -357,7 +354,7 @@ public class FlutterRendererTest { @Test public void itAddsListenerWhenSurfaceTextureEntryCreated() { // Setup the test. - FlutterRenderer flutterRenderer = spy(new FlutterRenderer(fakeFlutterJNI)); + FlutterRenderer flutterRenderer = spy(engineRule.getFlutterEngine().getRenderer()); // Execute the behavior under test. FlutterRenderer.SurfaceTextureRegistryEntry entry = @@ -370,7 +367,7 @@ public class FlutterRendererTest { @Test public void itRemovesListenerWhenSurfaceTextureEntryReleased() { // Setup the test. - FlutterRenderer flutterRenderer = spy(new FlutterRenderer(fakeFlutterJNI)); + FlutterRenderer flutterRenderer = spy(engineRule.getFlutterEngine().getRenderer()); FlutterRenderer.SurfaceTextureRegistryEntry entry = (FlutterRenderer.SurfaceTextureRegistryEntry) flutterRenderer.createSurfaceTexture(); @@ -384,16 +381,11 @@ public class FlutterRendererTest { @Test public void itNotifySurfaceTextureEntryWhenMemoryPressureWarning() { // Setup the test. - FlutterRenderer flutterRenderer = new FlutterRenderer(fakeFlutterJNI); + FlutterRenderer flutterRenderer = engineRule.getFlutterEngine().getRenderer(); AtomicInteger invocationCount = new AtomicInteger(0); final TextureRegistry.OnTrimMemoryListener listener = - new TextureRegistry.OnTrimMemoryListener() { - @Override - public void onTrimMemory(int level) { - invocationCount.incrementAndGet(); - } - }; + level -> invocationCount.incrementAndGet(); FlutterRenderer.SurfaceTextureRegistryEntry entry = (FlutterRenderer.SurfaceTextureRegistryEntry) flutterRenderer.createSurfaceTexture(); @@ -409,7 +401,8 @@ public class FlutterRendererTest { @Test public void itDoesDispatchSurfaceDestructionNotificationOnlyOnce() { // Setup the test. - FlutterRenderer flutterRenderer = new FlutterRenderer(fakeFlutterJNI); + Surface fakeSurface = mock(Surface.class); + FlutterRenderer flutterRenderer = engineRule.getFlutterEngine().getRenderer(); flutterRenderer.startRenderingToSurface(fakeSurface, false); @@ -424,7 +417,8 @@ public class FlutterRendererTest { @Test public void itInvokesCreatesSurfaceWhenStartingRendering() { - FlutterRenderer flutterRenderer = new FlutterRenderer(fakeFlutterJNI); + Surface fakeSurface = mock(Surface.class); + FlutterRenderer flutterRenderer = engineRule.getFlutterEngine().getRenderer(); flutterRenderer.startRenderingToSurface(fakeSurface, false); verify(fakeFlutterJNI, times(1)).onSurfaceCreated(eq(fakeSurface)); @@ -432,7 +426,9 @@ public class FlutterRendererTest { @Test public void itDoesNotInvokeCreatesSurfaceWhenResumingRendering() { - FlutterRenderer flutterRenderer = new FlutterRenderer(fakeFlutterJNI); + Surface fakeSurface = mock(Surface.class); + Surface fakeSurface2 = mock(Surface.class); + FlutterRenderer flutterRenderer = engineRule.getFlutterEngine().getRenderer(); // The following call sequence mimics the behaviour of FlutterView when it exits from hybrid // composition mode. @@ -458,9 +454,10 @@ public class FlutterRendererTest { @Test public void ImageReaderSurfaceProducerProducesImageOfCorrectSize() { - FlutterRenderer flutterRenderer = new FlutterRenderer(fakeFlutterJNI); + FlutterRenderer flutterRenderer = engineRule.getFlutterEngine().getRenderer(); + TextureRegistry.SurfaceProducer producer = flutterRenderer.createSurfaceProducer(); FlutterRenderer.ImageReaderSurfaceProducer texture = - flutterRenderer.new ImageReaderSurfaceProducer(0); + (FlutterRenderer.ImageReaderSurfaceProducer) producer; texture.disableFenceForTest(); // Returns a null image when one hasn't been produced. @@ -481,6 +478,7 @@ public class FlutterRendererTest { // Extract the image and check its size. Image image = texture.acquireLatestImage(); + assert image != null; assertEquals(1, image.getWidth()); assertEquals(1, image.getHeight()); image.close(); @@ -500,6 +498,7 @@ public class FlutterRendererTest { // Extract the image and check its size. image = texture.acquireLatestImage(); + assert image != null; assertEquals(5, image.getWidth()); assertEquals(5, image.getHeight()); image.close(); @@ -510,10 +509,11 @@ public class FlutterRendererTest { } @Test - public void ImageReaderSurfaceProducerDoesNotDropFramesWhenResizeInflight() { - FlutterRenderer flutterRenderer = new FlutterRenderer(fakeFlutterJNI); + public void ImageReaderSurfaceProducerDoesNotDropFramesWhenResizeInFlight() { + FlutterRenderer flutterRenderer = engineRule.getFlutterEngine().getRenderer(); + TextureRegistry.SurfaceProducer producer = flutterRenderer.createSurfaceProducer(); FlutterRenderer.ImageReaderSurfaceProducer texture = - flutterRenderer.new ImageReaderSurfaceProducer(0); + (FlutterRenderer.ImageReaderSurfaceProducer) producer; texture.disableFenceForTest(); // Returns a null image when one hasn't been produced. @@ -541,9 +541,10 @@ public class FlutterRendererTest { @Test public void ImageReaderSurfaceProducerImageReadersAndImagesCount() { - FlutterRenderer flutterRenderer = new FlutterRenderer(fakeFlutterJNI); + FlutterRenderer flutterRenderer = engineRule.getFlutterEngine().getRenderer(); + TextureRegistry.SurfaceProducer producer = flutterRenderer.createSurfaceProducer(); FlutterRenderer.ImageReaderSurfaceProducer texture = - flutterRenderer.new ImageReaderSurfaceProducer(0); + (FlutterRenderer.ImageReaderSurfaceProducer) producer; texture.disableFenceForTest(); // Returns a null image when one hasn't been produced. @@ -623,9 +624,11 @@ public class FlutterRendererTest { @Test public void ImageReaderSurfaceProducerTrimMemoryCallback() { - FlutterRenderer flutterRenderer = new FlutterRenderer(fakeFlutterJNI); + FlutterRenderer flutterRenderer = engineRule.getFlutterEngine().getRenderer(); + TextureRegistry.SurfaceProducer producer = flutterRenderer.createSurfaceProducer(); FlutterRenderer.ImageReaderSurfaceProducer texture = - flutterRenderer.new ImageReaderSurfaceProducer(0); + (FlutterRenderer.ImageReaderSurfaceProducer) producer; + texture.disableFenceForTest(); // Returns a null image when one hasn't been produced. @@ -687,37 +690,46 @@ public class FlutterRendererTest { // A 0x0 ImageReader is a runtime error. @Test public void ImageReaderSurfaceProducerClampsWidthAndHeightTo1() { - FlutterRenderer flutterRenderer = new FlutterRenderer(fakeFlutterJNI); - FlutterRenderer.ImageReaderSurfaceProducer texture = - flutterRenderer.new ImageReaderSurfaceProducer(0); + FlutterRenderer flutterRenderer = engineRule.getFlutterEngine().getRenderer(); + TextureRegistry.SurfaceProducer producer = flutterRenderer.createSurfaceProducer(); // Default values. - assertEquals(texture.getWidth(), 1); - assertEquals(texture.getHeight(), 1); + assertEquals(producer.getWidth(), 1); + assertEquals(producer.getHeight(), 1); // Try setting width and height to 0. - texture.setSize(0, 0); + producer.setSize(0, 0); // Ensure we can still create/get a surface without an exception being raised. - assertNotNull(texture.getSurface()); + assertNotNull(producer.getSurface()); // Expect clamp to 1. - assertEquals(texture.getWidth(), 1); - assertEquals(texture.getHeight(), 1); + assertEquals(producer.getWidth(), 1); + assertEquals(producer.getHeight(), 1); } @Test public void SurfaceTextureSurfaceProducerCreatesAConnectedTexture() { // Force creating a SurfaceTextureSurfaceProducer regardless of Android API version. - FlutterRenderer.debugForceSurfaceProducerGlTextures = true; + Surface fakeSurface = mock(Surface.class); + try { + FlutterRenderer.debugForceSurfaceProducerGlTextures = true; + FlutterRenderer flutterRenderer = engineRule.getFlutterEngine().getRenderer(); + TextureRegistry.SurfaceProducer producer = flutterRenderer.createSurfaceProducer(); - FlutterRenderer flutterRenderer = new FlutterRenderer(fakeFlutterJNI); - TextureRegistry.SurfaceProducer producer = flutterRenderer.createSurfaceProducer(); + flutterRenderer.startRenderingToSurface(fakeSurface, false); - flutterRenderer.startRenderingToSurface(fakeSurface, false); + // Verify behavior under test. + assertEquals(producer.id(), 0); + verify(fakeFlutterJNI, times(1)).registerTexture(eq(producer.id()), any()); + } finally { + FlutterRenderer.debugForceSurfaceProducerGlTextures = false; + } + } - // Verify behavior under test. - assertEquals(producer.id(), 0); - verify(fakeFlutterJNI, times(1)).registerTexture(eq(producer.id()), any()); + @Test + public void CanLaunchActivityUsingFlutterEngine() { + // This is a placeholder test that will be used to test lifecycle events w/ SurfaceProducer. + scenarioRule.getScenario().moveToState(Lifecycle.State.RESUMED); } } diff --git a/engine/src/flutter/shell/platform/android/test_runner/src/main/AndroidManifest.xml b/engine/src/flutter/shell/platform/android/test_runner/src/main/AndroidManifest.xml index 57bdeee858..65ca9afc77 100644 --- a/engine/src/flutter/shell/platform/android/test_runner/src/main/AndroidManifest.xml +++ b/engine/src/flutter/shell/platform/android/test_runner/src/main/AndroidManifest.xml @@ -2,6 +2,8 @@ + +