[camera] Fix CamcorderProfile Usages (#4423)
diff --git a/packages/camera/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md
index e6495a8..29750f9 100644
--- a/packages/camera/camera/CHANGELOG.md
+++ b/packages/camera/camera/CHANGELOG.md
@@ -1,5 +1,8 @@
## 0.9.4+3
+* Change Android compileSdkVersion to 31.
+* Remove usages of deprecated Android API `CamcorderProfile`.
+* Update gradle version to 7.0.2 on Android.
* Fix registerTexture and result being called on background thread on iOS.
## 0.9.4+2
diff --git a/packages/camera/camera/android/build.gradle b/packages/camera/camera/android/build.gradle
index 25285ad..264f7f8 100644
--- a/packages/camera/camera/android/build.gradle
+++ b/packages/camera/camera/android/build.gradle
@@ -9,7 +9,7 @@
}
dependencies {
- classpath 'com.android.tools.build:gradle:3.5.0'
+ classpath 'com.android.tools.build:gradle:7.0.2'
}
}
@@ -27,9 +27,10 @@
apply plugin: 'com.android.library'
android {
- compileSdkVersion 29
+ compileSdkVersion 31
defaultConfig {
+ targetSdkVersion 31
minSdkVersion 21
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
@@ -60,7 +61,7 @@
dependencies {
compileOnly 'androidx.annotation:annotation:1.1.0'
testImplementation 'junit:junit:4.12'
- testImplementation 'org.mockito:mockito-inline:3.12.4'
+ testImplementation 'org.mockito:mockito-inline:4.0.0'
testImplementation 'androidx.test:core:1.3.0'
- testImplementation 'org.robolectric:robolectric:4.3'
+ testImplementation 'org.robolectric:robolectric:4.5'
}
diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java
index 75ced53..e319039 100644
--- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java
+++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java
@@ -20,6 +20,7 @@
import android.hardware.camera2.params.OutputConfiguration;
import android.hardware.camera2.params.SessionConfiguration;
import android.media.CamcorderProfile;
+import android.media.EncoderProfiles;
import android.media.Image;
import android.media.ImageReader;
import android.media.MediaRecorder;
@@ -199,8 +200,16 @@
((SensorOrientationFeature) cameraFeatures.getSensorOrientation())
.getLockedCaptureOrientation();
+ MediaRecorderBuilder mediaRecorderBuilder;
+
+ if (Build.VERSION.SDK_INT >= 31) {
+ mediaRecorderBuilder = new MediaRecorderBuilder(getRecordingProfile(), outputFilePath);
+ } else {
+ mediaRecorderBuilder = new MediaRecorderBuilder(getRecordingProfileLegacy(), outputFilePath);
+ }
+
mediaRecorder =
- new MediaRecorderBuilder(getRecordingProfile(), outputFilePath)
+ mediaRecorderBuilder
.setEnableAudio(enableAudio)
.setMediaOrientation(
lockedOrientation == null
@@ -918,8 +927,12 @@
return cameraFeatures.getZoomLevel().getMinimumZoomLevel();
}
- /** Shortcut to get current recording profile. */
- CamcorderProfile getRecordingProfile() {
+ /** Shortcut to get current recording profile. Legacy method provides support for SDK < 31. */
+ CamcorderProfile getRecordingProfileLegacy() {
+ return cameraFeatures.getResolution().getRecordingProfileLegacy();
+ }
+
+ EncoderProfiles getRecordingProfile() {
return cameraFeatures.getResolution().getRecordingProfile();
}
diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/resolution/ResolutionFeature.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/resolution/ResolutionFeature.java
index 67763dd..afbd7c3 100644
--- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/resolution/ResolutionFeature.java
+++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/resolution/ResolutionFeature.java
@@ -4,12 +4,16 @@
package io.flutter.plugins.camera.features.resolution;
+import android.annotation.TargetApi;
import android.hardware.camera2.CaptureRequest;
import android.media.CamcorderProfile;
+import android.media.EncoderProfiles;
+import android.os.Build;
import android.util.Size;
import androidx.annotation.VisibleForTesting;
import io.flutter.plugins.camera.CameraProperties;
import io.flutter.plugins.camera.features.CameraFeature;
+import java.util.List;
/**
* Controls the resolutions configuration on the {@link android.hardware.camera2} API.
@@ -21,7 +25,8 @@
public class ResolutionFeature extends CameraFeature<ResolutionPreset> {
private Size captureSize;
private Size previewSize;
- private CamcorderProfile recordingProfile;
+ private CamcorderProfile recordingProfileLegacy;
+ private EncoderProfiles recordingProfile;
private ResolutionPreset currentSetting;
private int cameraId;
@@ -51,7 +56,11 @@
*
* @return Resolution information to configure the {@link android.hardware.camera2} API.
*/
- public CamcorderProfile getRecordingProfile() {
+ public CamcorderProfile getRecordingProfileLegacy() {
+ return this.recordingProfileLegacy;
+ }
+
+ public EncoderProfiles getRecordingProfile() {
return this.recordingProfile;
}
@@ -100,19 +109,29 @@
}
@VisibleForTesting
- static Size computeBestPreviewSize(int cameraId, ResolutionPreset preset) {
+ static Size computeBestPreviewSize(int cameraId, ResolutionPreset preset)
+ throws IndexOutOfBoundsException {
if (preset.ordinal() > ResolutionPreset.high.ordinal()) {
preset = ResolutionPreset.high;
}
+ if (Build.VERSION.SDK_INT >= 31) {
+ EncoderProfiles profile =
+ getBestAvailableCamcorderProfileForResolutionPreset(cameraId, preset);
+ List<EncoderProfiles.VideoProfile> videoProfiles = profile.getVideoProfiles();
+ EncoderProfiles.VideoProfile defaultVideoProfile = videoProfiles.get(0);
- CamcorderProfile profile =
- getBestAvailableCamcorderProfileForResolutionPreset(cameraId, preset);
- return new Size(profile.videoFrameWidth, profile.videoFrameHeight);
+ return new Size(defaultVideoProfile.getWidth(), defaultVideoProfile.getHeight());
+ } else {
+ @SuppressWarnings("deprecation")
+ CamcorderProfile profile =
+ getBestAvailableCamcorderProfileForResolutionPresetLegacy(cameraId, preset);
+ return new Size(profile.videoFrameWidth, profile.videoFrameHeight);
+ }
}
/**
* Gets the best possible {@link android.media.CamcorderProfile} for the supplied {@link
- * ResolutionPreset}.
+ * ResolutionPreset}. Supports SDK < 31.
*
* @param cameraId Camera identifier which indicates the device's camera for which to select a
* {@link android.media.CamcorderProfile}.
@@ -121,7 +140,7 @@
* @return The best possible {@link android.media.CamcorderProfile} that matches the supplied
* {@link ResolutionPreset}.
*/
- public static CamcorderProfile getBestAvailableCamcorderProfileForResolutionPreset(
+ public static CamcorderProfile getBestAvailableCamcorderProfileForResolutionPresetLegacy(
int cameraId, ResolutionPreset preset) {
if (cameraId < 0) {
throw new AssertionError(
@@ -164,13 +183,74 @@
}
}
- private void configureResolution(ResolutionPreset resolutionPreset, int cameraId) {
+ @TargetApi(Build.VERSION_CODES.S)
+ public static EncoderProfiles getBestAvailableCamcorderProfileForResolutionPreset(
+ int cameraId, ResolutionPreset preset) {
+ if (cameraId < 0) {
+ throw new AssertionError(
+ "getBestAvailableCamcorderProfileForResolutionPreset can only be used with valid (>=0) camera identifiers.");
+ }
+
+ String cameraIdString = Integer.toString(cameraId);
+
+ switch (preset) {
+ // All of these cases deliberately fall through to get the best available profile.
+ case max:
+ if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_HIGH)) {
+ return CamcorderProfile.getAll(cameraIdString, CamcorderProfile.QUALITY_HIGH);
+ }
+ case ultraHigh:
+ if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_2160P)) {
+ return CamcorderProfile.getAll(cameraIdString, CamcorderProfile.QUALITY_2160P);
+ }
+ case veryHigh:
+ if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_1080P)) {
+ return CamcorderProfile.getAll(cameraIdString, CamcorderProfile.QUALITY_1080P);
+ }
+ case high:
+ if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_720P)) {
+ return CamcorderProfile.getAll(cameraIdString, CamcorderProfile.QUALITY_720P);
+ }
+ case medium:
+ if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_480P)) {
+ return CamcorderProfile.getAll(cameraIdString, CamcorderProfile.QUALITY_480P);
+ }
+ case low:
+ if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_QVGA)) {
+ return CamcorderProfile.getAll(cameraIdString, CamcorderProfile.QUALITY_QVGA);
+ }
+ default:
+ if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_LOW)) {
+ return CamcorderProfile.getAll(cameraIdString, CamcorderProfile.QUALITY_LOW);
+ }
+
+ throw new IllegalArgumentException(
+ "No capture session available for current capture session.");
+ }
+ }
+
+ private void configureResolution(ResolutionPreset resolutionPreset, int cameraId)
+ throws IndexOutOfBoundsException {
if (!checkIsSupported()) {
return;
}
- recordingProfile =
- getBestAvailableCamcorderProfileForResolutionPreset(cameraId, resolutionPreset);
- captureSize = new Size(recordingProfile.videoFrameWidth, recordingProfile.videoFrameHeight);
+
+ if (Build.VERSION.SDK_INT >= 31) {
+ recordingProfile =
+ getBestAvailableCamcorderProfileForResolutionPreset(cameraId, resolutionPreset);
+ List<EncoderProfiles.VideoProfile> videoProfiles = recordingProfile.getVideoProfiles();
+
+ EncoderProfiles.VideoProfile defaultVideoProfile = videoProfiles.get(0);
+ captureSize = new Size(defaultVideoProfile.getWidth(), defaultVideoProfile.getHeight());
+ } else {
+ @SuppressWarnings("deprecation")
+ CamcorderProfile camcorderProfile =
+ getBestAvailableCamcorderProfileForResolutionPresetLegacy(cameraId, resolutionPreset);
+ recordingProfileLegacy = camcorderProfile;
+ captureSize =
+ new Size(recordingProfileLegacy.videoFrameWidth, recordingProfileLegacy.videoFrameHeight);
+ }
+
previewSize = computeBestPreviewSize(cameraId, resolutionPreset);
}
}
diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/media/MediaRecorderBuilder.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/media/MediaRecorderBuilder.java
index a78c2b4..0aebfee 100644
--- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/media/MediaRecorderBuilder.java
+++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/media/MediaRecorderBuilder.java
@@ -5,11 +5,14 @@
package io.flutter.plugins.camera.media;
import android.media.CamcorderProfile;
+import android.media.EncoderProfiles;
import android.media.MediaRecorder;
+import android.os.Build;
import androidx.annotation.NonNull;
import java.io.IOException;
public class MediaRecorderBuilder {
+ @SuppressWarnings("deprecation")
static class MediaRecorderFactory {
MediaRecorder makeMediaRecorder() {
return new MediaRecorder();
@@ -17,23 +20,40 @@
}
private final String outputFilePath;
- private final CamcorderProfile recordingProfile;
+ private final CamcorderProfile camcorderProfile;
+ private final EncoderProfiles encoderProfiles;
private final MediaRecorderFactory recorderFactory;
private boolean enableAudio;
private int mediaOrientation;
public MediaRecorderBuilder(
- @NonNull CamcorderProfile recordingProfile, @NonNull String outputFilePath) {
- this(recordingProfile, outputFilePath, new MediaRecorderFactory());
+ @NonNull CamcorderProfile camcorderProfile, @NonNull String outputFilePath) {
+ this(camcorderProfile, outputFilePath, new MediaRecorderFactory());
+ }
+
+ public MediaRecorderBuilder(
+ @NonNull EncoderProfiles encoderProfiles, @NonNull String outputFilePath) {
+ this(encoderProfiles, outputFilePath, new MediaRecorderFactory());
}
MediaRecorderBuilder(
- @NonNull CamcorderProfile recordingProfile,
+ @NonNull CamcorderProfile camcorderProfile,
@NonNull String outputFilePath,
MediaRecorderFactory helper) {
this.outputFilePath = outputFilePath;
- this.recordingProfile = recordingProfile;
+ this.camcorderProfile = camcorderProfile;
+ this.encoderProfiles = null;
+ this.recorderFactory = helper;
+ }
+
+ MediaRecorderBuilder(
+ @NonNull EncoderProfiles encoderProfiles,
+ @NonNull String outputFilePath,
+ MediaRecorderFactory helper) {
+ this.outputFilePath = outputFilePath;
+ this.encoderProfiles = encoderProfiles;
+ this.camcorderProfile = null;
this.recorderFactory = helper;
}
@@ -47,23 +67,43 @@
return this;
}
- public MediaRecorder build() throws IOException {
+ public MediaRecorder build() throws IOException, NullPointerException, IndexOutOfBoundsException {
MediaRecorder mediaRecorder = recorderFactory.makeMediaRecorder();
// There's a fixed order that mediaRecorder expects. Only change these functions accordingly.
// You can find the specifics here: https://developer.android.com/reference/android/media/MediaRecorder.
if (enableAudio) mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
- mediaRecorder.setOutputFormat(recordingProfile.fileFormat);
- if (enableAudio) {
- mediaRecorder.setAudioEncoder(recordingProfile.audioCodec);
- mediaRecorder.setAudioEncodingBitRate(recordingProfile.audioBitRate);
- mediaRecorder.setAudioSamplingRate(recordingProfile.audioSampleRate);
+
+ if (Build.VERSION.SDK_INT >= 31) {
+ EncoderProfiles.VideoProfile videoProfile = encoderProfiles.getVideoProfiles().get(0);
+ EncoderProfiles.AudioProfile audioProfile = encoderProfiles.getAudioProfiles().get(0);
+
+ mediaRecorder.setOutputFormat(encoderProfiles.getRecommendedFileFormat());
+ if (enableAudio) {
+ mediaRecorder.setAudioEncoder(audioProfile.getCodec());
+ mediaRecorder.setAudioEncodingBitRate(audioProfile.getBitrate());
+ mediaRecorder.setAudioSamplingRate(audioProfile.getSampleRate());
+ }
+ mediaRecorder.setVideoEncoder(videoProfile.getCodec());
+ mediaRecorder.setVideoEncodingBitRate(videoProfile.getBitrate());
+ mediaRecorder.setVideoFrameRate(videoProfile.getFrameRate());
+ mediaRecorder.setVideoSize(videoProfile.getWidth(), videoProfile.getHeight());
+ mediaRecorder.setVideoSize(videoProfile.getWidth(), videoProfile.getHeight());
+ } else {
+ mediaRecorder.setOutputFormat(camcorderProfile.fileFormat);
+ if (enableAudio) {
+ mediaRecorder.setAudioEncoder(camcorderProfile.audioCodec);
+ mediaRecorder.setAudioEncodingBitRate(camcorderProfile.audioBitRate);
+ mediaRecorder.setAudioSamplingRate(camcorderProfile.audioSampleRate);
+ }
+ mediaRecorder.setVideoEncoder(camcorderProfile.videoCodec);
+ mediaRecorder.setVideoEncodingBitRate(camcorderProfile.videoBitRate);
+ mediaRecorder.setVideoFrameRate(camcorderProfile.videoFrameRate);
+ mediaRecorder.setVideoSize(
+ camcorderProfile.videoFrameWidth, camcorderProfile.videoFrameHeight);
}
- mediaRecorder.setVideoEncoder(recordingProfile.videoCodec);
- mediaRecorder.setVideoEncodingBitRate(recordingProfile.videoBitRate);
- mediaRecorder.setVideoFrameRate(recordingProfile.videoFrameRate);
- mediaRecorder.setVideoSize(recordingProfile.videoFrameWidth, recordingProfile.videoFrameHeight);
+
mediaRecorder.setOutputFile(outputFilePath);
mediaRecorder.setOrientationHint(this.mediaOrientation);
diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraTest.java
index 9d97319..1ed2e4c 100644
--- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraTest.java
+++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraTest.java
@@ -22,7 +22,6 @@
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraMetadata;
import android.hardware.camera2.CaptureRequest;
-import android.media.CamcorderProfile;
import android.media.MediaRecorder;
import android.os.Build;
import android.os.Handler;
@@ -250,20 +249,6 @@
}
@Test
- public void getRecordingProfile() {
- ResolutionFeature mockResolutionFeature =
- mockCameraFeatureFactory.createResolutionFeature(mockCameraProperties, null, null);
- CamcorderProfile mockCamcorderProfile = mock(CamcorderProfile.class);
-
- when(mockResolutionFeature.getRecordingProfile()).thenReturn(mockCamcorderProfile);
-
- CamcorderProfile actualRecordingProfile = camera.getRecordingProfile();
-
- verify(mockResolutionFeature, times(1)).getRecordingProfile();
- assertEquals(mockCamcorderProfile, actualRecordingProfile);
- }
-
- @Test
public void setExposureMode_shouldUpdateExposureLockFeature() {
ExposureLockFeature mockExposureLockFeature =
mockCameraFeatureFactory.createExposureLockFeature(mockCameraProperties);
diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraTest_getRecordingProfileTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraTest_getRecordingProfileTest.java
new file mode 100644
index 0000000..04bab14
--- /dev/null
+++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraTest_getRecordingProfileTest.java
@@ -0,0 +1,205 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package io.flutter.plugins.camera;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.Activity;
+import android.hardware.camera2.CameraCaptureSession;
+import android.hardware.camera2.CaptureRequest;
+import android.media.CamcorderProfile;
+import android.media.EncoderProfiles;
+import android.os.Handler;
+import android.os.HandlerThread;
+import androidx.annotation.NonNull;
+import io.flutter.plugins.camera.features.CameraFeatureFactory;
+import io.flutter.plugins.camera.features.autofocus.AutoFocusFeature;
+import io.flutter.plugins.camera.features.exposurelock.ExposureLockFeature;
+import io.flutter.plugins.camera.features.exposureoffset.ExposureOffsetFeature;
+import io.flutter.plugins.camera.features.exposurepoint.ExposurePointFeature;
+import io.flutter.plugins.camera.features.flash.FlashFeature;
+import io.flutter.plugins.camera.features.focuspoint.FocusPointFeature;
+import io.flutter.plugins.camera.features.fpsrange.FpsRangeFeature;
+import io.flutter.plugins.camera.features.noisereduction.NoiseReductionFeature;
+import io.flutter.plugins.camera.features.resolution.ResolutionFeature;
+import io.flutter.plugins.camera.features.resolution.ResolutionPreset;
+import io.flutter.plugins.camera.features.sensororientation.SensorOrientationFeature;
+import io.flutter.plugins.camera.features.zoomlevel.ZoomLevelFeature;
+import io.flutter.view.TextureRegistry;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockedStatic;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+
+@RunWith(RobolectricTestRunner.class)
+public class CameraTest_getRecordingProfileTest {
+
+ private CameraProperties mockCameraProperties;
+ private CameraFeatureFactory mockCameraFeatureFactory;
+ private DartMessenger mockDartMessenger;
+ private Camera camera;
+ private CameraCaptureSession mockCaptureSession;
+ private CaptureRequest.Builder mockPreviewRequestBuilder;
+ private MockedStatic<Camera.HandlerThreadFactory> mockHandlerThreadFactory;
+ private HandlerThread mockHandlerThread;
+ private MockedStatic<Camera.HandlerFactory> mockHandlerFactory;
+ private Handler mockHandler;
+
+ @Before
+ public void before() {
+ mockCameraProperties = mock(CameraProperties.class);
+ mockCameraFeatureFactory = new TestCameraFeatureFactory();
+ mockDartMessenger = mock(DartMessenger.class);
+
+ final Activity mockActivity = mock(Activity.class);
+ final TextureRegistry.SurfaceTextureEntry mockFlutterTexture =
+ mock(TextureRegistry.SurfaceTextureEntry.class);
+ final ResolutionPreset resolutionPreset = ResolutionPreset.high;
+ final boolean enableAudio = false;
+
+ camera =
+ new Camera(
+ mockActivity,
+ mockFlutterTexture,
+ mockCameraFeatureFactory,
+ mockDartMessenger,
+ mockCameraProperties,
+ resolutionPreset,
+ enableAudio);
+ }
+
+ @Config(maxSdk = 30)
+ @Test
+ public void getRecordingProfileLegacy() {
+ ResolutionFeature mockResolutionFeature =
+ mockCameraFeatureFactory.createResolutionFeature(mockCameraProperties, null, null);
+ CamcorderProfile mockCamcorderProfile = mock(CamcorderProfile.class);
+
+ when(mockResolutionFeature.getRecordingProfileLegacy()).thenReturn(mockCamcorderProfile);
+
+ CamcorderProfile actualRecordingProfile = camera.getRecordingProfileLegacy();
+
+ verify(mockResolutionFeature, times(1)).getRecordingProfileLegacy();
+ assertEquals(mockCamcorderProfile, actualRecordingProfile);
+ }
+
+ @Config(minSdk = 31)
+ @Test
+ public void getRecordingProfile() {
+ ResolutionFeature mockResolutionFeature =
+ mockCameraFeatureFactory.createResolutionFeature(mockCameraProperties, null, null);
+ EncoderProfiles mockRecordingProfile = mock(EncoderProfiles.class);
+
+ when(mockResolutionFeature.getRecordingProfile()).thenReturn(mockRecordingProfile);
+
+ EncoderProfiles actualRecordingProfile = camera.getRecordingProfile();
+
+ verify(mockResolutionFeature, times(1)).getRecordingProfile();
+ assertEquals(mockRecordingProfile, actualRecordingProfile);
+ }
+
+ private static class TestCameraFeatureFactory implements CameraFeatureFactory {
+ private final AutoFocusFeature mockAutoFocusFeature;
+ private final ExposureLockFeature mockExposureLockFeature;
+ private final ExposureOffsetFeature mockExposureOffsetFeature;
+ private final ExposurePointFeature mockExposurePointFeature;
+ private final FlashFeature mockFlashFeature;
+ private final FocusPointFeature mockFocusPointFeature;
+ private final FpsRangeFeature mockFpsRangeFeature;
+ private final NoiseReductionFeature mockNoiseReductionFeature;
+ private final ResolutionFeature mockResolutionFeature;
+ private final SensorOrientationFeature mockSensorOrientationFeature;
+ private final ZoomLevelFeature mockZoomLevelFeature;
+
+ public TestCameraFeatureFactory() {
+ this.mockAutoFocusFeature = mock(AutoFocusFeature.class);
+ this.mockExposureLockFeature = mock(ExposureLockFeature.class);
+ this.mockExposureOffsetFeature = mock(ExposureOffsetFeature.class);
+ this.mockExposurePointFeature = mock(ExposurePointFeature.class);
+ this.mockFlashFeature = mock(FlashFeature.class);
+ this.mockFocusPointFeature = mock(FocusPointFeature.class);
+ this.mockFpsRangeFeature = mock(FpsRangeFeature.class);
+ this.mockNoiseReductionFeature = mock(NoiseReductionFeature.class);
+ this.mockResolutionFeature = mock(ResolutionFeature.class);
+ this.mockSensorOrientationFeature = mock(SensorOrientationFeature.class);
+ this.mockZoomLevelFeature = mock(ZoomLevelFeature.class);
+ }
+
+ @Override
+ public AutoFocusFeature createAutoFocusFeature(
+ @NonNull CameraProperties cameraProperties, boolean recordingVideo) {
+ return mockAutoFocusFeature;
+ }
+
+ @Override
+ public ExposureLockFeature createExposureLockFeature(
+ @NonNull CameraProperties cameraProperties) {
+ return mockExposureLockFeature;
+ }
+
+ @Override
+ public ExposureOffsetFeature createExposureOffsetFeature(
+ @NonNull CameraProperties cameraProperties) {
+ return mockExposureOffsetFeature;
+ }
+
+ @Override
+ public FlashFeature createFlashFeature(@NonNull CameraProperties cameraProperties) {
+ return mockFlashFeature;
+ }
+
+ @Override
+ public ResolutionFeature createResolutionFeature(
+ @NonNull CameraProperties cameraProperties,
+ ResolutionPreset initialSetting,
+ String cameraName) {
+ return mockResolutionFeature;
+ }
+
+ @Override
+ public FocusPointFeature createFocusPointFeature(
+ @NonNull CameraProperties cameraProperties,
+ @NonNull SensorOrientationFeature sensorOrienttionFeature) {
+ return mockFocusPointFeature;
+ }
+
+ @Override
+ public FpsRangeFeature createFpsRangeFeature(@NonNull CameraProperties cameraProperties) {
+ return mockFpsRangeFeature;
+ }
+
+ @Override
+ public SensorOrientationFeature createSensorOrientationFeature(
+ @NonNull CameraProperties cameraProperties,
+ @NonNull Activity activity,
+ @NonNull DartMessenger dartMessenger) {
+ return mockSensorOrientationFeature;
+ }
+
+ @Override
+ public ZoomLevelFeature createZoomLevelFeature(@NonNull CameraProperties cameraProperties) {
+ return mockZoomLevelFeature;
+ }
+
+ @Override
+ public ExposurePointFeature createExposurePointFeature(
+ @NonNull CameraProperties cameraProperties,
+ @NonNull SensorOrientationFeature sensorOrientationFeature) {
+ return mockExposurePointFeature;
+ }
+
+ @Override
+ public NoiseReductionFeature createNoiseReductionFeature(
+ @NonNull CameraProperties cameraProperties) {
+ return mockNoiseReductionFeature;
+ }
+ }
+}
diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/resolution/ResolutionFeatureTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/resolution/ResolutionFeatureTest.java
index e09223d..957b57a 100644
--- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/resolution/ResolutionFeatureTest.java
+++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/resolution/ResolutionFeatureTest.java
@@ -8,24 +8,33 @@
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.when;
import android.media.CamcorderProfile;
+import android.media.EncoderProfiles;
import io.flutter.plugins.camera.CameraProperties;
+import java.util.List;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
+import org.junit.runner.RunWith;
import org.mockito.MockedStatic;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+@RunWith(RobolectricTestRunner.class)
public class ResolutionFeatureTest {
private static final String cameraName = "1";
- private CamcorderProfile mockProfileLow;
+ private CamcorderProfile mockProfileLowLegacy;
+ private EncoderProfiles mockProfileLow;
private MockedStatic<CamcorderProfile> mockedStaticProfile;
@Before
- public void before() {
+ @SuppressWarnings("deprecation")
+ public void beforeLegacy() {
mockedStaticProfile = mockStatic(CamcorderProfile.class);
- mockProfileLow = mock(CamcorderProfile.class);
- CamcorderProfile mockProfile = mock(CamcorderProfile.class);
+ mockProfileLowLegacy = mock(CamcorderProfile.class);
+ CamcorderProfile mockProfileLegacy = mock(CamcorderProfile.class);
mockedStaticProfile
.when(() -> CamcorderProfile.hasProfile(1, CamcorderProfile.QUALITY_HIGH))
@@ -51,25 +60,58 @@
mockedStaticProfile
.when(() -> CamcorderProfile.get(1, CamcorderProfile.QUALITY_HIGH))
- .thenReturn(mockProfile);
+ .thenReturn(mockProfileLegacy);
mockedStaticProfile
.when(() -> CamcorderProfile.get(1, CamcorderProfile.QUALITY_2160P))
- .thenReturn(mockProfile);
+ .thenReturn(mockProfileLegacy);
mockedStaticProfile
.when(() -> CamcorderProfile.get(1, CamcorderProfile.QUALITY_1080P))
- .thenReturn(mockProfile);
+ .thenReturn(mockProfileLegacy);
mockedStaticProfile
.when(() -> CamcorderProfile.get(1, CamcorderProfile.QUALITY_720P))
- .thenReturn(mockProfile);
+ .thenReturn(mockProfileLegacy);
mockedStaticProfile
.when(() -> CamcorderProfile.get(1, CamcorderProfile.QUALITY_480P))
- .thenReturn(mockProfile);
+ .thenReturn(mockProfileLegacy);
mockedStaticProfile
.when(() -> CamcorderProfile.get(1, CamcorderProfile.QUALITY_QVGA))
- .thenReturn(mockProfile);
+ .thenReturn(mockProfileLegacy);
mockedStaticProfile
.when(() -> CamcorderProfile.get(1, CamcorderProfile.QUALITY_LOW))
+ .thenReturn(mockProfileLowLegacy);
+ }
+
+ public void before() {
+ mockProfileLow = mock(EncoderProfiles.class);
+ EncoderProfiles mockProfile = mock(EncoderProfiles.class);
+ EncoderProfiles.VideoProfile mockVideoProfile = mock(EncoderProfiles.VideoProfile.class);
+ List<EncoderProfiles.VideoProfile> mockVideoProfilesList = List.of(mockVideoProfile);
+
+ mockedStaticProfile
+ .when(() -> CamcorderProfile.getAll("1", CamcorderProfile.QUALITY_HIGH))
+ .thenReturn(mockProfile);
+ mockedStaticProfile
+ .when(() -> CamcorderProfile.getAll("1", CamcorderProfile.QUALITY_2160P))
+ .thenReturn(mockProfile);
+ mockedStaticProfile
+ .when(() -> CamcorderProfile.getAll("1", CamcorderProfile.QUALITY_1080P))
+ .thenReturn(mockProfile);
+ mockedStaticProfile
+ .when(() -> CamcorderProfile.getAll("1", CamcorderProfile.QUALITY_720P))
+ .thenReturn(mockProfile);
+ mockedStaticProfile
+ .when(() -> CamcorderProfile.getAll("1", CamcorderProfile.QUALITY_480P))
+ .thenReturn(mockProfile);
+ mockedStaticProfile
+ .when(() -> CamcorderProfile.getAll("1", CamcorderProfile.QUALITY_QVGA))
+ .thenReturn(mockProfile);
+ mockedStaticProfile
+ .when(() -> CamcorderProfile.getAll("1", CamcorderProfile.QUALITY_LOW))
.thenReturn(mockProfileLow);
+
+ when(mockProfile.getVideoProfiles()).thenReturn(mockVideoProfilesList);
+ when(mockVideoProfile.getHeight()).thenReturn(100);
+ when(mockVideoProfile.getWidth()).thenReturn(100);
}
@After
@@ -116,6 +158,39 @@
assertTrue(resolutionFeature.checkIsSupported());
}
+ @Config(maxSdk = 30)
+ @SuppressWarnings("deprecation")
+ @Test
+ public void getBestAvailableCamcorderProfileForResolutionPreset_shouldFallThroughLegacy() {
+ mockedStaticProfile
+ .when(() -> CamcorderProfile.hasProfile(1, CamcorderProfile.QUALITY_HIGH))
+ .thenReturn(false);
+ mockedStaticProfile
+ .when(() -> CamcorderProfile.hasProfile(1, CamcorderProfile.QUALITY_2160P))
+ .thenReturn(false);
+ mockedStaticProfile
+ .when(() -> CamcorderProfile.hasProfile(1, CamcorderProfile.QUALITY_1080P))
+ .thenReturn(false);
+ mockedStaticProfile
+ .when(() -> CamcorderProfile.hasProfile(1, CamcorderProfile.QUALITY_720P))
+ .thenReturn(false);
+ mockedStaticProfile
+ .when(() -> CamcorderProfile.hasProfile(1, CamcorderProfile.QUALITY_480P))
+ .thenReturn(false);
+ mockedStaticProfile
+ .when(() -> CamcorderProfile.hasProfile(1, CamcorderProfile.QUALITY_QVGA))
+ .thenReturn(false);
+ mockedStaticProfile
+ .when(() -> CamcorderProfile.hasProfile(1, CamcorderProfile.QUALITY_LOW))
+ .thenReturn(true);
+
+ assertEquals(
+ mockProfileLowLegacy,
+ ResolutionFeature.getBestAvailableCamcorderProfileForResolutionPresetLegacy(
+ 1, ResolutionPreset.max));
+ }
+
+ @Config(minSdk = 31)
@Test
public void getBestAvailableCamcorderProfileForResolutionPreset_shouldFallThrough() {
mockedStaticProfile
@@ -146,45 +221,112 @@
1, ResolutionPreset.max));
}
+ @Config(maxSdk = 30)
+ @SuppressWarnings("deprecation")
@Test
- public void computeBestPreviewSize_shouldUse720PWhenResolutionPresetMax() {
+ public void computeBestPreviewSize_shouldUse720PWhenResolutionPresetMaxLegacy() {
ResolutionFeature.computeBestPreviewSize(1, ResolutionPreset.max);
mockedStaticProfile.verify(() -> CamcorderProfile.get(1, CamcorderProfile.QUALITY_720P));
}
+ @Config(minSdk = 31)
@Test
- public void computeBestPreviewSize_shouldUse720PWhenResolutionPresetUltraHigh() {
+ public void computeBestPreviewSize_shouldUse720PWhenResolutionPresetMax() {
+ before();
+ ResolutionFeature.computeBestPreviewSize(1, ResolutionPreset.max);
+
+ mockedStaticProfile.verify(() -> CamcorderProfile.getAll("1", CamcorderProfile.QUALITY_720P));
+ }
+
+ @Config(maxSdk = 30)
+ @SuppressWarnings("deprecation")
+ @Test
+ public void computeBestPreviewSize_shouldUse720PWhenResolutionPresetUltraHighLegacy() {
ResolutionFeature.computeBestPreviewSize(1, ResolutionPreset.ultraHigh);
mockedStaticProfile.verify(() -> CamcorderProfile.get(1, CamcorderProfile.QUALITY_720P));
}
+ @Config(minSdk = 31)
@Test
- public void computeBestPreviewSize_shouldUse720PWhenResolutionPresetVeryHigh() {
+ public void computeBestPreviewSize_shouldUse720PWhenResolutionPresetUltraHigh() {
+ before();
+ ResolutionFeature.computeBestPreviewSize(1, ResolutionPreset.ultraHigh);
+
+ mockedStaticProfile.verify(() -> CamcorderProfile.getAll("1", CamcorderProfile.QUALITY_720P));
+ }
+
+ @Config(maxSdk = 30)
+ @SuppressWarnings("deprecation")
+ @Test
+ public void computeBestPreviewSize_shouldUse720PWhenResolutionPresetVeryHighLegacy() {
ResolutionFeature.computeBestPreviewSize(1, ResolutionPreset.veryHigh);
mockedStaticProfile.verify(() -> CamcorderProfile.get(1, CamcorderProfile.QUALITY_720P));
}
+ @Config(minSdk = 31)
+ @SuppressWarnings("deprecation")
@Test
- public void computeBestPreviewSize_shouldUse720PWhenResolutionPresetHigh() {
+ public void computeBestPreviewSize_shouldUse720PWhenResolutionPresetVeryHigh() {
+ before();
+ ResolutionFeature.computeBestPreviewSize(1, ResolutionPreset.veryHigh);
+
+ mockedStaticProfile.verify(() -> CamcorderProfile.getAll("1", CamcorderProfile.QUALITY_720P));
+ }
+
+ @Config(maxSdk = 30)
+ @SuppressWarnings("deprecation")
+ @Test
+ public void computeBestPreviewSize_shouldUse720PWhenResolutionPresetHighLegacy() {
ResolutionFeature.computeBestPreviewSize(1, ResolutionPreset.high);
mockedStaticProfile.verify(() -> CamcorderProfile.get(1, CamcorderProfile.QUALITY_720P));
}
+ @Config(minSdk = 31)
@Test
- public void computeBestPreviewSize_shouldUse480PWhenResolutionPresetMedium() {
+ public void computeBestPreviewSize_shouldUse720PWhenResolutionPresetHigh() {
+ before();
+ ResolutionFeature.computeBestPreviewSize(1, ResolutionPreset.high);
+
+ mockedStaticProfile.verify(() -> CamcorderProfile.getAll("1", CamcorderProfile.QUALITY_720P));
+ }
+
+ @Config(maxSdk = 30)
+ @SuppressWarnings("deprecation")
+ @Test
+ public void computeBestPreviewSize_shouldUse480PWhenResolutionPresetMediumLegacy() {
ResolutionFeature.computeBestPreviewSize(1, ResolutionPreset.medium);
mockedStaticProfile.verify(() -> CamcorderProfile.get(1, CamcorderProfile.QUALITY_480P));
}
+ @Config(minSdk = 31)
@Test
- public void computeBestPreviewSize_shouldUseQVGAWhenResolutionPresetLow() {
+ public void computeBestPreviewSize_shouldUse480PWhenResolutionPresetMedium() {
+ before();
+ ResolutionFeature.computeBestPreviewSize(1, ResolutionPreset.medium);
+
+ mockedStaticProfile.verify(() -> CamcorderProfile.getAll("1", CamcorderProfile.QUALITY_480P));
+ }
+
+ @Config(maxSdk = 30)
+ @SuppressWarnings("deprecation")
+ @Test
+ public void computeBestPreviewSize_shouldUseQVGAWhenResolutionPresetLowLegacy() {
ResolutionFeature.computeBestPreviewSize(1, ResolutionPreset.low);
mockedStaticProfile.verify(() -> CamcorderProfile.get(1, CamcorderProfile.QUALITY_QVGA));
}
+
+ @Config(minSdk = 31)
+ @Test
+ public void computeBestPreviewSize_shouldUseQVGAWhenResolutionPresetLow() {
+ before();
+ ResolutionFeature.computeBestPreviewSize(1, ResolutionPreset.low);
+
+ mockedStaticProfile.verify(() -> CamcorderProfile.getAll("1", CamcorderProfile.QUALITY_QVGA));
+ }
}
diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/sensororientation/DeviceOrientationManagerTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/sensororientation/DeviceOrientationManagerTest.java
index 58f17cb..82449a1 100644
--- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/sensororientation/DeviceOrientationManagerTest.java
+++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/sensororientation/DeviceOrientationManagerTest.java
@@ -36,6 +36,7 @@
private DeviceOrientationManager deviceOrientationManager;
@Before
+ @SuppressWarnings("deprecation")
public void before() {
mockActivity = mock(Activity.class);
mockDartMessenger = mock(DartMessenger.class);
diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/media/MediaRecorderBuilderTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/media/MediaRecorderBuilderTest.java
index 5425409..6cc58ee 100644
--- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/media/MediaRecorderBuilderTest.java
+++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/media/MediaRecorderBuilderTest.java
@@ -8,23 +8,42 @@
import static org.mockito.Mockito.*;
import android.media.CamcorderProfile;
+import android.media.EncoderProfiles;
import android.media.MediaRecorder;
import java.io.IOException;
import java.lang.reflect.Constructor;
+import java.util.List;
import org.junit.Test;
+import org.junit.runner.RunWith;
import org.mockito.InOrder;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+@RunWith(RobolectricTestRunner.class)
public class MediaRecorderBuilderTest {
+ @Config(maxSdk = 30)
+ @SuppressWarnings("deprecation")
@Test
- public void ctor_test() {
+ public void ctor_testLegacy() {
MediaRecorderBuilder builder =
new MediaRecorderBuilder(CamcorderProfile.get(CamcorderProfile.QUALITY_1080P), "");
assertNotNull(builder);
}
+ @Config(minSdk = 31)
@Test
- public void build_shouldSetValuesInCorrectOrderWhenAudioIsDisabled() throws IOException {
+ public void ctor_test() {
+ MediaRecorderBuilder builder =
+ new MediaRecorderBuilder(CamcorderProfile.getAll("0", CamcorderProfile.QUALITY_1080P), "");
+
+ assertNotNull(builder);
+ }
+
+ @Config(maxSdk = 30)
+ @SuppressWarnings("deprecation")
+ @Test
+ public void build_shouldSetValuesInCorrectOrderWhenAudioIsDisabledLegacy() throws IOException {
CamcorderProfile recorderProfile = getEmptyCamcorderProfile();
MediaRecorderBuilder.MediaRecorderFactory mockFactory =
mock(MediaRecorderBuilder.MediaRecorderFactory.class);
@@ -54,8 +73,67 @@
inOrder.verify(recorder).prepare();
}
+ @Config(minSdk = 31)
@Test
- public void build_shouldSetValuesInCorrectOrderWhenAudioIsEnabled() throws IOException {
+ public void build_shouldSetValuesInCorrectOrderWhenAudioIsDisabled() throws IOException {
+ EncoderProfiles recorderProfile = mock(EncoderProfiles.class);
+ List<EncoderProfiles.VideoProfile> mockVideoProfiles =
+ List.of(mock(EncoderProfiles.VideoProfile.class));
+ List<EncoderProfiles.AudioProfile> mockAudioProfiles =
+ List.of(mock(EncoderProfiles.AudioProfile.class));
+ MediaRecorderBuilder.MediaRecorderFactory mockFactory =
+ mock(MediaRecorderBuilder.MediaRecorderFactory.class);
+ MediaRecorder mockMediaRecorder = mock(MediaRecorder.class);
+ String outputFilePath = "mock_video_file_path";
+ int mediaOrientation = 1;
+ MediaRecorderBuilder builder =
+ new MediaRecorderBuilder(recorderProfile, outputFilePath, mockFactory)
+ .setEnableAudio(false)
+ .setMediaOrientation(mediaOrientation);
+
+ when(mockFactory.makeMediaRecorder()).thenReturn(mockMediaRecorder);
+ when(recorderProfile.getVideoProfiles()).thenReturn(mockVideoProfiles);
+ when(recorderProfile.getAudioProfiles()).thenReturn(mockAudioProfiles);
+
+ MediaRecorder recorder = builder.build();
+
+ EncoderProfiles.VideoProfile videoProfile = mockVideoProfiles.get(0);
+
+ InOrder inOrder = inOrder(recorder);
+ inOrder.verify(recorder).setVideoSource(MediaRecorder.VideoSource.SURFACE);
+ inOrder.verify(recorder).setOutputFormat(recorderProfile.getRecommendedFileFormat());
+ inOrder.verify(recorder).setVideoEncoder(videoProfile.getCodec());
+ inOrder.verify(recorder).setVideoEncodingBitRate(videoProfile.getBitrate());
+ inOrder.verify(recorder).setVideoFrameRate(videoProfile.getFrameRate());
+ inOrder.verify(recorder).setVideoSize(videoProfile.getWidth(), videoProfile.getHeight());
+ inOrder.verify(recorder).setOutputFile(outputFilePath);
+ inOrder.verify(recorder).setOrientationHint(mediaOrientation);
+ inOrder.verify(recorder).prepare();
+ }
+
+ @Config(minSdk = 31)
+ @Test(expected = IndexOutOfBoundsException.class)
+ public void build_shouldThrowExceptionWithoutVideoOrAudioProfiles() throws IOException {
+ EncoderProfiles recorderProfile = mock(EncoderProfiles.class);
+ MediaRecorderBuilder.MediaRecorderFactory mockFactory =
+ mock(MediaRecorderBuilder.MediaRecorderFactory.class);
+ MediaRecorder mockMediaRecorder = mock(MediaRecorder.class);
+ String outputFilePath = "mock_video_file_path";
+ int mediaOrientation = 1;
+ MediaRecorderBuilder builder =
+ new MediaRecorderBuilder(recorderProfile, outputFilePath, mockFactory)
+ .setEnableAudio(false)
+ .setMediaOrientation(mediaOrientation);
+
+ when(mockFactory.makeMediaRecorder()).thenReturn(mockMediaRecorder);
+
+ MediaRecorder recorder = builder.build();
+ }
+
+ @Config(maxSdk = 30)
+ @SuppressWarnings("deprecation")
+ @Test
+ public void build_shouldSetValuesInCorrectOrderWhenAudioIsEnabledLegacy() throws IOException {
CamcorderProfile recorderProfile = getEmptyCamcorderProfile();
MediaRecorderBuilder.MediaRecorderFactory mockFactory =
mock(MediaRecorderBuilder.MediaRecorderFactory.class);
@@ -89,6 +167,49 @@
inOrder.verify(recorder).prepare();
}
+ @Config(minSdk = 31)
+ @Test
+ public void build_shouldSetValuesInCorrectOrderWhenAudioIsEnabled() throws IOException {
+ EncoderProfiles recorderProfile = mock(EncoderProfiles.class);
+ List<EncoderProfiles.VideoProfile> mockVideoProfiles =
+ List.of(mock(EncoderProfiles.VideoProfile.class));
+ List<EncoderProfiles.AudioProfile> mockAudioProfiles =
+ List.of(mock(EncoderProfiles.AudioProfile.class));
+ MediaRecorderBuilder.MediaRecorderFactory mockFactory =
+ mock(MediaRecorderBuilder.MediaRecorderFactory.class);
+ MediaRecorder mockMediaRecorder = mock(MediaRecorder.class);
+ String outputFilePath = "mock_video_file_path";
+ int mediaOrientation = 1;
+ MediaRecorderBuilder builder =
+ new MediaRecorderBuilder(recorderProfile, outputFilePath, mockFactory)
+ .setEnableAudio(true)
+ .setMediaOrientation(mediaOrientation);
+
+ when(mockFactory.makeMediaRecorder()).thenReturn(mockMediaRecorder);
+ when(recorderProfile.getVideoProfiles()).thenReturn(mockVideoProfiles);
+ when(recorderProfile.getAudioProfiles()).thenReturn(mockAudioProfiles);
+
+ MediaRecorder recorder = builder.build();
+
+ EncoderProfiles.VideoProfile videoProfile = mockVideoProfiles.get(0);
+ EncoderProfiles.AudioProfile audioProfile = mockAudioProfiles.get(0);
+
+ InOrder inOrder = inOrder(recorder);
+ inOrder.verify(recorder).setAudioSource(MediaRecorder.AudioSource.MIC);
+ inOrder.verify(recorder).setVideoSource(MediaRecorder.VideoSource.SURFACE);
+ inOrder.verify(recorder).setOutputFormat(recorderProfile.getRecommendedFileFormat());
+ inOrder.verify(recorder).setAudioEncoder(audioProfile.getCodec());
+ inOrder.verify(recorder).setAudioEncodingBitRate(audioProfile.getBitrate());
+ inOrder.verify(recorder).setAudioSamplingRate(audioProfile.getSampleRate());
+ inOrder.verify(recorder).setVideoEncoder(videoProfile.getCodec());
+ inOrder.verify(recorder).setVideoEncodingBitRate(videoProfile.getBitrate());
+ inOrder.verify(recorder).setVideoFrameRate(videoProfile.getFrameRate());
+ inOrder.verify(recorder).setVideoSize(videoProfile.getWidth(), videoProfile.getHeight());
+ inOrder.verify(recorder).setOutputFile(outputFilePath);
+ inOrder.verify(recorder).setOrientationHint(mediaOrientation);
+ inOrder.verify(recorder).prepare();
+ }
+
private CamcorderProfile getEmptyCamcorderProfile() {
try {
Constructor<CamcorderProfile> constructor =
diff --git a/packages/camera/camera/android/src/test/resources/robolectric.properties b/packages/camera/camera/android/src/test/resources/robolectric.properties
new file mode 100644
index 0000000..90fbd74
--- /dev/null
+++ b/packages/camera/camera/android/src/test/resources/robolectric.properties
@@ -0,0 +1 @@
+sdk=30
\ No newline at end of file
diff --git a/packages/camera/camera/example/android/app/build.gradle b/packages/camera/camera/example/android/app/build.gradle
index 7d0e281..476d653 100644
--- a/packages/camera/camera/example/android/app/build.gradle
+++ b/packages/camera/camera/example/android/app/build.gradle
@@ -25,7 +25,7 @@
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
android {
- compileSdkVersion 29
+ compileSdkVersion 31
lintOptions {
disable 'InvalidPackage'
diff --git a/packages/camera/camera/example/android/gradle.properties b/packages/camera/camera/example/android/gradle.properties
index a673820..b253d8e 100644
--- a/packages/camera/camera/example/android/gradle.properties
+++ b/packages/camera/camera/example/android/gradle.properties
@@ -1,4 +1,4 @@
org.gradle.jvmargs=-Xmx1536M
android.useAndroidX=true
-android.enableJetifier=true
+android.enableJetifier=false
android.enableR8=true