Skip to content

Commit

Permalink
Bump Camera Example Plugin Apps Targetsdk Versions (#8193)
Browse files Browse the repository at this point in the history
Bumped targetsdk versions of example app plugins for `camera`, `camera_android`, and `camera_android_camerax`. Deleted `Capture specific image resolutions` integration. The Android CameraX team confirmed the result coming from the CameraX side is correct and works as they expect. This means the supported output sizes cannot fulfill our test case assumptions.

For 'camera_android_camerax', we use the automatic selection described [here](https://developer.android.com/media/camera/camerax/configuration#resolution), and it willl automatically choose, so we can't control the outcome. Even if we specify, the resolution is not gauranteed. 

`camera` would have the same behavior as `camera_android_camerax` because `camera`'s android implementation defaults to `camera_android_camerax` behavior.

For `camera_android` we cannot choose the aspect ratio [here](https://developer.android.com/reference/android/media/CamcorderProfile#getAll%28java.lang.String,%20int%29). If there's an unsupported size, it "falls through" to the next smallest size, which means we cannot choose the final resolution. Example high quality aspect ratio [here](https://developer.android.com/reference/android/media/CamcorderProfile#QUALITY_HIGH), and logic for final resolution [here](https://github.com/flutter/packages/blob/a02deb49c1f6bcb8bb895dd67fbf36ac2c9738bd/packages/camera/camera_android/android/src/main/java/io/flutter/plugins/camera/features/resolution/ResolutionFeature.java#L172).
 
Fixes flutter/flutter#154682
  • Loading branch information
jesswrd authored Dec 13, 2024
1 parent cb9ab42 commit 2f78047
Show file tree
Hide file tree
Showing 9 changed files with 6 additions and 145 deletions.
2 changes: 1 addition & 1 deletion packages/camera/camera/example/android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ android {
defaultConfig {
applicationId "io.flutter.plugins.cameraexample"
minSdkVersion flutter.minSdkVersion
targetSdkVersion 28
targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<activity
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection"
android:hardwareAccelerated="true"
android:exported="true"
android:launchMode="singleTop"
android:name="io.flutter.embedding.android.FlutterActivity"
android:theme="@style/LaunchTheme"
Expand Down
43 changes: 0 additions & 43 deletions packages/camera/camera/example/integration_test/camera_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -53,49 +53,6 @@ void main() {
actual.longestSide == expectedSize.longestSide;
}

// This tests that the capture is no bigger than the preset, since we have
// automatic code to fall back to smaller sizes when we need to. Returns
// whether the image is exactly the desired resolution.
Future<bool> testCaptureImageResolution(
CameraController controller, ResolutionPreset preset) async {
final Size expectedSize = presetExpectedSizes[preset]!;

// Take Picture
final XFile file = await controller.takePicture();

// Load picture
final File fileImage = File(file.path);
final Image image = await decodeImageFromList(fileImage.readAsBytesSync());

// Verify image dimensions are as expected
expect(image, isNotNull);
return assertExpectedDimensions(
expectedSize, Size(image.height.toDouble(), image.width.toDouble()));
}

testWidgets('Capture specific image resolutions',
(WidgetTester tester) async {
final List<CameraDescription> cameras = await availableCameras();
if (cameras.isEmpty) {
return;
}
for (final CameraDescription cameraDescription in cameras) {
bool previousPresetExactlySupported = true;
for (final MapEntry<ResolutionPreset, Size> preset
in presetExpectedSizes.entries) {
final CameraController controller =
CameraController(cameraDescription, preset.key);
await controller.initialize();
final bool presetExactlySupported =
await testCaptureImageResolution(controller, preset.key);
assert(!(!previousPresetExactlySupported && presetExactlySupported),
'The camera took higher resolution pictures at a lower resolution.');
previousPresetExactlySupported = presetExactlySupported;
await controller.dispose();
}
}
});

// This tests that the capture is no bigger than the preset, since we have
// automatic code to fall back to smaller sizes when we need to. Returns
// whether the image is exactly the desired resolution.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ android {
defaultConfig {
applicationId "io.flutter.plugins.cameraexample"
minSdkVersion flutter.minSdkVersion
targetSdkVersion 28
targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<activity
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection"
android:hardwareAccelerated="true"
android:exported="true"
android:launchMode="singleTop"
android:name="io.flutter.embedding.android.FlutterActivity"
android:theme="@style/LaunchTheme"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,10 @@
// found in the LICENSE file.

import 'dart:io';
import 'dart:ui';

import 'package:camera_android/camera_android.dart';
import 'package:camera_example/camera_controller.dart';
import 'package:camera_platform_interface/camera_platform_interface.dart';
import 'package:flutter/painting.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
Expand Down Expand Up @@ -50,50 +48,6 @@ void main() {
actual.longestSide == expectedSize.longestSide;
}

// This tests that the capture is no bigger than the preset, since we have
// automatic code to fall back to smaller sizes when we need to. Returns
// whether the image is exactly the desired resolution.
Future<bool> testCaptureImageResolution(
CameraController controller, ResolutionPreset preset) async {
final Size expectedSize = presetExpectedSizes[preset]!;

// Take Picture
final XFile file = await controller.takePicture();

// Load picture
final File fileImage = File(file.path);
final Image image = await decodeImageFromList(fileImage.readAsBytesSync());

// Verify image dimensions are as expected
expect(image, isNotNull);
return assertExpectedDimensions(
expectedSize, Size(image.height.toDouble(), image.width.toDouble()));
}

testWidgets('Capture specific image resolutions',
(WidgetTester tester) async {
final List<CameraDescription> cameras =
await CameraPlatform.instance.availableCameras();
if (cameras.isEmpty) {
return;
}
for (final CameraDescription cameraDescription in cameras) {
bool previousPresetExactlySupported = true;
for (final MapEntry<ResolutionPreset, Size> preset
in presetExpectedSizes.entries) {
final CameraController controller = CameraController(cameraDescription,
mediaSettings: MediaSettings(resolutionPreset: preset.key));
await controller.initialize();
final bool presetExactlySupported =
await testCaptureImageResolution(controller, preset.key);
assert(!(!previousPresetExactlySupported && presetExactlySupported),
'The camera took higher resolution pictures at a lower resolution.');
previousPresetExactlySupported = presetExactlySupported;
await controller.dispose();
}
}
});

// This tests that the capture is no bigger than the preset, since we have
// automatic code to fall back to smaller sizes when we need to. Returns
// whether the image is exactly the desired resolution.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ android {
defaultConfig {
applicationId "io.flutter.plugins.cameraxexample"
minSdkVersion flutter.minSdkVersion
targetSdkVersion 30
targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:exported="true"
android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import 'package:camera_android_camerax/camera_android_camerax.dart';
import 'package:camera_android_camerax_example/camera_controller.dart';
import 'package:camera_android_camerax_example/camera_image.dart';
import 'package:camera_platform_interface/camera_platform_interface.dart';
import 'package:flutter/painting.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:video_player/video_player.dart';
Expand Down Expand Up @@ -46,26 +45,6 @@ void main() {
actual.longestSide == expectedSize.longestSide;
}

// This tests that the capture is no bigger than the preset, since we have
// automatic code to fall back to smaller sizes when we need to. Returns
// whether the image is exactly the desired resolution.
Future<bool> testCaptureImageResolution(
CameraController controller, ResolutionPreset preset) async {
final Size expectedSize = presetExpectedSizes[preset]!;

// Take Picture
final XFile file = await controller.takePicture();

// Load picture
final File fileImage = File(file.path);
final Image image = await decodeImageFromList(fileImage.readAsBytesSync());

// Verify image dimensions are as expected
expect(image, isNotNull);
return assertExpectedDimensions(
expectedSize, Size(image.height.toDouble(), image.width.toDouble()));
}

testWidgets('availableCameras only supports valid back or front cameras',
(WidgetTester tester) async {
final List<CameraDescription> availableCameras =
Expand All @@ -78,37 +57,6 @@ void main() {
}
});

testWidgets('Capture specific image resolutions',
(WidgetTester tester) async {
final List<CameraDescription> cameras =
await CameraPlatform.instance.availableCameras();
if (cameras.isEmpty) {
return;
}
for (final CameraDescription cameraDescription in cameras) {
bool previousPresetExactlySupported = true;
for (final MapEntry<ResolutionPreset, Size> preset
in presetExpectedSizes.entries) {
final CameraController controller = CameraController(
cameraDescription,
mediaSettings: MediaSettings(resolutionPreset: preset.key),
);
await controller.initialize();
final bool presetExactlySupported =
await testCaptureImageResolution(controller, preset.key);
// Ensures that if a lower resolution was used for previous (lower)
// resolution preset, then the current (higher) preset also is adjusted,
// as it demands a higher resolution.
expect(
previousPresetExactlySupported || !presetExactlySupported, isTrue,
reason:
'The camera took higher resolution pictures at a lower resolution.');
previousPresetExactlySupported = presetExactlySupported;
await controller.dispose();
}
}
});

testWidgets('Preview takes expected resolution from preset',
(WidgetTester tester) async {
final List<CameraDescription> cameras =
Expand Down

0 comments on commit 2f78047

Please sign in to comment.