Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.

Commit e85e0f2

Browse files
lucasoskorepcamsim99stuartmorgan-g
authored
[camera] Allow logical cameras to use all physical cameras via zoom on android 11+ (#6150)
* Adding support for the android 11+ Camera2 CONTROL_ZOOM_RATIO_RANGE camera preference. This preference is essential for supporting Logical cameras on the rear which after android 11 wrap multiple cameras (ultrawide, normal, superzoom, etc) into a single rear facing camera. This updates change how zoom functions as well as how min and max zoom is set to be compliant with those updates as long as the user device is on android 11+. * Adding updates to the changelog and pubspec to reflect the zoom and camera updates. * comment cleanup for min and max zoom ratio functions * Pull request fixes * Update packages/camera/camera_android/CHANGELOG.md Co-authored-by: Camille Simon <[email protected]> * Update packages/camera/camera_android/android/src/main/java/io/flutter/plugins/camera/features/zoomlevel/ZoomUtils.java Co-authored-by: Camille Simon <[email protected]> * Updating comments from PR * Fixing variable name formatting, and comment structures * Fixing variable name formatting, and comment structures * Autogormatter updates Co-authored-by: Camille Simon <[email protected]> Co-authored-by: stuartmorgan <[email protected]>
1 parent 56ab33f commit e85e0f2

File tree

10 files changed

+191
-208
lines changed

10 files changed

+191
-208
lines changed

packages/camera/camera_android/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
## 0.10.2+2
2+
3+
* Fixes zoom computation for virtual cameras hiding physical cameras in Android 11+.
4+
* Removes the unused CameraZoom class from the codebase.
5+
16
## 0.10.2+1
27

38
* Updates code for stricter lint checks.

packages/camera/camera_android/android/src/main/java/io/flutter/plugins/camera/CameraProperties.java

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,10 +150,34 @@ public interface CameraProperties {
150150
* android.hardware.camera2.CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM key.
151151
*
152152
* @return Float Maximum ratio between both active area width and crop region width, and active
153-
* area height and crop region height
153+
* area height and crop region height.
154154
*/
155155
Float getScalerAvailableMaxDigitalZoom();
156156

157+
/**
158+
* Returns the minimum ratio between the default camera zoom setting and all of the available
159+
* zoom.
160+
*
161+
* <p>By default maps to the @see
162+
* android.hardware.camera2.CameraCharacteristics#CONTROL_ZOOM_RATIO_RANGE key's lower value.
163+
*
164+
* @return Float Minimum ratio between the default zoom ratio and the minimum possible zoom.
165+
*/
166+
@RequiresApi(api = VERSION_CODES.R)
167+
Float getScalerMinZoomRatio();
168+
169+
/**
170+
* Returns the maximum ratio between the default camera zoom setting and all of the available
171+
* zoom.
172+
*
173+
* <p>By default maps to the @see
174+
* android.hardware.camera2.CameraCharacteristics#CONTROL_ZOOM_RATIO_RANGE key's upper value.
175+
*
176+
* @return Float Maximum ratio between the default zoom ratio and the maximum possible zoom.
177+
*/
178+
@RequiresApi(api = VERSION_CODES.R)
179+
Float getScalerMaxZoomRatio();
180+
157181
/**
158182
* Returns the area of the image sensor which corresponds to active pixels after any geometric
159183
* distortion correction has been applied.
@@ -315,6 +339,18 @@ public Float getScalerAvailableMaxDigitalZoom() {
315339
return cameraCharacteristics.get(CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM);
316340
}
317341

342+
@RequiresApi(api = VERSION_CODES.R)
343+
@Override
344+
public Float getScalerMaxZoomRatio() {
345+
return cameraCharacteristics.get(CameraCharacteristics.CONTROL_ZOOM_RATIO_RANGE).getUpper();
346+
}
347+
348+
@RequiresApi(api = VERSION_CODES.R)
349+
@Override
350+
public Float getScalerMinZoomRatio() {
351+
return cameraCharacteristics.get(CameraCharacteristics.CONTROL_ZOOM_RATIO_RANGE).getLower();
352+
}
353+
318354
@Override
319355
public Rect getSensorInfoActiveArraySize() {
320356
return cameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);

packages/camera/camera_android/android/src/main/java/io/flutter/plugins/camera/CameraZoom.java

Lines changed: 0 additions & 52 deletions
This file was deleted.

packages/camera/camera_android/android/src/main/java/io/flutter/plugins/camera/features/zoomlevel/ZoomLevelFeature.java

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,18 @@
66

77
import android.graphics.Rect;
88
import android.hardware.camera2.CaptureRequest;
9+
import android.os.Build;
910
import io.flutter.plugins.camera.CameraProperties;
1011
import io.flutter.plugins.camera.features.CameraFeature;
1112

1213
/** Controls the zoom configuration on the {@link android.hardware.camera2} API. */
1314
public class ZoomLevelFeature extends CameraFeature<Float> {
14-
private static final float MINIMUM_ZOOM_LEVEL = 1.0f;
15+
private static final Float DEFAULT_ZOOM_LEVEL = 1.0f;
1516
private final boolean hasSupport;
1617
private final Rect sensorArraySize;
17-
private Float currentSetting = MINIMUM_ZOOM_LEVEL;
18-
private Float maximumZoomLevel = MINIMUM_ZOOM_LEVEL;
18+
private Float currentSetting = DEFAULT_ZOOM_LEVEL;
19+
private Float minimumZoomLevel = currentSetting;
20+
private Float maximumZoomLevel;
1921

2022
/**
2123
* Creates a new instance of the {@link ZoomLevelFeature}.
@@ -28,18 +30,24 @@ public ZoomLevelFeature(CameraProperties cameraProperties) {
2830
sensorArraySize = cameraProperties.getSensorInfoActiveArraySize();
2931

3032
if (sensorArraySize == null) {
31-
maximumZoomLevel = MINIMUM_ZOOM_LEVEL;
33+
maximumZoomLevel = minimumZoomLevel;
3234
hasSupport = false;
3335
return;
3436
}
37+
// On Android 11+ CONTROL_ZOOM_RATIO_RANGE should be use to get the zoom ratio directly as minimum zoom does not have to be 1.0f.
38+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
39+
minimumZoomLevel = cameraProperties.getScalerMinZoomRatio();
40+
maximumZoomLevel = cameraProperties.getScalerMaxZoomRatio();
41+
} else {
42+
minimumZoomLevel = DEFAULT_ZOOM_LEVEL;
43+
Float maxDigitalZoom = cameraProperties.getScalerAvailableMaxDigitalZoom();
44+
maximumZoomLevel =
45+
((maxDigitalZoom == null) || (maxDigitalZoom < minimumZoomLevel))
46+
? minimumZoomLevel
47+
: maxDigitalZoom;
48+
}
3549

36-
Float maxDigitalZoom = cameraProperties.getScalerAvailableMaxDigitalZoom();
37-
maximumZoomLevel =
38-
((maxDigitalZoom == null) || (maxDigitalZoom < MINIMUM_ZOOM_LEVEL))
39-
? MINIMUM_ZOOM_LEVEL
40-
: maxDigitalZoom;
41-
42-
hasSupport = (Float.compare(maximumZoomLevel, MINIMUM_ZOOM_LEVEL) > 0);
50+
hasSupport = (Float.compare(maximumZoomLevel, minimumZoomLevel) > 0);
4351
}
4452

4553
@Override
@@ -67,11 +75,19 @@ public void updateBuilder(CaptureRequest.Builder requestBuilder) {
6775
if (!checkIsSupported()) {
6876
return;
6977
}
70-
71-
final Rect computedZoom =
72-
ZoomUtils.computeZoom(
73-
currentSetting, sensorArraySize, MINIMUM_ZOOM_LEVEL, maximumZoomLevel);
74-
requestBuilder.set(CaptureRequest.SCALER_CROP_REGION, computedZoom);
78+
// On Android 11+ CONTROL_ZOOM_RATIO can be set to a zoom ratio and the camera feed will compute
79+
// how to zoom on its own accounting for multiple logical cameras.
80+
// Prior the image cropping window must be calculated and set manually.
81+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
82+
requestBuilder.set(
83+
CaptureRequest.CONTROL_ZOOM_RATIO,
84+
ZoomUtils.computeZoomRatio(currentSetting, minimumZoomLevel, maximumZoomLevel));
85+
} else {
86+
final Rect computedZoom =
87+
ZoomUtils.computeZoomRect(
88+
currentSetting, sensorArraySize, minimumZoomLevel, maximumZoomLevel);
89+
requestBuilder.set(CaptureRequest.SCALER_CROP_REGION, computedZoom);
90+
}
7591
}
7692

7793
/**
@@ -80,7 +96,7 @@ public void updateBuilder(CaptureRequest.Builder requestBuilder) {
8096
* @return The minimum zoom level.
8197
*/
8298
public float getMinimumZoomLevel() {
83-
return MINIMUM_ZOOM_LEVEL;
99+
return minimumZoomLevel;
84100
}
85101

86102
/**

packages/camera/camera_android/android/src/main/java/io/flutter/plugins/camera/features/zoomlevel/ZoomUtils.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,18 @@ final class ZoomUtils {
1818
* Computes an image sensor area based on the supplied zoom settings.
1919
*
2020
* <p>The returned image sensor area can be applied to the {@link android.hardware.camera2} API in
21-
* order to control zoom levels.
21+
* order to control zoom levels. This method of zoom should only be used for Android versions <=
22+
* 11 as past that, the newer {@link #computeZoomRatio()} functional can be used.
2223
*
2324
* @param zoom The desired zoom level.
2425
* @param sensorArraySize The current area of the image sensor.
2526
* @param minimumZoomLevel The minimum supported zoom level.
2627
* @param maximumZoomLevel The maximim supported zoom level.
2728
* @return An image sensor area based on the supplied zoom settings
2829
*/
29-
static Rect computeZoom(
30+
static Rect computeZoomRect(
3031
float zoom, @NonNull Rect sensorArraySize, float minimumZoomLevel, float maximumZoomLevel) {
31-
final float newZoom = MathUtils.clamp(zoom, minimumZoomLevel, maximumZoomLevel);
32+
final float newZoom = computeZoomRatio(zoom, minimumZoomLevel, maximumZoomLevel);
3233

3334
final int centerX = sensorArraySize.width() / 2;
3435
final int centerY = sensorArraySize.height() / 2;
@@ -37,4 +38,8 @@ static Rect computeZoom(
3738

3839
return new Rect(centerX - deltaX, centerY - deltaY, centerX + deltaX, centerY + deltaY);
3940
}
41+
42+
static Float computeZoomRatio(float zoom, float minimumZoomLevel, float maximumZoomLevel) {
43+
return MathUtils.clamp(zoom, minimumZoomLevel, maximumZoomLevel);
44+
}
4045
}

packages/camera/camera_android/android/src/test/java/io/flutter/plugins/camera/CameraPropertiesImplTest.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,30 @@ public void getScalerAvailableMaxDigitalZoomTest() {
201201
assertEquals(actualDigitalZoom, expectedDigitalZoom);
202202
}
203203

204+
@Test
205+
public void getScalerGetScalerMinZoomRatioTest() {
206+
Range zoomRange = mock(Range.class);
207+
when(mockCharacteristics.get(CameraCharacteristics.CONTROL_ZOOM_RATIO_RANGE))
208+
.thenReturn(zoomRange);
209+
210+
Float minZoom = cameraProperties.getScalerMinZoomRatio();
211+
212+
verify(mockCharacteristics, times(1)).get(CameraCharacteristics.CONTROL_ZOOM_RATIO_RANGE);
213+
assertEquals(zoomRange.getLower(), minZoom);
214+
}
215+
216+
@Test
217+
public void getScalerGetScalerMaxZoomRatioTest() {
218+
Range zoomRange = mock(Range.class);
219+
when(mockCharacteristics.get(CameraCharacteristics.CONTROL_ZOOM_RATIO_RANGE))
220+
.thenReturn(zoomRange);
221+
222+
Float maxZoom = cameraProperties.getScalerMaxZoomRatio();
223+
224+
verify(mockCharacteristics, times(1)).get(CameraCharacteristics.CONTROL_ZOOM_RATIO_RANGE);
225+
assertEquals(zoomRange.getUpper(), maxZoom);
226+
}
227+
204228
@Test
205229
public void getSensorInfoActiveArraySizeTest() {
206230
Rect expectedArraySize = mock(Rect.class);

packages/camera/camera_android/android/src/test/java/io/flutter/plugins/camera/CameraZoomTest.java

Lines changed: 0 additions & 125 deletions
This file was deleted.

0 commit comments

Comments
 (0)