Migrate `camera/android` from `SurfaceTexture`->`SurfaceProducer`. (#6461)

_**WIP**: We do not plan to land this PR until the next stable release (>= April 3rd 2024)_.

Work towards https://github.com/flutter/flutter/issues/145930.

## Details

Migrates uses of `createSurfaceTexture` to `createSurfaceProducer`, which is intended to have no change in behavior, but _does_ change the backend rendering path, so it will require more testing (and we're also open to minor API renames or changes before it becomes stable).

## Background 

Android plugins previously requested a `SurfaceTexture` from the Android embedder, and used that to produce a `Surface` to render external textures on (i.e. `video_player`).  This worked because 100% of Flutter applications on Android used OpenGLES (via our Skia backend), and `SurfaceTexture` is actually an (opaque) OpenGLES-texture.

Starting soon (roughly ~Q3, this is not a guarantee and just an estimate), Flutter on Android will start to use our new Impeller graphics backend, which on newer devices (`>= API_VERSION_28`), will default to the Vulkan, _not_ OpenGLES. In other words, `SurfaceTexture` will cease to work (it is possible, but non-trivial, to map an OpenGLES texture over to Vulkan).

After consultation with the Android team, they helped us understand that vending `SurfaceTexture` (the _consumer-side_ API) was never the right abstraction, and we should have been vending the _producer-side_ API, or `Surface` directly. The new `SurfaceProducer` API is exactly that - it generates a `Surface`, and similar to our platform view strategy, picks the "right" _consumer-side_ implementation details _for_ the user/plugin packages.

The new `SurfaceProducer` API has 2 possible rendering types (as an implementation detail):

- `SurfaceTexture`, for older OpenGLES devices, which works exactly as it does today.
- `ImageReader`, for newer OpenGLES _or_ Vulkan devices.

These are some subtle nuances in how these two APIs work differently (one example: https://github.com/flutter/flutter/issues/144407), but our theory at this point is we don't expect these changes to be observed by any users, and we have other ideas if necessary. 

> [!NOTE]
> These invariants are [tested on CI in `flutter/engine`](https://github.com/flutter/engine/tree/main/testing/scenario_app/android#ci-configuration).

Points of contact: 
- @matanlurey or @jonahwilliams  (Flutter Engine)
- @johnmccutchan or @reidbaker  (Flutter on Android)
diff --git a/packages/camera/camera_android/CHANGELOG.md b/packages/camera/camera_android/CHANGELOG.md
index dbf3789..102fe72 100644
--- a/packages/camera/camera_android/CHANGELOG.md
+++ b/packages/camera/camera_android/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.10.9+4
+
+* [Supports Impeller](https://docs.flutter.dev/release/breaking-changes/android-surface-plugins).
+
 ## 0.10.9+3
 
 * Updates minimum supported SDK version to Flutter 3.22/Dart 3.4.
@@ -36,7 +40,7 @@
 
 ## 0.10.8+14
 
-* Fixes `pausePreview` null pointer error. `pausePreview` should not be called 
+* Fixes `pausePreview` null pointer error. `pausePreview` should not be called
   when camera is closed or not configured.
 * Updates minimum supported SDK version to Flutter 3.10/Dart 3.0.
 
diff --git a/packages/camera/camera_android/android/src/main/java/io/flutter/plugins/camera/Camera.java b/packages/camera/camera_android/android/src/main/java/io/flutter/plugins/camera/Camera.java
index 7668ec9..52c5e59 100644
--- a/packages/camera/camera_android/android/src/main/java/io/flutter/plugins/camera/Camera.java
+++ b/packages/camera/camera_android/android/src/main/java/io/flutter/plugins/camera/Camera.java
@@ -9,7 +9,6 @@
 import android.app.Activity;
 import android.content.Context;
 import android.graphics.ImageFormat;
-import android.graphics.SurfaceTexture;
 import android.hardware.camera2.CameraAccessException;
 import android.hardware.camera2.CameraCaptureSession;
 import android.hardware.camera2.CameraDevice;
@@ -63,7 +62,7 @@
 import io.flutter.plugins.camera.media.MediaRecorderBuilder;
 import io.flutter.plugins.camera.types.CameraCaptureProperties;
 import io.flutter.plugins.camera.types.CaptureTimeoutsWrapper;
-import io.flutter.view.TextureRegistry.SurfaceTextureEntry;
+import io.flutter.view.TextureRegistry;
 import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
@@ -113,7 +112,7 @@
    */
   @VisibleForTesting int initialCameraFacing;
 
-  @VisibleForTesting final SurfaceTextureEntry flutterTexture;
+  @VisibleForTesting final TextureRegistry.SurfaceProducer surfaceProducer;
   private final VideoCaptureSettings videoCaptureSettings;
   private final Context applicationContext;
   final DartMessenger dartMessenger;
@@ -214,17 +213,16 @@
 
   public Camera(
       final Activity activity,
-      final SurfaceTextureEntry flutterTexture,
+      final TextureRegistry.SurfaceProducer surfaceProducer,
       final CameraFeatureFactory cameraFeatureFactory,
       final DartMessenger dartMessenger,
       final CameraProperties cameraProperties,
       final VideoCaptureSettings videoCaptureSettings) {
-
     if (activity == null) {
       throw new IllegalStateException("No activity available!");
     }
     this.activity = activity;
-    this.flutterTexture = flutterTexture;
+    this.surfaceProducer = surfaceProducer;
     this.dartMessenger = dartMessenger;
     this.applicationContext = activity.getApplicationContext();
     this.cameraProperties = cameraProperties;
@@ -243,7 +241,6 @@
     if (videoCaptureSettings.fps != null && videoCaptureSettings.fps.intValue() > 0) {
       recordingFps = videoCaptureSettings.fps;
     } else {
-
       if (SdkCapabilityChecker.supportsEncoderProfiles()) {
         EncoderProfiles encoderProfiles = getRecordingProfile();
         if (encoderProfiles != null && encoderProfiles.getVideoProfiles().size() > 0) {
@@ -256,7 +253,6 @@
     }
 
     if (recordingFps != null && recordingFps.intValue() > 0) {
-
       final FpsRangeFeature fpsRange = new FpsRangeFeature(cameraProperties);
       fpsRange.setValue(new Range<Integer>(recordingFps, recordingFps));
       this.cameraFeatures.setFpsRange(fpsRange);
@@ -307,8 +303,9 @@
 
     MediaRecorderBuilder mediaRecorderBuilder;
 
-    // TODO(camsim99): Revert changes that allow legacy code to be used when recordingProfile is null
-    // once this has largely been fixed on the Android side. https://github.com/flutter/flutter/issues/119668
+    // TODO(camsim99): Revert changes that allow legacy code to be used when recordingProfile is
+    // null once this has largely been fixed on the Android side.
+    // https://github.com/flutter/flutter/issues/119668
     if (SdkCapabilityChecker.supportsEncoderProfiles() && getRecordingProfile() != null) {
       mediaRecorderBuilder =
           new MediaRecorderBuilder(
@@ -386,7 +383,8 @@
             cameraDevice = new DefaultCameraDeviceWrapper(device);
             try {
               startPreview();
-              if (!recordingVideo) { // only send initialization if we werent already recording and switching cameras
+              if (!recordingVideo) { // only send initialization if we werent already recording and
+                // switching cameras
                 dartMessenger.sendCameraInitializedEvent(
                     resolutionFeature.getPreviewSize().getWidth(),
                     resolutionFeature.getPreviewSize().getHeight(),
@@ -470,11 +468,10 @@
 
     // Build Flutter surface to render to.
     ResolutionFeature resolutionFeature = cameraFeatures.getResolution();
-    SurfaceTexture surfaceTexture = flutterTexture.surfaceTexture();
-    surfaceTexture.setDefaultBufferSize(
+    surfaceProducer.setSize(
         resolutionFeature.getPreviewSize().getWidth(),
         resolutionFeature.getPreviewSize().getHeight());
-    Surface flutterSurface = new Surface(surfaceTexture);
+    Surface flutterSurface = surfaceProducer.getSurface();
     previewRequestBuilder.addTarget(flutterSurface);
 
     List<Surface> remainingSurfaces = Arrays.asList(surfaces);
@@ -1160,7 +1157,8 @@
   }
 
   public void startPreview() throws CameraAccessException, InterruptedException {
-    // If recording is already in progress, the camera is being flipped, so send it through the VideoRenderer to keep the correct orientation.
+    // If recording is already in progress, the camera is being flipped, so send it through the
+    // VideoRenderer to keep the correct orientation.
     if (recordingVideo) {
       startPreviewWithVideoRendererStream();
     } else {
@@ -1193,7 +1191,6 @@
     }
 
     if (cameraProperties.getLensFacing() != initialCameraFacing) {
-
       // If the new camera is facing the opposite way than the initial recording,
       // the rotation should be flipped 180 degrees.
       rotation = (rotation + 180) % 360;
@@ -1361,13 +1358,13 @@
 
   public void setDescriptionWhileRecording(
       @NonNull final Result result, CameraProperties properties) {
-
     if (!recordingVideo) {
       result.error("setDescriptionWhileRecordingFailed", "Device was not recording", null);
       return;
     }
 
-    // See VideoRenderer.java; support for this EGL extension is required to switch camera while recording.
+    // See VideoRenderer.java; support for this EGL extension is required to switch camera while
+    // recording.
     if (!SdkCapabilityChecker.supportsEglRecordableAndroid()) {
       result.error(
           "setDescriptionWhileRecordingFailed",
@@ -1400,7 +1397,7 @@
     Log.i(TAG, "dispose");
 
     close();
-    flutterTexture.release();
+    surfaceProducer.release();
     getDeviceOrientationManager().stop();
   }
 
diff --git a/packages/camera/camera_android/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java b/packages/camera/camera_android/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java
index eae8c65..b3f4da8 100644
--- a/packages/camera/camera_android/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java
+++ b/packages/camera/camera_android/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java
@@ -393,11 +393,9 @@
     Integer videoBitrate = call.argument("videoBitrate");
     Integer audioBitrate = call.argument("audioBitrate");
 
-    TextureRegistry.SurfaceTextureEntry flutterSurfaceTexture =
-        textureRegistry.createSurfaceTexture();
+    TextureRegistry.SurfaceProducer surfaceProducer = textureRegistry.createSurfaceProducer();
     DartMessenger dartMessenger =
-        new DartMessenger(
-            messenger, flutterSurfaceTexture.id(), new Handler(Looper.getMainLooper()));
+        new DartMessenger(messenger, surfaceProducer.id(), new Handler(Looper.getMainLooper()));
     CameraProperties cameraProperties =
         new CameraPropertiesImpl(cameraName, CameraUtils.getCameraManager(activity));
     ResolutionPreset resolutionPreset = ResolutionPreset.valueOf(preset);
@@ -405,7 +403,7 @@
     camera =
         new Camera(
             activity,
-            flutterSurfaceTexture,
+            surfaceProducer,
             new CameraFeatureFactoryImpl(),
             dartMessenger,
             cameraProperties,
@@ -413,7 +411,7 @@
                 resolutionPreset, enableAudio, fps, videoBitrate, audioBitrate));
 
     Map<String, Object> reply = new HashMap<>();
-    reply.put("cameraId", flutterSurfaceTexture.id());
+    reply.put("cameraId", surfaceProducer.id());
     result.success(reply);
   }
 
diff --git a/packages/camera/camera_android/android/src/test/java/io/flutter/plugins/camera/CameraTest.java b/packages/camera/camera_android/android/src/test/java/io/flutter/plugins/camera/CameraTest.java
index d2d90b7..9763808 100644
--- a/packages/camera/camera_android/android/src/test/java/io/flutter/plugins/camera/CameraTest.java
+++ b/packages/camera/camera_android/android/src/test/java/io/flutter/plugins/camera/CameraTest.java
@@ -32,7 +32,6 @@
 import io.flutter.plugin.common.EventChannel;
 import io.flutter.plugin.common.MethodChannel;
 import io.flutter.plugins.camera.features.CameraFeatureFactory;
-import io.flutter.plugins.camera.features.CameraFeatures;
 import io.flutter.plugins.camera.features.Point;
 import io.flutter.plugins.camera.features.autofocus.AutoFocusFeature;
 import io.flutter.plugins.camera.features.autofocus.FocusMode;
@@ -123,7 +122,6 @@
 
   @Before
   public void before() {
-
     mockRangeConstruction = new RangeConstruction();
     mockCameraProperties = mock(CameraProperties.class);
     mockDartMessenger = mock(DartMessenger.class);
@@ -135,8 +133,8 @@
     mockHandler = mock(Handler.class);
 
     final Activity mockActivity = mock(Activity.class);
-    final TextureRegistry.SurfaceTextureEntry mockFlutterTexture =
-        mock(TextureRegistry.SurfaceTextureEntry.class);
+    final TextureRegistry.SurfaceProducer mockSurfaceProducer =
+        mock(TextureRegistry.SurfaceProducer.class);
     final String cameraName = "1";
     final ResolutionPreset resolutionPreset = ResolutionPreset.high;
     final boolean enableAudio = false;
@@ -163,7 +161,7 @@
     camera =
         new Camera(
             mockActivity,
-            mockFlutterTexture,
+            mockSurfaceProducer,
             mockCameraFeatureFactory,
             mockDartMessenger,
             mockCameraProperties,
@@ -195,8 +193,8 @@
   @Test
   public void shouldCreateCameraPluginAndSetAllFeatures() {
     final Activity mockActivity = mock(Activity.class);
-    final TextureRegistry.SurfaceTextureEntry mockFlutterTexture =
-        mock(TextureRegistry.SurfaceTextureEntry.class);
+    final TextureRegistry.SurfaceProducer mockSurfaceProducer =
+        mock(TextureRegistry.SurfaceProducer.class);
     final CameraFeatureFactory spyMockCameraFeatureFactory = spy(mockCameraFeatureFactory);
     final String cameraName = "1";
     final ResolutionPreset resolutionPreset = ResolutionPreset.high;
@@ -210,7 +208,7 @@
     Camera camera =
         new Camera(
             mockActivity,
-            mockFlutterTexture,
+            mockSurfaceProducer,
             spyMockCameraFeatureFactory,
             mockDartMessenger,
             mockCameraProperties,
@@ -681,7 +679,6 @@
     VideoRenderer mockVideoRenderer = mock(VideoRenderer.class);
     ArrayList<CaptureRequest.Builder> mockRequestBuilders = new ArrayList<>();
     mockRequestBuilders.add(mock(CaptureRequest.Builder.class));
-    SurfaceTexture mockSurfaceTexture = mock(SurfaceTexture.class);
     Size mockSize = mock(Size.class);
     camera.recordingVideo = true;
     camera.videoRenderer = mockVideoRenderer;
@@ -690,10 +687,8 @@
     ImageReader mockPictureImageReader = mock(ImageReader.class);
     camera.pictureImageReader = mockPictureImageReader;
 
-    TextureRegistry.SurfaceTextureEntry cameraFlutterTexture = camera.flutterTexture;
     ResolutionFeature resolutionFeature = mockCameraFeatureFactory.mockResolutionFeature;
 
-    when(cameraFlutterTexture.surfaceTexture()).thenReturn(mockSurfaceTexture);
     when(resolutionFeature.getPreviewSize()).thenReturn(mockSize);
 
     camera.startPreview();
@@ -706,7 +701,6 @@
       throws InterruptedException, CameraAccessException {
     ArrayList<CaptureRequest.Builder> mockRequestBuilders = new ArrayList<>();
     mockRequestBuilders.add(mock(CaptureRequest.Builder.class));
-    SurfaceTexture mockSurfaceTexture = mock(SurfaceTexture.class);
     Size mockSize = mock(Size.class);
     ImageReader mockImageReader = mock(ImageReader.class);
     camera.recordingVideo = false;
@@ -714,10 +708,8 @@
     CameraDeviceWrapper fakeCamera = new FakeCameraDeviceWrapper(mockRequestBuilders);
     camera.cameraDevice = fakeCamera;
 
-    TextureRegistry.SurfaceTextureEntry cameraFlutterTexture = camera.flutterTexture;
     ResolutionFeature resolutionFeature = mockCameraFeatureFactory.mockResolutionFeature;
 
-    when(cameraFlutterTexture.surfaceTexture()).thenReturn(mockSurfaceTexture);
     when(resolutionFeature.getPreviewSize()).thenReturn(mockSize);
     when(mockImageReader.getSurface()).thenReturn(mock(Surface.class));
 
@@ -731,7 +723,6 @@
     VideoRenderer mockVideoRenderer = mock(VideoRenderer.class);
     ArrayList<CaptureRequest.Builder> mockRequestBuilders = new ArrayList<>();
     mockRequestBuilders.add(mock(CaptureRequest.Builder.class));
-    SurfaceTexture mockSurfaceTexture = mock(SurfaceTexture.class);
     Size mockSize = mock(Size.class);
     camera.recordingVideo = true;
     camera.videoRenderer = mockVideoRenderer;
@@ -741,10 +732,8 @@
     ImageReader mockPictureImageReader = mock(ImageReader.class);
     camera.pictureImageReader = mockPictureImageReader;
 
-    TextureRegistry.SurfaceTextureEntry cameraFlutterTexture = camera.flutterTexture;
     ResolutionFeature resolutionFeature = mockCameraFeatureFactory.mockResolutionFeature;
 
-    when(cameraFlutterTexture.surfaceTexture()).thenReturn(mockSurfaceTexture);
     when(resolutionFeature.getPreviewSize()).thenReturn(mockSize);
     when(mockCameraProperties.getLensFacing()).thenReturn(CameraMetadata.LENS_FACING_FRONT);
 
@@ -767,10 +756,8 @@
     camera.cameraDevice = fakeCamera;
     camera.imageStreamReader = mockImageStreamReader;
 
-    TextureRegistry.SurfaceTextureEntry cameraFlutterTexture = camera.flutterTexture;
     ResolutionFeature resolutionFeature = mockCameraFeatureFactory.mockResolutionFeature;
 
-    when(cameraFlutterTexture.surfaceTexture()).thenReturn(mockSurfaceTexture);
     when(resolutionFeature.getPreviewSize()).thenReturn(mockSize);
 
     camera.startPreviewWithImageStream(mock(EventChannel.class));
@@ -887,7 +874,6 @@
     Camera cameraSpy = spy(camera);
     ArrayList<CaptureRequest.Builder> mockRequestBuilders = new ArrayList<>();
     mockRequestBuilders.add(mock(CaptureRequest.Builder.class));
-    SurfaceTexture mockSurfaceTexture = mock(SurfaceTexture.class);
     Size mockSize = mock(Size.class);
     MediaRecorder mockMediaRecorder = mock(MediaRecorder.class);
     ImageReader mockPictureImageReader = mock(ImageReader.class);
@@ -898,10 +884,8 @@
     cameraSpy.cameraDevice = fakeCamera;
     MethodChannel.Result mockResult = mock(MethodChannel.Result.class);
 
-    TextureRegistry.SurfaceTextureEntry cameraFlutterTexture = cameraSpy.flutterTexture;
     ResolutionFeature resolutionFeature = mockCameraFeatureFactory.mockResolutionFeature;
 
-    when(cameraFlutterTexture.surfaceTexture()).thenReturn(mockSurfaceTexture);
     when(resolutionFeature.getPreviewSize()).thenReturn(mockSize);
     doNothing().when(cameraSpy).prepareRecording(mockResult);
 
@@ -1089,7 +1073,8 @@
     camera.onConverged();
     // A picture should be taken.
     verify(mockCaptureSession, times(1)).capture(any(), any(), any());
-    // The session shuold not be aborted as part of this flow, as this breaks capture on some
+    // The session shuold not be aborted as part of this flow, as this breaks
+    // capture on some
     // devices, and causes delays on others.
     verify(mockCaptureSession, never()).abortCaptures();
   }
@@ -1097,19 +1082,14 @@
   @Test
   public void createCaptureSession_doesNotCloseCaptureSession() throws CameraAccessException {
     Surface mockSurface = mock(Surface.class);
-    SurfaceTexture mockSurfaceTexture = mock(SurfaceTexture.class);
-    ResolutionFeature mockResolutionFeature = mock(ResolutionFeature.class);
     Size mockSize = mock(Size.class);
     ArrayList<CaptureRequest.Builder> mockRequestBuilders = new ArrayList<>();
     mockRequestBuilders.add(mock(CaptureRequest.Builder.class));
     CameraDeviceWrapper fakeCamera = new FakeCameraDeviceWrapper(mockRequestBuilders);
     camera.cameraDevice = fakeCamera;
 
-    TextureRegistry.SurfaceTextureEntry cameraFlutterTexture = camera.flutterTexture;
-    CameraFeatures cameraFeatures = camera.cameraFeatures;
     ResolutionFeature resolutionFeature = mockCameraFeatureFactory.mockResolutionFeature;
 
-    when(cameraFlutterTexture.surfaceTexture()).thenReturn(mockSurfaceTexture);
     when(resolutionFeature.getPreviewSize()).thenReturn(mockSize);
 
     camera.createCaptureSession(CameraDevice.TEMPLATE_PREVIEW, mockSurface);
@@ -1122,8 +1102,6 @@
       throws CameraAccessException {
     Surface mockSurface = mock(Surface.class);
     Surface mockSecondarySurface = mock(Surface.class);
-    SurfaceTexture mockSurfaceTexture = mock(SurfaceTexture.class);
-    ResolutionFeature mockResolutionFeature = mock(ResolutionFeature.class);
     Size mockSize = mock(Size.class);
     ArrayList<CaptureRequest.Builder> mockRequestBuilders = new ArrayList<>();
     mockRequestBuilders.add(mock(CaptureRequest.Builder.class));
@@ -1133,11 +1111,8 @@
     camera.pictureImageReader = mockPictureImageReader;
     CaptureRequest.Builder mockPreviewRequestBuilder = mock(CaptureRequest.Builder.class);
 
-    TextureRegistry.SurfaceTextureEntry cameraFlutterTexture = camera.flutterTexture;
-    CameraFeatures cameraFeatures = camera.cameraFeatures;
     ResolutionFeature resolutionFeature = mockCameraFeatureFactory.mockResolutionFeature;
 
-    when(cameraFlutterTexture.surfaceTexture()).thenReturn(mockSurfaceTexture);
     when(resolutionFeature.getPreviewSize()).thenReturn(mockSize);
     when(fakeCamera.createCaptureRequest(anyInt())).thenReturn(mockPreviewRequestBuilder);
     when(mockPictureImageReader.getSurface()).thenReturn(mockSurface);
@@ -1174,19 +1149,18 @@
   @Test
   public void startVideoRecording_shouldApplySettingsToMediaRecorder()
       throws InterruptedException, IOException, CameraAccessException {
-
     final Activity mockActivity = mock(Activity.class);
-    final TextureRegistry.SurfaceTextureEntry mockFlutterTexture =
-        mock(TextureRegistry.SurfaceTextureEntry.class);
+    final TextureRegistry.SurfaceProducer mockSurfaceProducer =
+        mock(TextureRegistry.SurfaceProducer.class);
     final String cameraName = "1";
     final ResolutionPreset resolutionPreset = ResolutionPreset.high;
     final boolean enableAudio = true;
 
-    //region These parameters should be set in android MediaRecorder.
+    // region These parameters should be set in android MediaRecorder.
     final int fps = 15;
     final int videoBitrate = 200000;
     final int audioBitrate = 32000;
-    //endregion
+    // endregion
 
     when(mockCameraProperties.getCameraName()).thenReturn(cameraName);
 
@@ -1209,7 +1183,6 @@
     try (final MockedStatic<File> mockFile = mockStatic(File.class);
         final MockedConstruction<MediaRecorder> mockMediaRecorder =
             Mockito.mockConstruction(MediaRecorder.class)) {
-
       assertNotNull(mockMediaRecorder);
 
       mockFile
@@ -1222,7 +1195,7 @@
           spy(
               new Camera(
                   mockActivity,
-                  mockFlutterTexture,
+                  mockSurfaceProducer,
                   mockCameraFeatureFactory,
                   mockDartMessenger,
                   mockCameraProperties,
@@ -1255,19 +1228,15 @@
       camera.cameraDevice = fakeCamera;
       MethodChannel.Result mockResult = mock(MethodChannel.Result.class);
 
-      TextureRegistry.SurfaceTextureEntry cameraFlutterTexture = camera.flutterTexture;
-
       ResolutionFeature resolutionFeature = mockCameraFeatureFactory.mockResolutionFeature;
 
-      assertNotNull(cameraFlutterTexture);
-      when(cameraFlutterTexture.surfaceTexture()).thenReturn(mockSurfaceTexture);
-
       assertNotNull(resolutionFeature);
       when(resolutionFeature.getPreviewSize()).thenReturn(mockSize);
 
       camera.startVideoRecording(mockResult, null);
 
-      //region Check that FPS parameter affects AE range at which the camera captures frames.
+      // region Check that FPS parameter affects AE range at which the camera captures
+      // frames.
       assertEquals(camera.cameraFeatures.getFpsRange().getValue().getLower(), Integer.valueOf(fps));
       assertEquals(camera.cameraFeatures.getFpsRange().getValue().getUpper(), Integer.valueOf(fps));
 
@@ -1276,15 +1245,15 @@
               eq(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE),
               argThat(
                   (Range<Integer> range) -> range.getLower() == fps && range.getUpper() == fps));
-      //endregion
+      // endregion
 
       final MediaRecorder recorder = camera.mediaRecorder;
 
-      //region Check that parameters affects movies, written by MediaRecorder.
+      // region Check that parameters affects movies, written by MediaRecorder.
       verify(recorder).setVideoFrameRate(fps);
       verify(recorder).setAudioEncodingBitRate(audioBitrate);
       verify(recorder).setVideoEncodingBitRate(videoBitrate);
-      //endregion
+      // endregion
     }
   }
 
diff --git a/packages/camera/camera_android/android/src/test/java/io/flutter/plugins/camera/CameraTest_getRecordingProfileTest.java b/packages/camera/camera_android/android/src/test/java/io/flutter/plugins/camera/CameraTest_getRecordingProfileTest.java
index c5a97a1..8791ecd 100644
--- a/packages/camera/camera_android/android/src/test/java/io/flutter/plugins/camera/CameraTest_getRecordingProfileTest.java
+++ b/packages/camera/camera_android/android/src/test/java/io/flutter/plugins/camera/CameraTest_getRecordingProfileTest.java
@@ -60,15 +60,15 @@
     mockDartMessenger = mock(DartMessenger.class);
 
     final Activity mockActivity = mock(Activity.class);
-    final TextureRegistry.SurfaceTextureEntry mockFlutterTexture =
-        mock(TextureRegistry.SurfaceTextureEntry.class);
+    final TextureRegistry.SurfaceProducer mockSurfaceProducer =
+        mock(TextureRegistry.SurfaceProducer.class);
     final ResolutionPreset resolutionPreset = ResolutionPreset.high;
     final boolean enableAudio = false;
 
     camera =
         new Camera(
             mockActivity,
-            mockFlutterTexture,
+            mockSurfaceProducer,
             mockCameraFeatureFactory,
             mockDartMessenger,
             mockCameraProperties,
diff --git a/packages/camera/camera_android/pubspec.yaml b/packages/camera/camera_android/pubspec.yaml
index 704f64b..f5b21d6 100644
--- a/packages/camera/camera_android/pubspec.yaml
+++ b/packages/camera/camera_android/pubspec.yaml
@@ -3,7 +3,7 @@
 repository: https://github.com/flutter/packages/tree/main/packages/camera/camera_android
 issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22
 
-version: 0.10.9+3
+version: 0.10.9+4
 
 environment:
   sdk: ^3.4.0