@capgo/camera-preview 8.2.2 → 8.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -29
- package/android/build.gradle +4 -0
- package/android/src/main/java/app/capgo/capacitor/camera/preview/CameraPreview.java +87 -20
- package/android/src/main/java/app/capgo/capacitor/camera/preview/CameraXView.java +551 -157
- package/android/src/main/java/app/capgo/capacitor/camera/preview/model/CameraSessionConfiguration.java +13 -0
- package/dist/docs.json +17 -1
- package/dist/esm/definitions.d.ts +9 -1
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/web.d.ts +1 -1
- package/dist/esm/web.js +120 -92
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +119 -92
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +119 -92
- package/dist/plugin.js.map +1 -1
- package/ios/Sources/CapgoCameraPreviewPlugin/CameraController.swift +14 -12
- package/ios/Sources/CapgoCameraPreviewPlugin/Plugin.swift +16 -14
- package/package.json +8 -7
- package/android/.gradle/8.14.4/checksums/checksums.lock +0 -0
- package/android/.gradle/8.14.4/checksums/md5-checksums.bin +0 -0
- package/android/.gradle/8.14.4/checksums/sha1-checksums.bin +0 -0
- package/android/.gradle/8.14.4/executionHistory/executionHistory.bin +0 -0
- package/android/.gradle/8.14.4/executionHistory/executionHistory.lock +0 -0
- package/android/.gradle/8.14.4/fileChanges/last-build.bin +0 -0
- package/android/.gradle/8.14.4/fileHashes/fileHashes.bin +0 -0
- package/android/.gradle/8.14.4/fileHashes/fileHashes.lock +0 -0
- package/android/.gradle/8.14.4/fileHashes/resourceHashesCache.bin +0 -0
- package/android/.gradle/8.14.4/gc.properties +0 -0
- package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
- package/android/.gradle/buildOutputCleanup/cache.properties +0 -2
- package/android/.gradle/buildOutputCleanup/outputFiles.bin +0 -0
- package/android/.gradle/file-system.probe +0 -0
- package/android/.gradle/vcs-1/gc.properties +0 -0
|
@@ -96,11 +96,14 @@ import java.util.Collections;
|
|
|
96
96
|
import java.util.Date;
|
|
97
97
|
import java.util.List;
|
|
98
98
|
import java.util.Locale;
|
|
99
|
+
import java.util.Map;
|
|
99
100
|
import java.util.Objects;
|
|
100
101
|
import java.util.Set;
|
|
102
|
+
import java.util.concurrent.ConcurrentHashMap;
|
|
101
103
|
import java.util.concurrent.Executor;
|
|
102
104
|
import java.util.concurrent.ExecutorService;
|
|
103
105
|
import java.util.concurrent.Executors;
|
|
106
|
+
import java.util.concurrent.RejectedExecutionException;
|
|
104
107
|
import org.json.JSONObject;
|
|
105
108
|
|
|
106
109
|
public class CameraXView implements LifecycleOwner, LifecycleObserver {
|
|
@@ -138,6 +141,8 @@ public class CameraXView implements LifecycleOwner, LifecycleObserver {
|
|
|
138
141
|
private long focusIndicatorAnimationId = 0; // Incrementing token to invalidate previous animations
|
|
139
142
|
private CameraSelector currentCameraSelector;
|
|
140
143
|
private String currentDeviceId;
|
|
144
|
+
private String currentPhysicalDeviceId;
|
|
145
|
+
private String currentLogicalDeviceId;
|
|
141
146
|
private int currentFlashMode = ImageCapture.FLASH_MODE_OFF;
|
|
142
147
|
private CameraSessionConfiguration sessionConfig;
|
|
143
148
|
private CameraXViewListener listener;
|
|
@@ -150,6 +155,10 @@ public class CameraXView implements LifecycleOwner, LifecycleObserver {
|
|
|
150
155
|
private final LifecycleRegistry lifecycleRegistry;
|
|
151
156
|
private final Executor mainExecutor;
|
|
152
157
|
private ExecutorService cameraExecutor;
|
|
158
|
+
private static volatile Map<String, app.capgo.capacitor.camera.preview.model.CameraDevice> enumeratedDeviceCache =
|
|
159
|
+
new ConcurrentHashMap<>();
|
|
160
|
+
private static final Object enumeratedDeviceCacheLock = new Object();
|
|
161
|
+
private static volatile boolean enumeratedDeviceCacheRefreshInProgress = false;
|
|
153
162
|
private boolean isRunning = false;
|
|
154
163
|
private Size currentPreviewResolution = null;
|
|
155
164
|
private ListenableFuture<FocusMeteringResult> currentFocusFuture = null; // Track current focus operation
|
|
@@ -213,6 +222,56 @@ public class CameraXView implements LifecycleOwner, LifecycleObserver {
|
|
|
213
222
|
}
|
|
214
223
|
};
|
|
215
224
|
|
|
225
|
+
private static final class PhysicalCameraBindingTarget {
|
|
226
|
+
|
|
227
|
+
private final CameraInfo logicalCameraInfo;
|
|
228
|
+
private final String logicalCameraId;
|
|
229
|
+
private final int requiredFacing;
|
|
230
|
+
|
|
231
|
+
private PhysicalCameraBindingTarget(CameraInfo logicalCameraInfo, String logicalCameraId, int requiredFacing) {
|
|
232
|
+
this.logicalCameraInfo = logicalCameraInfo;
|
|
233
|
+
this.logicalCameraId = logicalCameraId;
|
|
234
|
+
this.requiredFacing = requiredFacing;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
private static final class PhysicalDeviceMetadata {
|
|
239
|
+
|
|
240
|
+
private final String position;
|
|
241
|
+
private final float fallbackZoom;
|
|
242
|
+
|
|
243
|
+
private PhysicalDeviceMetadata(String position, float fallbackZoom) {
|
|
244
|
+
this.position = position;
|
|
245
|
+
this.fallbackZoom = fallbackZoom;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
private static final class CameraBindingPlan {
|
|
250
|
+
|
|
251
|
+
private final CameraSelector selector;
|
|
252
|
+
private final String reportedDeviceId;
|
|
253
|
+
private final String logicalCameraId;
|
|
254
|
+
private final String physicalCameraId;
|
|
255
|
+
private final float fallbackZoom;
|
|
256
|
+
private final boolean usesPhysicalSelection;
|
|
257
|
+
|
|
258
|
+
private CameraBindingPlan(
|
|
259
|
+
CameraSelector selector,
|
|
260
|
+
String reportedDeviceId,
|
|
261
|
+
String logicalCameraId,
|
|
262
|
+
String physicalCameraId,
|
|
263
|
+
float fallbackZoom,
|
|
264
|
+
boolean usesPhysicalSelection
|
|
265
|
+
) {
|
|
266
|
+
this.selector = selector;
|
|
267
|
+
this.reportedDeviceId = reportedDeviceId;
|
|
268
|
+
this.logicalCameraId = logicalCameraId;
|
|
269
|
+
this.physicalCameraId = physicalCameraId;
|
|
270
|
+
this.fallbackZoom = fallbackZoom;
|
|
271
|
+
this.usesPhysicalSelection = usesPhysicalSelection;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
216
275
|
private boolean IsOperationRunning(String name) {
|
|
217
276
|
synchronized (operationLock) {
|
|
218
277
|
if (stopPending) {
|
|
@@ -453,6 +512,7 @@ public class CameraXView implements LifecycleOwner, LifecycleObserver {
|
|
|
453
512
|
|
|
454
513
|
this.sessionConfig = config;
|
|
455
514
|
cameraExecutor = Executors.newSingleThreadExecutor();
|
|
515
|
+
requestEnumeratedDeviceCacheRefresh();
|
|
456
516
|
|
|
457
517
|
// Reset cached orientation so we don't reuse stale values across sessions
|
|
458
518
|
synchronized (accelerometerLock) {
|
|
@@ -523,6 +583,9 @@ public class CameraXView implements LifecycleOwner, LifecycleObserver {
|
|
|
523
583
|
|
|
524
584
|
private void performImmediateStop() {
|
|
525
585
|
isRunning = false;
|
|
586
|
+
currentDeviceId = null;
|
|
587
|
+
currentPhysicalDeviceId = null;
|
|
588
|
+
currentLogicalDeviceId = null;
|
|
526
589
|
// Stop accelerometer and rotation vector sensor
|
|
527
590
|
if (sensorManager != null && accelerometer != null) {
|
|
528
591
|
sensorManager.unregisterListener(accelerometerListener);
|
|
@@ -928,7 +991,8 @@ public class CameraXView implements LifecycleOwner, LifecycleObserver {
|
|
|
928
991
|
" and position: " +
|
|
929
992
|
sessionConfig.getPosition()
|
|
930
993
|
);
|
|
931
|
-
|
|
994
|
+
CameraBindingPlan bindingPlan = buildCameraBindingPlan(sessionConfig);
|
|
995
|
+
currentCameraSelector = bindingPlan.selector;
|
|
932
996
|
|
|
933
997
|
ResolutionSelector.Builder resolutionSelectorBuilder = new ResolutionSelector.Builder().setResolutionStrategy(
|
|
934
998
|
ResolutionStrategy.HIGHEST_AVAILABLE_STRATEGY
|
|
@@ -1006,17 +1070,24 @@ public class CameraXView implements LifecycleOwner, LifecycleObserver {
|
|
|
1006
1070
|
// is connected and video frames are captured correctly
|
|
1007
1071
|
preview.setSurfaceProvider(previewView.getSurfaceProvider());
|
|
1008
1072
|
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1073
|
+
try {
|
|
1074
|
+
bindConfiguredUseCases(bindingPlan, preview);
|
|
1075
|
+
} catch (Exception initialBindError) {
|
|
1076
|
+
if (!bindingPlan.usesPhysicalSelection) {
|
|
1077
|
+
throw initialBindError;
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
Log.w(
|
|
1081
|
+
TAG,
|
|
1082
|
+
"bindCameraUseCases: Physical camera binding failed for " +
|
|
1083
|
+
bindingPlan.physicalCameraId +
|
|
1084
|
+
", falling back to logical camera behavior",
|
|
1085
|
+
initialBindError
|
|
1086
|
+
);
|
|
1087
|
+
|
|
1088
|
+
bindingPlan = buildLogicalFallbackPlan(sessionConfig, bindingPlan);
|
|
1089
|
+
currentCameraSelector = bindingPlan.selector;
|
|
1090
|
+
bindConfiguredUseCases(bindingPlan, preview);
|
|
1020
1091
|
}
|
|
1021
1092
|
|
|
1022
1093
|
resetExposureCompensationToDefault();
|
|
@@ -1024,7 +1095,10 @@ public class CameraXView implements LifecycleOwner, LifecycleObserver {
|
|
|
1024
1095
|
// Log details about the active camera
|
|
1025
1096
|
Log.d(TAG, "Use cases bound. Inspecting active camera and use cases.");
|
|
1026
1097
|
CameraInfo cameraInfo = camera.getCameraInfo();
|
|
1027
|
-
Log.d(TAG, "Bound Camera ID: " +
|
|
1098
|
+
Log.d(TAG, "Bound Camera ID: " + currentLogicalDeviceId);
|
|
1099
|
+
if (currentPhysicalDeviceId != null) {
|
|
1100
|
+
Log.d(TAG, "Bound Physical Camera ID: " + currentPhysicalDeviceId);
|
|
1101
|
+
}
|
|
1028
1102
|
|
|
1029
1103
|
// Log zoom state
|
|
1030
1104
|
ZoomState zoomState = cameraInfo.getZoomState().getValue();
|
|
@@ -1100,7 +1174,11 @@ public class CameraXView implements LifecycleOwner, LifecycleObserver {
|
|
|
1100
1174
|
previewView.setScaleType("cover".equals(aspectMode) ? PreviewView.ScaleType.FILL_CENTER : PreviewView.ScaleType.FIT_CENTER);
|
|
1101
1175
|
|
|
1102
1176
|
// Set initial zoom if specified, prioritizing targetZoom over default zoomFactor
|
|
1103
|
-
float initialZoom =
|
|
1177
|
+
float initialZoom = !bindingPlan.usesPhysicalSelection &&
|
|
1178
|
+
bindingPlan.fallbackZoom != 1.0f &&
|
|
1179
|
+
sessionConfig.getTargetZoom() == 1.0f
|
|
1180
|
+
? bindingPlan.fallbackZoom
|
|
1181
|
+
: (sessionConfig.getTargetZoom() != 1.0f ? sessionConfig.getTargetZoom() : sessionConfig.getZoomFactor());
|
|
1104
1182
|
if (initialZoom != 1.0f) {
|
|
1105
1183
|
Log.d(TAG, "Applying initial zoom of " + initialZoom);
|
|
1106
1184
|
|
|
@@ -1170,24 +1248,320 @@ public class CameraXView implements LifecycleOwner, LifecycleObserver {
|
|
|
1170
1248
|
|
|
1171
1249
|
@OptIn(markerClass = ExperimentalCamera2Interop.class)
|
|
1172
1250
|
private CameraSelector buildCameraSelector() {
|
|
1173
|
-
|
|
1174
|
-
|
|
1251
|
+
return buildCameraBindingPlan(sessionConfig).selector;
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
@OptIn(markerClass = ExperimentalCamera2Interop.class)
|
|
1255
|
+
private CameraBindingPlan buildCameraBindingPlan(CameraSessionConfiguration config) {
|
|
1256
|
+
final String deviceId = config.getDeviceId();
|
|
1257
|
+
final String position = config.getPosition();
|
|
1175
1258
|
|
|
1176
1259
|
if (deviceId != null && !deviceId.isEmpty()) {
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1260
|
+
CameraInfo directCameraInfo = findAvailableCameraInfoById(deviceId);
|
|
1261
|
+
if (directCameraInfo != null) {
|
|
1262
|
+
CameraSelector.Builder directBuilder = new CameraSelector.Builder();
|
|
1263
|
+
directBuilder.addCameraFilter((cameraInfos) -> {
|
|
1264
|
+
for (CameraInfo cameraInfo : cameraInfos) {
|
|
1265
|
+
if (deviceId.equals(Camera2CameraInfo.from(cameraInfo).getCameraId())) {
|
|
1266
|
+
return Collections.singletonList(cameraInfo);
|
|
1267
|
+
}
|
|
1181
1268
|
}
|
|
1269
|
+
return Collections.emptyList();
|
|
1270
|
+
});
|
|
1271
|
+
|
|
1272
|
+
return new CameraBindingPlan(directBuilder.build(), deviceId, deviceId, null, 1.0f, false);
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1275
|
+
CameraBindingPlan logicalFallbackPlan = buildLogicalFallbackPlanForDeviceId(deviceId);
|
|
1276
|
+
if (config.isPhysicalDeviceSelectionEnabled()) {
|
|
1277
|
+
PhysicalCameraBindingTarget physicalTarget = findPhysicalCameraBindingTarget(deviceId);
|
|
1278
|
+
if (physicalTarget != null) {
|
|
1279
|
+
CameraSelector.Builder physicalBuilder = new CameraSelector.Builder()
|
|
1280
|
+
.requireLensFacing(physicalTarget.requiredFacing)
|
|
1281
|
+
.setPhysicalCameraId(deviceId)
|
|
1282
|
+
.addCameraFilter((cameraInfos) -> {
|
|
1283
|
+
for (CameraInfo cameraInfo : cameraInfos) {
|
|
1284
|
+
if (physicalTarget.logicalCameraId.equals(Camera2CameraInfo.from(cameraInfo).getCameraId())) {
|
|
1285
|
+
return Collections.singletonList(cameraInfo);
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
return Collections.emptyList();
|
|
1289
|
+
});
|
|
1290
|
+
|
|
1291
|
+
return new CameraBindingPlan(
|
|
1292
|
+
physicalBuilder.build(),
|
|
1293
|
+
deviceId,
|
|
1294
|
+
physicalTarget.logicalCameraId,
|
|
1295
|
+
deviceId,
|
|
1296
|
+
logicalFallbackPlan != null ? logicalFallbackPlan.fallbackZoom : getFallbackZoomForDeviceId(deviceId),
|
|
1297
|
+
true
|
|
1298
|
+
);
|
|
1182
1299
|
}
|
|
1183
|
-
|
|
1184
|
-
|
|
1300
|
+
}
|
|
1301
|
+
|
|
1302
|
+
if (logicalFallbackPlan != null) {
|
|
1303
|
+
return logicalFallbackPlan;
|
|
1304
|
+
}
|
|
1305
|
+
|
|
1306
|
+
throw invalidDeviceId(deviceId);
|
|
1307
|
+
}
|
|
1308
|
+
|
|
1309
|
+
return buildPositionPlan(position);
|
|
1310
|
+
}
|
|
1311
|
+
|
|
1312
|
+
private CameraBindingPlan buildLogicalFallbackPlan(CameraSessionConfiguration config, CameraBindingPlan failedPhysicalPlan) {
|
|
1313
|
+
String fallbackPosition = config.getPosition();
|
|
1314
|
+
|
|
1315
|
+
if (failedPhysicalPlan.logicalCameraId != null) {
|
|
1316
|
+
CameraInfo logicalCameraInfo = findAvailableCameraInfoById(failedPhysicalPlan.logicalCameraId);
|
|
1317
|
+
if (logicalCameraInfo != null) {
|
|
1318
|
+
fallbackPosition = isBackCamera(logicalCameraInfo) ? "rear" : "front";
|
|
1319
|
+
}
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1322
|
+
CameraBindingPlan positionPlan = buildPositionPlan(fallbackPosition);
|
|
1323
|
+
return new CameraBindingPlan(
|
|
1324
|
+
positionPlan.selector,
|
|
1325
|
+
failedPhysicalPlan.reportedDeviceId,
|
|
1326
|
+
positionPlan.logicalCameraId,
|
|
1327
|
+
null,
|
|
1328
|
+
failedPhysicalPlan.fallbackZoom,
|
|
1329
|
+
false
|
|
1330
|
+
);
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1333
|
+
private CameraBindingPlan buildLogicalFallbackPlanForDeviceId(String deviceId) {
|
|
1334
|
+
String fallbackPosition = resolveFallbackPositionForDeviceId(deviceId);
|
|
1335
|
+
if (fallbackPosition == null) {
|
|
1336
|
+
return null;
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1339
|
+
CameraBindingPlan positionPlan = buildPositionPlan(fallbackPosition);
|
|
1340
|
+
return new CameraBindingPlan(
|
|
1341
|
+
positionPlan.selector,
|
|
1342
|
+
deviceId,
|
|
1343
|
+
positionPlan.logicalCameraId,
|
|
1344
|
+
null,
|
|
1345
|
+
getFallbackZoomForDeviceId(deviceId),
|
|
1346
|
+
false
|
|
1347
|
+
);
|
|
1348
|
+
}
|
|
1349
|
+
|
|
1350
|
+
private CameraBindingPlan buildPositionPlan(String position) {
|
|
1351
|
+
int requiredFacing = "front".equals(position) ? CameraSelector.LENS_FACING_FRONT : CameraSelector.LENS_FACING_BACK;
|
|
1352
|
+
CameraSelector selector = new CameraSelector.Builder().requireLensFacing(requiredFacing).build();
|
|
1353
|
+
return new CameraBindingPlan(selector, null, null, null, 1.0f, false);
|
|
1354
|
+
}
|
|
1355
|
+
|
|
1356
|
+
private IllegalArgumentException invalidDeviceId(String deviceId) {
|
|
1357
|
+
return new IllegalArgumentException("Unknown or unsupported deviceId: " + deviceId);
|
|
1358
|
+
}
|
|
1359
|
+
|
|
1360
|
+
private CameraInfo findAvailableCameraInfoById(String deviceId) {
|
|
1361
|
+
if (cameraProvider == null || deviceId == null || deviceId.isEmpty()) {
|
|
1362
|
+
return null;
|
|
1363
|
+
}
|
|
1364
|
+
|
|
1365
|
+
for (CameraInfo cameraInfo : cameraProvider.getAvailableCameraInfos()) {
|
|
1366
|
+
if (deviceId.equals(Camera2CameraInfo.from(cameraInfo).getCameraId())) {
|
|
1367
|
+
return cameraInfo;
|
|
1368
|
+
}
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1371
|
+
return null;
|
|
1372
|
+
}
|
|
1373
|
+
|
|
1374
|
+
@OptIn(markerClass = ExperimentalCamera2Interop.class)
|
|
1375
|
+
private PhysicalCameraBindingTarget findPhysicalCameraBindingTarget(String physicalDeviceId) {
|
|
1376
|
+
if (
|
|
1377
|
+
cameraProvider == null ||
|
|
1378
|
+
physicalDeviceId == null ||
|
|
1379
|
+
physicalDeviceId.isEmpty() ||
|
|
1380
|
+
Build.VERSION.SDK_INT < Build.VERSION_CODES.P
|
|
1381
|
+
) {
|
|
1382
|
+
return null;
|
|
1383
|
+
}
|
|
1384
|
+
|
|
1385
|
+
CameraManager cameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
|
|
1386
|
+
if (cameraManager == null) {
|
|
1387
|
+
return null;
|
|
1388
|
+
}
|
|
1389
|
+
|
|
1390
|
+
for (CameraInfo cameraInfo : cameraProvider.getAvailableCameraInfos()) {
|
|
1391
|
+
String logicalCameraId = Camera2CameraInfo.from(cameraInfo).getCameraId();
|
|
1392
|
+
try {
|
|
1393
|
+
CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(logicalCameraId);
|
|
1394
|
+
if (characteristics.getPhysicalCameraIds().contains(physicalDeviceId)) {
|
|
1395
|
+
int requiredFacing = isBackCamera(cameraInfo) ? CameraSelector.LENS_FACING_BACK : CameraSelector.LENS_FACING_FRONT;
|
|
1396
|
+
return new PhysicalCameraBindingTarget(cameraInfo, logicalCameraId, requiredFacing);
|
|
1397
|
+
}
|
|
1398
|
+
} catch (CameraAccessException e) {
|
|
1399
|
+
Log.w(TAG, "findPhysicalCameraBindingTarget: Failed to inspect logical camera " + logicalCameraId, e);
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1402
|
+
|
|
1403
|
+
return null;
|
|
1404
|
+
}
|
|
1405
|
+
|
|
1406
|
+
private PhysicalDeviceMetadata resolvePhysicalDeviceMetadata(String deviceId) {
|
|
1407
|
+
if (deviceId == null || deviceId.isEmpty()) {
|
|
1408
|
+
return null;
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1411
|
+
CameraManager cameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
|
|
1412
|
+
if (cameraManager == null) {
|
|
1413
|
+
return null;
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1416
|
+
try {
|
|
1417
|
+
CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(deviceId);
|
|
1418
|
+
Integer lensFacing = characteristics.get(CameraCharacteristics.LENS_FACING);
|
|
1419
|
+
String position = lensFacing != null && lensFacing == CameraCharacteristics.LENS_FACING_FRONT ? "front" : "rear";
|
|
1420
|
+
return new PhysicalDeviceMetadata(position, getFallbackZoomForCharacteristics(characteristics));
|
|
1421
|
+
} catch (CameraAccessException | IllegalArgumentException e) {
|
|
1422
|
+
Log.w(TAG, "resolvePhysicalDeviceMetadata: Failed to inspect camera " + deviceId, e);
|
|
1423
|
+
return null;
|
|
1424
|
+
}
|
|
1425
|
+
}
|
|
1426
|
+
|
|
1427
|
+
private String resolveFallbackPositionForDeviceId(String deviceId) {
|
|
1428
|
+
app.capgo.capacitor.camera.preview.model.CameraDevice device = findEnumeratedDeviceById(deviceId);
|
|
1429
|
+
if (device != null) {
|
|
1430
|
+
return device.getPosition();
|
|
1431
|
+
}
|
|
1432
|
+
|
|
1433
|
+
PhysicalDeviceMetadata metadata = resolvePhysicalDeviceMetadata(deviceId);
|
|
1434
|
+
return metadata != null ? metadata.position : null;
|
|
1435
|
+
}
|
|
1436
|
+
|
|
1437
|
+
private app.capgo.capacitor.camera.preview.model.CameraDevice findEnumeratedDeviceById(String deviceId) {
|
|
1438
|
+
if (deviceId == null || deviceId.isEmpty()) {
|
|
1439
|
+
return null;
|
|
1440
|
+
}
|
|
1441
|
+
|
|
1442
|
+
app.capgo.capacitor.camera.preview.model.CameraDevice cachedDevice = enumeratedDeviceCache.get(deviceId);
|
|
1443
|
+
if (cachedDevice != null) {
|
|
1444
|
+
return cachedDevice;
|
|
1445
|
+
}
|
|
1446
|
+
|
|
1447
|
+
requestEnumeratedDeviceCacheRefresh();
|
|
1448
|
+
return null;
|
|
1449
|
+
}
|
|
1450
|
+
|
|
1451
|
+
private float getFallbackZoomForDeviceId(String deviceId) {
|
|
1452
|
+
app.capgo.capacitor.camera.preview.model.CameraDevice device = findEnumeratedDeviceById(deviceId);
|
|
1453
|
+
if (device != null) {
|
|
1454
|
+
for (LensInfo lens : device.getLenses()) {
|
|
1455
|
+
if ("ultraWide".equals(lens.getDeviceType())) {
|
|
1456
|
+
return 0.5f;
|
|
1457
|
+
}
|
|
1458
|
+
if ("telephoto".equals(lens.getDeviceType())) {
|
|
1459
|
+
return 2.0f;
|
|
1460
|
+
}
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
|
|
1464
|
+
PhysicalDeviceMetadata metadata = resolvePhysicalDeviceMetadata(deviceId);
|
|
1465
|
+
if (metadata != null) {
|
|
1466
|
+
return metadata.fallbackZoom;
|
|
1467
|
+
}
|
|
1468
|
+
|
|
1469
|
+
return 1.0f;
|
|
1470
|
+
}
|
|
1471
|
+
|
|
1472
|
+
private float getFallbackZoomForCharacteristics(CameraCharacteristics characteristics) {
|
|
1473
|
+
float[] focalLengths = characteristics.get(CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS);
|
|
1474
|
+
android.util.SizeF sensorSize = characteristics.get(CameraCharacteristics.SENSOR_INFO_PHYSICAL_SIZE);
|
|
1475
|
+
|
|
1476
|
+
if (focalLengths != null && focalLengths.length > 0) {
|
|
1477
|
+
float focalLength = focalLengths[0];
|
|
1478
|
+
if (sensorSize != null && sensorSize.getWidth() > 0) {
|
|
1479
|
+
double fov = 2 * Math.toDegrees(Math.atan(sensorSize.getWidth() / (2 * focalLength)));
|
|
1480
|
+
if (fov > 90) {
|
|
1481
|
+
return 0.5f;
|
|
1482
|
+
}
|
|
1483
|
+
if (fov < 40) {
|
|
1484
|
+
return 2.0f;
|
|
1485
|
+
}
|
|
1486
|
+
} else {
|
|
1487
|
+
if (focalLength < 3.0f) {
|
|
1488
|
+
return 0.5f;
|
|
1489
|
+
}
|
|
1490
|
+
if (focalLength > 5.0f) {
|
|
1491
|
+
return 2.0f;
|
|
1492
|
+
}
|
|
1493
|
+
}
|
|
1494
|
+
}
|
|
1495
|
+
|
|
1496
|
+
return 1.0f;
|
|
1497
|
+
}
|
|
1498
|
+
|
|
1499
|
+
private void bindConfiguredUseCases(CameraBindingPlan bindingPlan, Preview preview) {
|
|
1500
|
+
if (sessionConfig.isVideoModeEnabled() && videoCapture != null) {
|
|
1501
|
+
camera = cameraProvider.bindToLifecycle(this, bindingPlan.selector, preview, imageCapture, videoCapture);
|
|
1185
1502
|
} else {
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1503
|
+
camera = cameraProvider.bindToLifecycle(this, bindingPlan.selector, preview, imageCapture);
|
|
1504
|
+
}
|
|
1505
|
+
|
|
1506
|
+
CameraInfo cameraInfo = camera.getCameraInfo();
|
|
1507
|
+
currentLogicalDeviceId = Camera2CameraInfo.from(cameraInfo).getCameraId();
|
|
1508
|
+
currentPhysicalDeviceId = bindingPlan.physicalCameraId;
|
|
1509
|
+
currentDeviceId = currentPhysicalDeviceId != null ? currentPhysicalDeviceId : currentLogicalDeviceId;
|
|
1510
|
+
|
|
1511
|
+
Log.d(
|
|
1512
|
+
TAG,
|
|
1513
|
+
"bindConfiguredUseCases: Camera successfully bound. activeDeviceId=" +
|
|
1514
|
+
currentDeviceId +
|
|
1515
|
+
", logicalCameraId=" +
|
|
1516
|
+
currentLogicalDeviceId +
|
|
1517
|
+
", physicalCameraId=" +
|
|
1518
|
+
currentPhysicalDeviceId
|
|
1519
|
+
);
|
|
1520
|
+
}
|
|
1521
|
+
|
|
1522
|
+
private void copyMutableSessionConfigState(CameraSessionConfiguration source, CameraSessionConfiguration target) {
|
|
1523
|
+
target.setCentered(source.isCentered());
|
|
1524
|
+
target.setTargetZoom(source.getTargetZoom());
|
|
1525
|
+
target.setEnablePhysicalDeviceSelection(source.isPhysicalDeviceSelectionEnabled());
|
|
1526
|
+
}
|
|
1527
|
+
|
|
1528
|
+
private void requestEnumeratedDeviceCacheRefresh() {
|
|
1529
|
+
synchronized (enumeratedDeviceCacheLock) {
|
|
1530
|
+
if (enumeratedDeviceCacheRefreshInProgress) {
|
|
1531
|
+
return;
|
|
1532
|
+
}
|
|
1533
|
+
enumeratedDeviceCacheRefreshInProgress = true;
|
|
1534
|
+
}
|
|
1535
|
+
|
|
1536
|
+
Runnable refreshTask = () -> {
|
|
1537
|
+
try {
|
|
1538
|
+
getAvailableDevicesStatic(context);
|
|
1539
|
+
} finally {
|
|
1540
|
+
synchronized (enumeratedDeviceCacheLock) {
|
|
1541
|
+
enumeratedDeviceCacheRefreshInProgress = false;
|
|
1542
|
+
}
|
|
1543
|
+
}
|
|
1544
|
+
};
|
|
1545
|
+
|
|
1546
|
+
if (cameraExecutor != null && !cameraExecutor.isShutdown()) {
|
|
1547
|
+
try {
|
|
1548
|
+
cameraExecutor.execute(refreshTask);
|
|
1549
|
+
return;
|
|
1550
|
+
} catch (RejectedExecutionException e) {
|
|
1551
|
+
Log.w(TAG, "requestEnumeratedDeviceCacheRefresh: cameraExecutor rejected refresh task", e);
|
|
1552
|
+
}
|
|
1553
|
+
}
|
|
1554
|
+
|
|
1555
|
+
try {
|
|
1556
|
+
Thread refreshThread = new Thread(refreshTask, "CameraPreview-DeviceCacheRefresh");
|
|
1557
|
+
refreshThread.setDaemon(true);
|
|
1558
|
+
refreshThread.start();
|
|
1559
|
+
} catch (RuntimeException e) {
|
|
1560
|
+
synchronized (enumeratedDeviceCacheLock) {
|
|
1561
|
+
enumeratedDeviceCacheRefreshInProgress = false;
|
|
1562
|
+
}
|
|
1563
|
+
throw e;
|
|
1189
1564
|
}
|
|
1190
|
-
return builder.build();
|
|
1191
1565
|
}
|
|
1192
1566
|
|
|
1193
1567
|
private static boolean isBackCamera(androidx.camera.core.CameraInfo cameraInfo) {
|
|
@@ -2273,6 +2647,7 @@ public class CameraXView implements LifecycleOwner, LifecycleObserver {
|
|
|
2273
2647
|
}
|
|
2274
2648
|
|
|
2275
2649
|
Log.d(TAG, "=== Enumeration Complete: " + devices.size() + " cameras ===");
|
|
2650
|
+
updateEnumeratedDeviceCache(devices);
|
|
2276
2651
|
return devices;
|
|
2277
2652
|
} catch (Exception e) {
|
|
2278
2653
|
Log.e(TAG, "getAvailableDevicesStatic: Error getting devices", e);
|
|
@@ -2280,6 +2655,14 @@ public class CameraXView implements LifecycleOwner, LifecycleObserver {
|
|
|
2280
2655
|
}
|
|
2281
2656
|
}
|
|
2282
2657
|
|
|
2658
|
+
private static void updateEnumeratedDeviceCache(List<app.capgo.capacitor.camera.preview.model.CameraDevice> devices) {
|
|
2659
|
+
Map<String, app.capgo.capacitor.camera.preview.model.CameraDevice> newCache = new ConcurrentHashMap<>();
|
|
2660
|
+
for (app.capgo.capacitor.camera.preview.model.CameraDevice device : devices) {
|
|
2661
|
+
newCache.put(device.getDeviceId(), device);
|
|
2662
|
+
}
|
|
2663
|
+
enumeratedDeviceCache = newCache;
|
|
2664
|
+
}
|
|
2665
|
+
|
|
2283
2666
|
public static ZoomFactors getZoomFactorsStatic() {
|
|
2284
2667
|
try {
|
|
2285
2668
|
// For static method, return default zoom factors
|
|
@@ -2357,6 +2740,9 @@ public class CameraXView implements LifecycleOwner, LifecycleObserver {
|
|
|
2357
2740
|
}
|
|
2358
2741
|
|
|
2359
2742
|
camera.getCameraControl().setZoomRatio(zoomRatio);
|
|
2743
|
+
if (sessionConfig != null) {
|
|
2744
|
+
sessionConfig.setTargetZoom(zoomRatio);
|
|
2745
|
+
}
|
|
2360
2746
|
// Note: autofocus is intentionally not triggered on zoom because it's done by CameraX
|
|
2361
2747
|
} catch (Exception e) {
|
|
2362
2748
|
Log.e(TAG, "Failed to set zoom: " + e.getMessage());
|
|
@@ -2880,53 +3266,52 @@ public class CameraXView implements LifecycleOwner, LifecycleObserver {
|
|
|
2880
3266
|
|
|
2881
3267
|
mainExecutor.execute(() -> {
|
|
2882
3268
|
try {
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
3269
|
+
CameraSessionConfiguration previousConfig = sessionConfig;
|
|
3270
|
+
CameraInfo targetCameraInfo = findAvailableCameraInfoById(deviceId);
|
|
3271
|
+
String fallbackPosition = resolveFallbackPositionForDeviceId(deviceId);
|
|
3272
|
+
String position = fallbackPosition != null ? fallbackPosition : previousConfig.getPosition();
|
|
3273
|
+
if (targetCameraInfo != null) {
|
|
3274
|
+
position = isBackCamera(targetCameraInfo) ? "rear" : "front";
|
|
3275
|
+
} else if (previousConfig.isPhysicalDeviceSelectionEnabled()) {
|
|
3276
|
+
PhysicalCameraBindingTarget physicalTarget = findPhysicalCameraBindingTarget(deviceId);
|
|
3277
|
+
if (physicalTarget != null) {
|
|
3278
|
+
position = physicalTarget.requiredFacing == CameraSelector.LENS_FACING_FRONT ? "front" : "rear";
|
|
3279
|
+
} else if (fallbackPosition == null) {
|
|
3280
|
+
Log.e(TAG, "switchToDevice: Could not resolve deviceId: " + deviceId);
|
|
3281
|
+
return;
|
|
2892
3282
|
}
|
|
3283
|
+
} else if (fallbackPosition == null) {
|
|
3284
|
+
Log.e(TAG, "switchToDevice: Could not find any CameraInfo matching deviceId: " + deviceId);
|
|
3285
|
+
return;
|
|
2893
3286
|
}
|
|
2894
3287
|
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
sessionConfig.isVideoModeEnabled(),
|
|
2920
|
-
sessionConfig.getVideoQuality()
|
|
2921
|
-
);
|
|
2922
|
-
|
|
2923
|
-
sessionConfig.setCentered(wasCentered);
|
|
3288
|
+
CameraSessionConfiguration updatedConfig = new CameraSessionConfiguration(
|
|
3289
|
+
deviceId,
|
|
3290
|
+
position,
|
|
3291
|
+
previousConfig.getX(),
|
|
3292
|
+
previousConfig.getY(),
|
|
3293
|
+
previousConfig.getWidth(),
|
|
3294
|
+
previousConfig.getHeight(),
|
|
3295
|
+
previousConfig.getPaddingBottom(),
|
|
3296
|
+
previousConfig.getToBack(),
|
|
3297
|
+
previousConfig.getStoreToFile(),
|
|
3298
|
+
previousConfig.getEnableOpacity(),
|
|
3299
|
+
previousConfig.getDisableExifHeaderStripping(),
|
|
3300
|
+
previousConfig.getDisableAudio(),
|
|
3301
|
+
previousConfig.getZoomFactor(),
|
|
3302
|
+
previousConfig.getAspectRatio(),
|
|
3303
|
+
previousConfig.getAspectMode(),
|
|
3304
|
+
previousConfig.getGridMode(),
|
|
3305
|
+
previousConfig.getDisableFocusIndicator(),
|
|
3306
|
+
previousConfig.isVideoModeEnabled(),
|
|
3307
|
+
previousConfig.getVideoQuality()
|
|
3308
|
+
);
|
|
3309
|
+
copyMutableSessionConfigState(previousConfig, updatedConfig);
|
|
3310
|
+
updatedConfig.setTargetZoom(1.0f);
|
|
3311
|
+
sessionConfig = updatedConfig;
|
|
2924
3312
|
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
} else {
|
|
2928
|
-
Log.e(TAG, "switchToDevice: Could not find any CameraInfo matching deviceId: " + deviceId);
|
|
2929
|
-
}
|
|
3313
|
+
Log.d(TAG, "switchToDevice: Updated sessionConfig with deviceId: " + deviceId);
|
|
3314
|
+
bindCameraUseCases();
|
|
2930
3315
|
} catch (Exception e) {
|
|
2931
3316
|
Log.e(TAG, "switchToDevice: Error switching camera", e);
|
|
2932
3317
|
}
|
|
@@ -2944,38 +3329,39 @@ public class CameraXView implements LifecycleOwner, LifecycleObserver {
|
|
|
2944
3329
|
boolean wasCentered = sessionConfig.isCentered();
|
|
2945
3330
|
Log.d(TAG, "flipCamera: Switching from " + currentPosition + " to " + newPosition);
|
|
2946
3331
|
|
|
3332
|
+
CameraSessionConfiguration previousConfig = sessionConfig;
|
|
2947
3333
|
sessionConfig = new CameraSessionConfiguration(
|
|
2948
3334
|
null, // deviceId - clear device ID to force position-based selection
|
|
2949
3335
|
newPosition, // position
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
|
|
3336
|
+
previousConfig.getX(), // x
|
|
3337
|
+
previousConfig.getY(), // y
|
|
3338
|
+
previousConfig.getWidth(), // width
|
|
3339
|
+
previousConfig.getHeight(), // height
|
|
3340
|
+
previousConfig.getPaddingBottom(), // paddingBottom
|
|
3341
|
+
previousConfig.isToBack(), // toBack
|
|
3342
|
+
previousConfig.isStoreToFile(), // storeToFile
|
|
3343
|
+
previousConfig.isEnableOpacity(), // enableOpacity
|
|
3344
|
+
previousConfig.isDisableExifHeaderStripping(), // disableExifHeaderStripping
|
|
3345
|
+
previousConfig.isDisableAudio(), // disableAudio
|
|
3346
|
+
previousConfig.getZoomFactor(), // zoomFactor
|
|
3347
|
+
previousConfig.getAspectRatio(), // aspectRatio
|
|
3348
|
+
previousConfig.getAspectMode(), // aspectMode
|
|
3349
|
+
previousConfig.getGridMode(), // gridMode
|
|
3350
|
+
previousConfig.getDisableFocusIndicator(), // disableFocusIndicator
|
|
3351
|
+
previousConfig.isVideoModeEnabled(), // enableVideoMode
|
|
3352
|
+
previousConfig.getVideoQuality() // videoQuality
|
|
2967
3353
|
);
|
|
2968
|
-
|
|
3354
|
+
copyMutableSessionConfigState(previousConfig, sessionConfig);
|
|
3355
|
+
sessionConfig.setTargetZoom(1.0f);
|
|
2969
3356
|
sessionConfig.setCentered(wasCentered);
|
|
2970
3357
|
|
|
2971
|
-
// Clear current device
|
|
3358
|
+
// Clear current device IDs to force position-based selection
|
|
2972
3359
|
currentDeviceId = null;
|
|
3360
|
+
currentPhysicalDeviceId = null;
|
|
3361
|
+
currentLogicalDeviceId = null;
|
|
2973
3362
|
|
|
2974
|
-
//
|
|
2975
|
-
|
|
2976
|
-
currentCameraSelector = buildCameraSelector();
|
|
2977
|
-
bindCameraUseCases();
|
|
2978
|
-
});
|
|
3363
|
+
// Rebind camera with the new position
|
|
3364
|
+
bindCameraUseCases();
|
|
2979
3365
|
}
|
|
2980
3366
|
|
|
2981
3367
|
public void setOpacity(float opacity) {
|
|
@@ -3059,32 +3445,34 @@ public class CameraXView implements LifecycleOwner, LifecycleObserver {
|
|
|
3059
3445
|
return;
|
|
3060
3446
|
}
|
|
3061
3447
|
|
|
3062
|
-
|
|
3448
|
+
CameraSessionConfiguration previousConfig = sessionConfig;
|
|
3449
|
+
String currentGridMode = previousConfig.getGridMode();
|
|
3063
3450
|
Log.d(TAG, "Changing aspect ratio from " + currentAspectRatio + " to " + aspectRatio);
|
|
3064
3451
|
Log.d(TAG, "Auto-centering will be applied (matching iOS behavior)");
|
|
3065
3452
|
|
|
3066
3453
|
// Match iOS behavior: when aspect ratio changes, always auto-center
|
|
3067
3454
|
sessionConfig = new CameraSessionConfiguration(
|
|
3068
|
-
|
|
3069
|
-
|
|
3455
|
+
previousConfig.getDeviceId(),
|
|
3456
|
+
previousConfig.getPosition(),
|
|
3070
3457
|
-1, // Force auto-center X (iOS: self.posX = -1)
|
|
3071
3458
|
-1, // Force auto-center Y (iOS: self.posY = -1)
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3459
|
+
previousConfig.getWidth(),
|
|
3460
|
+
previousConfig.getHeight(),
|
|
3461
|
+
previousConfig.getPaddingBottom(),
|
|
3462
|
+
previousConfig.getToBack(),
|
|
3463
|
+
previousConfig.getStoreToFile(),
|
|
3464
|
+
previousConfig.getEnableOpacity(),
|
|
3465
|
+
previousConfig.getDisableExifHeaderStripping(),
|
|
3466
|
+
previousConfig.getDisableAudio(),
|
|
3467
|
+
previousConfig.getZoomFactor(),
|
|
3081
3468
|
aspectRatio,
|
|
3082
|
-
|
|
3469
|
+
previousConfig.getAspectMode(),
|
|
3083
3470
|
currentGridMode,
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3471
|
+
previousConfig.getDisableFocusIndicator(),
|
|
3472
|
+
previousConfig.isVideoModeEnabled(),
|
|
3473
|
+
previousConfig.getVideoQuality()
|
|
3087
3474
|
);
|
|
3475
|
+
copyMutableSessionConfigState(previousConfig, sessionConfig);
|
|
3088
3476
|
sessionConfig.setCentered(true);
|
|
3089
3477
|
|
|
3090
3478
|
// Update layout and rebind camera with new aspect ratio
|
|
@@ -3135,32 +3523,34 @@ public class CameraXView implements LifecycleOwner, LifecycleObserver {
|
|
|
3135
3523
|
return;
|
|
3136
3524
|
}
|
|
3137
3525
|
|
|
3138
|
-
|
|
3526
|
+
CameraSessionConfiguration previousConfig = sessionConfig;
|
|
3527
|
+
String currentGridMode = previousConfig.getGridMode();
|
|
3139
3528
|
Log.d(TAG, "Forcing aspect ratio recalculation for: " + aspectRatio);
|
|
3140
3529
|
Log.d(TAG, "Auto-centering will be applied (matching iOS behavior)");
|
|
3141
3530
|
|
|
3142
3531
|
// Match iOS behavior: when aspect ratio changes, always auto-center
|
|
3143
3532
|
sessionConfig = new CameraSessionConfiguration(
|
|
3144
|
-
|
|
3145
|
-
|
|
3533
|
+
previousConfig.getDeviceId(),
|
|
3534
|
+
previousConfig.getPosition(),
|
|
3146
3535
|
-1, // Force auto-center X (iOS: self.posX = -1)
|
|
3147
3536
|
-1, // Force auto-center Y (iOS: self.posY = -1)
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
|
|
3537
|
+
previousConfig.getWidth(),
|
|
3538
|
+
previousConfig.getHeight(),
|
|
3539
|
+
previousConfig.getPaddingBottom(),
|
|
3540
|
+
previousConfig.getToBack(),
|
|
3541
|
+
previousConfig.getStoreToFile(),
|
|
3542
|
+
previousConfig.getEnableOpacity(),
|
|
3543
|
+
previousConfig.getDisableExifHeaderStripping(),
|
|
3544
|
+
previousConfig.getDisableAudio(),
|
|
3545
|
+
previousConfig.getZoomFactor(),
|
|
3157
3546
|
aspectRatio,
|
|
3158
|
-
|
|
3547
|
+
previousConfig.getAspectMode(),
|
|
3159
3548
|
currentGridMode,
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3549
|
+
previousConfig.getDisableFocusIndicator(),
|
|
3550
|
+
previousConfig.isVideoModeEnabled(),
|
|
3551
|
+
previousConfig.getVideoQuality()
|
|
3163
3552
|
);
|
|
3553
|
+
copyMutableSessionConfigState(previousConfig, sessionConfig);
|
|
3164
3554
|
sessionConfig.setCentered(true);
|
|
3165
3555
|
|
|
3166
3556
|
// Update layout and rebind camera with new aspect ratio
|
|
@@ -3203,27 +3593,29 @@ public class CameraXView implements LifecycleOwner, LifecycleObserver {
|
|
|
3203
3593
|
public void setGridMode(String gridMode) {
|
|
3204
3594
|
if (sessionConfig != null) {
|
|
3205
3595
|
Log.d(TAG, "setGridMode: Changing grid mode to: " + gridMode);
|
|
3596
|
+
CameraSessionConfiguration previousConfig = sessionConfig;
|
|
3206
3597
|
sessionConfig = new CameraSessionConfiguration(
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
|
|
3220
|
-
|
|
3221
|
-
|
|
3598
|
+
previousConfig.getDeviceId(),
|
|
3599
|
+
previousConfig.getPosition(),
|
|
3600
|
+
previousConfig.getX(),
|
|
3601
|
+
previousConfig.getY(),
|
|
3602
|
+
previousConfig.getWidth(),
|
|
3603
|
+
previousConfig.getHeight(),
|
|
3604
|
+
previousConfig.getPaddingBottom(),
|
|
3605
|
+
previousConfig.getToBack(),
|
|
3606
|
+
previousConfig.getStoreToFile(),
|
|
3607
|
+
previousConfig.getEnableOpacity(),
|
|
3608
|
+
previousConfig.getDisableExifHeaderStripping(),
|
|
3609
|
+
previousConfig.getDisableAudio(),
|
|
3610
|
+
previousConfig.getZoomFactor(),
|
|
3611
|
+
previousConfig.getAspectRatio(),
|
|
3612
|
+
previousConfig.getAspectMode(),
|
|
3222
3613
|
gridMode,
|
|
3223
|
-
|
|
3224
|
-
|
|
3225
|
-
|
|
3614
|
+
previousConfig.getDisableFocusIndicator(),
|
|
3615
|
+
previousConfig.isVideoModeEnabled(),
|
|
3616
|
+
previousConfig.getVideoQuality()
|
|
3226
3617
|
);
|
|
3618
|
+
copyMutableSessionConfigState(previousConfig, sessionConfig);
|
|
3227
3619
|
|
|
3228
3620
|
// Update the grid overlay immediately
|
|
3229
3621
|
if (gridOverlayView != null) {
|
|
@@ -3543,27 +3935,29 @@ public class CameraXView implements LifecycleOwner, LifecycleObserver {
|
|
|
3543
3935
|
);
|
|
3544
3936
|
}
|
|
3545
3937
|
|
|
3938
|
+
CameraSessionConfiguration previousConfig = sessionConfig;
|
|
3546
3939
|
sessionConfig = new CameraSessionConfiguration(
|
|
3547
|
-
|
|
3548
|
-
|
|
3940
|
+
previousConfig.getDeviceId(),
|
|
3941
|
+
previousConfig.getPosition(),
|
|
3549
3942
|
params.leftMargin,
|
|
3550
3943
|
params.topMargin,
|
|
3551
3944
|
params.width,
|
|
3552
3945
|
params.height,
|
|
3553
|
-
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
|
|
3946
|
+
previousConfig.getPaddingBottom(),
|
|
3947
|
+
previousConfig.getToBack(),
|
|
3948
|
+
previousConfig.getStoreToFile(),
|
|
3949
|
+
previousConfig.getEnableOpacity(),
|
|
3950
|
+
previousConfig.getDisableExifHeaderStripping(),
|
|
3951
|
+
previousConfig.getDisableAudio(),
|
|
3952
|
+
previousConfig.getZoomFactor(),
|
|
3560
3953
|
calculatedAspectRatio,
|
|
3561
|
-
|
|
3562
|
-
|
|
3563
|
-
|
|
3564
|
-
|
|
3565
|
-
|
|
3954
|
+
previousConfig.getAspectMode(),
|
|
3955
|
+
previousConfig.getGridMode(),
|
|
3956
|
+
previousConfig.getDisableFocusIndicator(),
|
|
3957
|
+
previousConfig.isVideoModeEnabled(),
|
|
3958
|
+
previousConfig.getVideoQuality()
|
|
3566
3959
|
);
|
|
3960
|
+
copyMutableSessionConfigState(previousConfig, sessionConfig);
|
|
3567
3961
|
|
|
3568
3962
|
// If aspect ratio changed due to size update, rebind camera
|
|
3569
3963
|
if (isRunning && !Objects.equals(currentAspectRatio, calculatedAspectRatio)) {
|