@capgo/camera-preview 7.4.0-beta.2 → 7.4.0-beta.21
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 +218 -35
- package/android/.gradle/8.14.2/checksums/checksums.lock +0 -0
- package/android/.gradle/8.14.2/checksums/md5-checksums.bin +0 -0
- package/android/.gradle/8.14.2/checksums/sha1-checksums.bin +0 -0
- package/android/.gradle/8.14.2/executionHistory/executionHistory.bin +0 -0
- package/android/.gradle/8.14.2/executionHistory/executionHistory.lock +0 -0
- package/android/.gradle/8.14.2/fileHashes/fileHashes.bin +0 -0
- package/android/.gradle/8.14.2/fileHashes/fileHashes.lock +0 -0
- package/android/.gradle/8.14.2/fileHashes/resourceHashesCache.bin +0 -0
- package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
- package/android/.gradle/file-system.probe +0 -0
- package/android/build.gradle +3 -1
- package/android/src/main/AndroidManifest.xml +1 -4
- package/android/src/main/java/com/ahm/capacitor/camera/preview/CameraPreview.java +759 -83
- package/android/src/main/java/com/ahm/capacitor/camera/preview/CameraXView.java +2813 -805
- package/android/src/main/java/com/ahm/capacitor/camera/preview/GridOverlayView.java +112 -0
- package/android/src/main/java/com/ahm/capacitor/camera/preview/model/CameraDevice.java +55 -46
- package/android/src/main/java/com/ahm/capacitor/camera/preview/model/CameraLens.java +61 -52
- package/android/src/main/java/com/ahm/capacitor/camera/preview/model/CameraSessionConfiguration.java +161 -59
- package/android/src/main/java/com/ahm/capacitor/camera/preview/model/LensInfo.java +29 -23
- package/android/src/main/java/com/ahm/capacitor/camera/preview/model/ZoomFactors.java +24 -23
- package/dist/docs.json +333 -29
- package/dist/esm/definitions.d.ts +156 -13
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/web.d.ts +52 -3
- package/dist/esm/web.js +592 -95
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +590 -95
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +590 -95
- package/dist/plugin.js.map +1 -1
- package/ios/Sources/CapgoCameraPreview/CameraController.swift +907 -222
- package/ios/Sources/CapgoCameraPreview/GridOverlayView.swift +65 -0
- package/ios/Sources/CapgoCameraPreview/Plugin.swift +986 -250
- package/package.json +2 -2
|
@@ -3,11 +3,22 @@ package com.ahm.capacitor.camera.preview;
|
|
|
3
3
|
import static android.Manifest.permission.CAMERA;
|
|
4
4
|
import static android.Manifest.permission.RECORD_AUDIO;
|
|
5
5
|
|
|
6
|
+
import android.Manifest;
|
|
6
7
|
import android.content.pm.ActivityInfo;
|
|
8
|
+
import android.location.Location;
|
|
7
9
|
import android.util.DisplayMetrics;
|
|
8
|
-
import android.util.
|
|
10
|
+
import android.util.Log;
|
|
11
|
+
import android.util.Size;
|
|
12
|
+
import android.view.View;
|
|
13
|
+
import android.view.ViewGroup;
|
|
14
|
+
import android.webkit.WebView;
|
|
15
|
+
import com.ahm.capacitor.camera.preview.model.CameraDevice;
|
|
16
|
+
import com.ahm.capacitor.camera.preview.model.CameraSessionConfiguration;
|
|
17
|
+
import com.ahm.capacitor.camera.preview.model.LensInfo;
|
|
18
|
+
import com.ahm.capacitor.camera.preview.model.ZoomFactors;
|
|
9
19
|
import com.getcapacitor.JSArray;
|
|
10
20
|
import com.getcapacitor.JSObject;
|
|
21
|
+
import com.getcapacitor.Logger;
|
|
11
22
|
import com.getcapacitor.PermissionState;
|
|
12
23
|
import com.getcapacitor.Plugin;
|
|
13
24
|
import com.getcapacitor.PluginCall;
|
|
@@ -15,15 +26,10 @@ import com.getcapacitor.PluginMethod;
|
|
|
15
26
|
import com.getcapacitor.annotation.CapacitorPlugin;
|
|
16
27
|
import com.getcapacitor.annotation.Permission;
|
|
17
28
|
import com.getcapacitor.annotation.PermissionCallback;
|
|
18
|
-
import com.
|
|
19
|
-
import com.
|
|
20
|
-
import com.ahm.capacitor.camera.preview.model.ZoomFactors;
|
|
29
|
+
import com.google.android.gms.location.FusedLocationProviderClient;
|
|
30
|
+
import com.google.android.gms.location.LocationServices;
|
|
21
31
|
import java.util.List;
|
|
22
32
|
import java.util.Objects;
|
|
23
|
-
import android.util.Size;
|
|
24
|
-
import android.util.Log;
|
|
25
|
-
import com.ahm.capacitor.camera.preview.model.LensInfo;
|
|
26
|
-
|
|
27
33
|
import org.json.JSONObject;
|
|
28
34
|
|
|
29
35
|
@CapacitorPlugin(
|
|
@@ -37,6 +43,13 @@ import org.json.JSONObject;
|
|
|
37
43
|
strings = { CAMERA },
|
|
38
44
|
alias = CameraPreview.CAMERA_ONLY_PERMISSION_ALIAS
|
|
39
45
|
),
|
|
46
|
+
@Permission(
|
|
47
|
+
strings = {
|
|
48
|
+
Manifest.permission.ACCESS_COARSE_LOCATION,
|
|
49
|
+
Manifest.permission.ACCESS_FINE_LOCATION,
|
|
50
|
+
},
|
|
51
|
+
alias = CameraPreview.CAMERA_WITH_LOCATION_PERMISSION_ALIAS
|
|
52
|
+
),
|
|
40
53
|
}
|
|
41
54
|
)
|
|
42
55
|
public class CameraPreview
|
|
@@ -45,16 +58,23 @@ public class CameraPreview
|
|
|
45
58
|
|
|
46
59
|
static final String CAMERA_WITH_AUDIO_PERMISSION_ALIAS = "cameraWithAudio";
|
|
47
60
|
static final String CAMERA_ONLY_PERMISSION_ALIAS = "cameraOnly";
|
|
61
|
+
static final String CAMERA_WITH_LOCATION_PERMISSION_ALIAS =
|
|
62
|
+
"cameraWithLocation";
|
|
48
63
|
|
|
49
64
|
private String captureCallbackId = "";
|
|
50
65
|
private String snapshotCallbackId = "";
|
|
51
66
|
private String cameraStartCallbackId = "";
|
|
52
|
-
private int previousOrientationRequest =
|
|
67
|
+
private int previousOrientationRequest =
|
|
68
|
+
ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
|
|
53
69
|
private CameraXView cameraXView;
|
|
70
|
+
private FusedLocationProviderClient fusedLocationClient;
|
|
71
|
+
private Location lastLocation;
|
|
54
72
|
|
|
55
73
|
@PluginMethod
|
|
56
74
|
public void start(PluginCall call) {
|
|
57
|
-
boolean disableAudio = Boolean.TRUE.equals(
|
|
75
|
+
boolean disableAudio = Boolean.TRUE.equals(
|
|
76
|
+
call.getBoolean("disableAudio", true)
|
|
77
|
+
);
|
|
58
78
|
String permissionAlias = disableAudio
|
|
59
79
|
? CAMERA_ONLY_PERMISSION_ALIAS
|
|
60
80
|
: CAMERA_WITH_AUDIO_PERMISSION_ALIAS;
|
|
@@ -87,12 +107,74 @@ public class CameraPreview
|
|
|
87
107
|
return;
|
|
88
108
|
}
|
|
89
109
|
|
|
110
|
+
final boolean withExifLocation = call.getBoolean("withExifLocation", false);
|
|
111
|
+
|
|
112
|
+
if (withExifLocation) {
|
|
113
|
+
if (
|
|
114
|
+
getPermissionState(CAMERA_WITH_LOCATION_PERMISSION_ALIAS) !=
|
|
115
|
+
PermissionState.GRANTED
|
|
116
|
+
) {
|
|
117
|
+
requestPermissionForAlias(
|
|
118
|
+
CAMERA_WITH_LOCATION_PERMISSION_ALIAS,
|
|
119
|
+
call,
|
|
120
|
+
"captureWithLocationPermission"
|
|
121
|
+
);
|
|
122
|
+
} else {
|
|
123
|
+
getLocationAndCapture(call);
|
|
124
|
+
}
|
|
125
|
+
} else {
|
|
126
|
+
captureWithoutLocation(call);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
@PermissionCallback
|
|
131
|
+
private void captureWithLocationPermission(PluginCall call) {
|
|
132
|
+
if (
|
|
133
|
+
getPermissionState(CAMERA_WITH_LOCATION_PERMISSION_ALIAS) ==
|
|
134
|
+
PermissionState.GRANTED
|
|
135
|
+
) {
|
|
136
|
+
getLocationAndCapture(call);
|
|
137
|
+
} else {
|
|
138
|
+
Logger.warn(
|
|
139
|
+
"Location permission denied. Capturing photo without location data."
|
|
140
|
+
);
|
|
141
|
+
captureWithoutLocation(call);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
private void getLocationAndCapture(PluginCall call) {
|
|
146
|
+
if (fusedLocationClient == null) {
|
|
147
|
+
fusedLocationClient = LocationServices.getFusedLocationProviderClient(
|
|
148
|
+
getContext()
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
fusedLocationClient
|
|
152
|
+
.getLastLocation()
|
|
153
|
+
.addOnSuccessListener(getActivity(), location -> {
|
|
154
|
+
lastLocation = location;
|
|
155
|
+
proceedWithCapture(call, lastLocation);
|
|
156
|
+
})
|
|
157
|
+
.addOnFailureListener(e -> {
|
|
158
|
+
Logger.error("Failed to get location: " + e.getMessage());
|
|
159
|
+
proceedWithCapture(call, null);
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
private void captureWithoutLocation(PluginCall call) {
|
|
164
|
+
proceedWithCapture(call, null);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
private void proceedWithCapture(PluginCall call, Location location) {
|
|
90
168
|
bridge.saveCall(call);
|
|
91
169
|
captureCallbackId = call.getCallbackId();
|
|
92
170
|
|
|
93
171
|
Integer quality = Objects.requireNonNull(call.getInt("quality", 85));
|
|
94
|
-
final boolean saveToGallery =
|
|
95
|
-
|
|
172
|
+
final boolean saveToGallery = call.getBoolean("saveToGallery", false);
|
|
173
|
+
Integer width = call.getInt("width");
|
|
174
|
+
Integer height = call.getInt("height");
|
|
175
|
+
String aspectRatio = call.getString("aspectRatio");
|
|
176
|
+
|
|
177
|
+
cameraXView.capturePhoto(quality, saveToGallery, width, height, aspectRatio, location);
|
|
96
178
|
}
|
|
97
179
|
|
|
98
180
|
@PluginMethod
|
|
@@ -111,19 +193,17 @@ public class CameraPreview
|
|
|
111
193
|
public void stop(final PluginCall call) {
|
|
112
194
|
bridge
|
|
113
195
|
.getActivity()
|
|
114
|
-
.runOnUiThread(
|
|
115
|
-
()
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
.setRequestedOrientation(previousOrientationRequest);
|
|
196
|
+
.runOnUiThread(() -> {
|
|
197
|
+
getBridge()
|
|
198
|
+
.getActivity()
|
|
199
|
+
.setRequestedOrientation(previousOrientationRequest);
|
|
119
200
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
}
|
|
124
|
-
call.resolve();
|
|
201
|
+
if (cameraXView != null && cameraXView.isRunning()) {
|
|
202
|
+
cameraXView.stopSession();
|
|
203
|
+
cameraXView = null;
|
|
125
204
|
}
|
|
126
|
-
|
|
205
|
+
call.resolve();
|
|
206
|
+
});
|
|
127
207
|
}
|
|
128
208
|
|
|
129
209
|
@PluginMethod
|
|
@@ -151,7 +231,9 @@ public class CameraPreview
|
|
|
151
231
|
|
|
152
232
|
@PluginMethod
|
|
153
233
|
public void getAvailableDevices(PluginCall call) {
|
|
154
|
-
List<CameraDevice> devices = CameraXView.getAvailableDevicesStatic(
|
|
234
|
+
List<CameraDevice> devices = CameraXView.getAvailableDevicesStatic(
|
|
235
|
+
getContext()
|
|
236
|
+
);
|
|
155
237
|
JSArray devicesArray = new JSArray();
|
|
156
238
|
for (CameraDevice device : devices) {
|
|
157
239
|
JSObject deviceJson = new JSObject();
|
|
@@ -198,14 +280,44 @@ public class CameraPreview
|
|
|
198
280
|
call.reject("level parameter is required");
|
|
199
281
|
return;
|
|
200
282
|
}
|
|
283
|
+
Boolean autoFocus = call.getBoolean("autoFocus", true);
|
|
201
284
|
try {
|
|
202
|
-
cameraXView.setZoom(level);
|
|
285
|
+
cameraXView.setZoom(level, autoFocus);
|
|
203
286
|
call.resolve();
|
|
204
287
|
} catch (Exception e) {
|
|
205
288
|
call.reject("Failed to set zoom: " + e.getMessage());
|
|
206
289
|
}
|
|
207
290
|
}
|
|
208
291
|
|
|
292
|
+
@PluginMethod
|
|
293
|
+
public void setFocus(PluginCall call) {
|
|
294
|
+
if (cameraXView == null || !cameraXView.isRunning()) {
|
|
295
|
+
call.reject("Camera is not running");
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
Float x = call.getFloat("x");
|
|
299
|
+
Float y = call.getFloat("y");
|
|
300
|
+
if (x == null || y == null) {
|
|
301
|
+
call.reject("x and y parameters are required");
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
// Reject if values are outside 0-1 range
|
|
305
|
+
if (x < 0f || x > 1f || y < 0f || y > 1f) {
|
|
306
|
+
call.reject("Focus coordinates must be between 0 and 1");
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
getActivity()
|
|
311
|
+
.runOnUiThread(() -> {
|
|
312
|
+
try {
|
|
313
|
+
cameraXView.setFocus(x, y);
|
|
314
|
+
call.resolve();
|
|
315
|
+
} catch (Exception e) {
|
|
316
|
+
call.reject("Failed to set focus: " + e.getMessage());
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
|
|
209
321
|
@PluginMethod
|
|
210
322
|
public void setDeviceId(PluginCall call) {
|
|
211
323
|
String deviceId = call.getString("deviceId");
|
|
@@ -228,7 +340,7 @@ public class CameraPreview
|
|
|
228
340
|
JSObject rear = new JSObject();
|
|
229
341
|
rear.put("facing", "rear");
|
|
230
342
|
JSArray rearSizesJs = new JSArray();
|
|
231
|
-
for(Size size : rearSizes) {
|
|
343
|
+
for (Size size : rearSizes) {
|
|
232
344
|
JSObject sizeJs = new JSObject();
|
|
233
345
|
sizeJs.put("width", size.getWidth());
|
|
234
346
|
sizeJs.put("height", size.getHeight());
|
|
@@ -236,12 +348,12 @@ public class CameraPreview
|
|
|
236
348
|
}
|
|
237
349
|
rear.put("supportedPictureSizes", rearSizesJs);
|
|
238
350
|
supportedPictureSizesResult.put(rear);
|
|
239
|
-
|
|
351
|
+
|
|
240
352
|
List<Size> frontSizes = CameraXView.getSupportedPictureSizes("front");
|
|
241
353
|
JSObject front = new JSObject();
|
|
242
354
|
front.put("facing", "front");
|
|
243
355
|
JSArray frontSizesJs = new JSArray();
|
|
244
|
-
for(Size size : frontSizes) {
|
|
356
|
+
for (Size size : frontSizes) {
|
|
245
357
|
JSObject sizeJs = new JSObject();
|
|
246
358
|
sizeJs.put("width", size.getWidth());
|
|
247
359
|
sizeJs.put("height", size.getHeight());
|
|
@@ -249,7 +361,7 @@ public class CameraPreview
|
|
|
249
361
|
}
|
|
250
362
|
front.put("supportedPictureSizes", frontSizesJs);
|
|
251
363
|
supportedPictureSizesResult.put(front);
|
|
252
|
-
|
|
364
|
+
|
|
253
365
|
JSObject ret = new JSObject();
|
|
254
366
|
ret.put("supportedPictureSizes", supportedPictureSizesResult);
|
|
255
367
|
call.resolve(ret);
|
|
@@ -308,8 +420,14 @@ public class CameraPreview
|
|
|
308
420
|
|
|
309
421
|
@PermissionCallback
|
|
310
422
|
private void handleCameraPermissionResult(PluginCall call) {
|
|
311
|
-
if (
|
|
312
|
-
|
|
423
|
+
if (
|
|
424
|
+
PermissionState.GRANTED.equals(
|
|
425
|
+
getPermissionState(CAMERA_ONLY_PERMISSION_ALIAS)
|
|
426
|
+
) ||
|
|
427
|
+
PermissionState.GRANTED.equals(
|
|
428
|
+
getPermissionState(CAMERA_WITH_AUDIO_PERMISSION_ALIAS)
|
|
429
|
+
)
|
|
430
|
+
) {
|
|
313
431
|
startCamera(call);
|
|
314
432
|
} else {
|
|
315
433
|
call.reject("Permission failed");
|
|
@@ -321,65 +439,412 @@ public class CameraPreview
|
|
|
321
439
|
String originalDeviceId = call.getString("deviceId");
|
|
322
440
|
String deviceId = originalDeviceId; // Use a mutable variable
|
|
323
441
|
|
|
324
|
-
final String position = (positionParam == null ||
|
|
325
|
-
|
|
326
|
-
|
|
442
|
+
final String position = (positionParam == null ||
|
|
443
|
+
positionParam.isEmpty() ||
|
|
444
|
+
"rear".equals(positionParam) ||
|
|
445
|
+
"back".equals(positionParam))
|
|
446
|
+
? "back"
|
|
447
|
+
: "front";
|
|
448
|
+
// Use -1 as default to indicate centering is needed when x/y not provided
|
|
449
|
+
final Integer xParam = call.getInt("x");
|
|
450
|
+
final Integer yParam = call.getInt("y");
|
|
451
|
+
final int x = xParam != null ? xParam : -1;
|
|
452
|
+
final int y = yParam != null ? yParam : -1;
|
|
453
|
+
|
|
454
|
+
Log.d("CameraPreview", "========================");
|
|
455
|
+
Log.d("CameraPreview", "CAMERA POSITION TRACKING START:");
|
|
456
|
+
Log.d(
|
|
457
|
+
"CameraPreview",
|
|
458
|
+
"1. RAW PARAMS - xParam: " + xParam + ", yParam: " + yParam
|
|
459
|
+
);
|
|
460
|
+
Log.d(
|
|
461
|
+
"CameraPreview",
|
|
462
|
+
"2. AFTER DEFAULT - x: " +
|
|
463
|
+
x +
|
|
464
|
+
" (center=" +
|
|
465
|
+
(x == -1) +
|
|
466
|
+
"), y: " +
|
|
467
|
+
y +
|
|
468
|
+
" (center=" +
|
|
469
|
+
(y == -1) +
|
|
470
|
+
")"
|
|
471
|
+
);
|
|
327
472
|
final int width = call.getInt("width", 0);
|
|
328
473
|
final int height = call.getInt("height", 0);
|
|
329
474
|
final int paddingBottom = call.getInt("paddingBottom", 0);
|
|
330
475
|
final boolean toBack = Boolean.TRUE.equals(call.getBoolean("toBack", true));
|
|
331
|
-
final boolean storeToFile = Boolean.TRUE.equals(
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
final boolean
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
476
|
+
final boolean storeToFile = Boolean.TRUE.equals(
|
|
477
|
+
call.getBoolean("storeToFile", false)
|
|
478
|
+
);
|
|
479
|
+
final boolean enableOpacity = Boolean.TRUE.equals(
|
|
480
|
+
call.getBoolean("enableOpacity", false)
|
|
481
|
+
);
|
|
482
|
+
final boolean enableZoom = Boolean.TRUE.equals(
|
|
483
|
+
call.getBoolean("enableZoom", false)
|
|
484
|
+
);
|
|
485
|
+
final boolean disableExifHeaderStripping = Boolean.TRUE.equals(
|
|
486
|
+
call.getBoolean("disableExifHeaderStripping", false)
|
|
487
|
+
);
|
|
488
|
+
final boolean lockOrientation = Boolean.TRUE.equals(
|
|
489
|
+
call.getBoolean("lockAndroidOrientation", false)
|
|
490
|
+
);
|
|
491
|
+
final boolean disableAudio = Boolean.TRUE.equals(
|
|
492
|
+
call.getBoolean("disableAudio", true)
|
|
493
|
+
);
|
|
494
|
+
final String aspectRatio = call.getString("aspectRatio", "4:3");
|
|
495
|
+
final String gridMode = call.getString("gridMode", "none");
|
|
496
|
+
final String positioning = call.getString("positioning", "center");
|
|
497
|
+
final float initialZoomLevel = call.getFloat("initialZoomLevel", 1.0f);
|
|
498
|
+
|
|
499
|
+
// Check for conflict between aspectRatio and size
|
|
500
|
+
if (
|
|
501
|
+
call.getData().has("aspectRatio") &&
|
|
502
|
+
(call.getData().has("width") || call.getData().has("height"))
|
|
503
|
+
) {
|
|
504
|
+
call.reject(
|
|
505
|
+
"Cannot set both aspectRatio and size (width/height). Use setPreviewSize after start."
|
|
506
|
+
);
|
|
507
|
+
return;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
float targetZoom = initialZoomLevel;
|
|
339
511
|
// Check if the selected device is a physical ultra-wide
|
|
340
512
|
if (originalDeviceId != null) {
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
513
|
+
List<CameraDevice> devices = CameraXView.getAvailableDevicesStatic(
|
|
514
|
+
getContext()
|
|
515
|
+
);
|
|
516
|
+
for (CameraDevice device : devices) {
|
|
517
|
+
if (
|
|
518
|
+
originalDeviceId.equals(device.getDeviceId()) && !device.isLogical()
|
|
519
|
+
) {
|
|
520
|
+
for (LensInfo lens : device.getLenses()) {
|
|
521
|
+
if ("ultraWide".equals(lens.getDeviceType())) {
|
|
522
|
+
Log.d(
|
|
523
|
+
"CameraPreview",
|
|
524
|
+
"Ultra-wide lens selected. Targeting 0.5x zoom on logical camera."
|
|
525
|
+
);
|
|
526
|
+
targetZoom = 0.5f;
|
|
527
|
+
// Force the use of the logical camera by clearing the specific deviceId
|
|
528
|
+
deviceId = null;
|
|
529
|
+
break;
|
|
353
530
|
}
|
|
354
|
-
|
|
531
|
+
}
|
|
355
532
|
}
|
|
533
|
+
if (deviceId == null) break; // Exit outer loop once we've made our decision
|
|
534
|
+
}
|
|
356
535
|
}
|
|
357
536
|
|
|
358
|
-
previousOrientationRequest = getBridge()
|
|
537
|
+
previousOrientationRequest = getBridge()
|
|
538
|
+
.getActivity()
|
|
539
|
+
.getRequestedOrientation();
|
|
359
540
|
cameraXView = new CameraXView(getContext(), getBridge().getWebView());
|
|
360
541
|
cameraXView.setListener(this);
|
|
361
542
|
|
|
362
543
|
String finalDeviceId = deviceId;
|
|
363
544
|
float finalTargetZoom = targetZoom;
|
|
364
|
-
getBridge()
|
|
365
|
-
|
|
545
|
+
getBridge()
|
|
546
|
+
.getActivity()
|
|
547
|
+
.runOnUiThread(() -> {
|
|
548
|
+
DisplayMetrics metrics = getBridge()
|
|
549
|
+
.getActivity()
|
|
550
|
+
.getResources()
|
|
551
|
+
.getDisplayMetrics();
|
|
366
552
|
if (lockOrientation) {
|
|
367
|
-
getBridge()
|
|
553
|
+
getBridge()
|
|
554
|
+
.getActivity()
|
|
555
|
+
.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED);
|
|
368
556
|
}
|
|
369
|
-
int computedX = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, x, metrics);
|
|
370
|
-
int computedY = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, y, metrics);
|
|
371
|
-
int computedWidth = width != 0 ? (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, width, metrics) : getBridge().getWebView().getWidth();
|
|
372
|
-
int computedHeight = height != 0 ? (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, height, metrics) : getBridge().getWebView().getHeight();
|
|
373
|
-
computedHeight -= (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, paddingBottom, metrics);
|
|
374
557
|
|
|
375
|
-
|
|
376
|
-
|
|
558
|
+
// Debug: Let's check all the positioning information
|
|
559
|
+
ViewGroup webViewParent = (ViewGroup) getBridge()
|
|
560
|
+
.getWebView()
|
|
561
|
+
.getParent();
|
|
562
|
+
|
|
563
|
+
// Get webview position in different coordinate systems
|
|
564
|
+
int[] webViewLocationInWindow = new int[2];
|
|
565
|
+
int[] webViewLocationOnScreen = new int[2];
|
|
566
|
+
getBridge().getWebView().getLocationInWindow(webViewLocationInWindow);
|
|
567
|
+
getBridge().getWebView().getLocationOnScreen(webViewLocationOnScreen);
|
|
568
|
+
|
|
569
|
+
int webViewLeft = getBridge().getWebView().getLeft();
|
|
570
|
+
int webViewTop = getBridge().getWebView().getTop();
|
|
571
|
+
|
|
572
|
+
// Check parent position too
|
|
573
|
+
int[] parentLocationInWindow = new int[2];
|
|
574
|
+
int[] parentLocationOnScreen = new int[2];
|
|
575
|
+
webViewParent.getLocationInWindow(parentLocationInWindow);
|
|
576
|
+
webViewParent.getLocationOnScreen(parentLocationOnScreen);
|
|
577
|
+
|
|
578
|
+
// Calculate pixel ratio
|
|
579
|
+
float pixelRatio = metrics.density;
|
|
580
|
+
|
|
581
|
+
// The key insight: JavaScript coordinates are relative to the WebView's viewport
|
|
582
|
+
// If the WebView is positioned below the status bar (webViewLocationOnScreen[1] > 0),
|
|
583
|
+
// we need to add that offset when placing native views
|
|
584
|
+
int webViewTopInset = webViewLocationOnScreen[1];
|
|
585
|
+
boolean isEdgeToEdgeActive = webViewLocationOnScreen[1] > 0;
|
|
586
|
+
|
|
587
|
+
// Log all the positioning information for debugging
|
|
588
|
+
Log.d("CameraPreview", "WebView Position Debug:");
|
|
589
|
+
Log.d("CameraPreview", " - webView.getTop(): " + webViewTop);
|
|
590
|
+
Log.d("CameraPreview", " - webView.getLeft(): " + webViewLeft);
|
|
591
|
+
Log.d("CameraPreview", " - webView locationInWindow: (" + webViewLocationInWindow[0] + ", " + webViewLocationInWindow[1] + ")");
|
|
592
|
+
Log.d("CameraPreview", " - webView locationOnScreen: (" + webViewLocationOnScreen[0] + ", " + webViewLocationOnScreen[1] + ")");
|
|
593
|
+
Log.d("CameraPreview", " - parent locationInWindow: (" + parentLocationInWindow[0] + ", " + parentLocationInWindow[1] + ")");
|
|
594
|
+
Log.d("CameraPreview", " - parent locationOnScreen: (" + parentLocationOnScreen[0] + ", " + parentLocationOnScreen[1] + ")");
|
|
595
|
+
|
|
596
|
+
// Check if WebView has margins
|
|
597
|
+
View webView = getBridge().getWebView();
|
|
598
|
+
ViewGroup.LayoutParams webViewLayoutParams = webView.getLayoutParams();
|
|
599
|
+
if (webViewLayoutParams instanceof ViewGroup.MarginLayoutParams) {
|
|
600
|
+
ViewGroup.MarginLayoutParams marginParams = (ViewGroup.MarginLayoutParams) webViewLayoutParams;
|
|
601
|
+
Log.d("CameraPreview", " - webView margins: left=" + marginParams.leftMargin +
|
|
602
|
+
", top=" + marginParams.topMargin +
|
|
603
|
+
", right=" + marginParams.rightMargin +
|
|
604
|
+
", bottom=" + marginParams.bottomMargin);
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
// Check WebView padding
|
|
608
|
+
Log.d("CameraPreview", " - webView padding: left=" + webView.getPaddingLeft() +
|
|
609
|
+
", top=" + webView.getPaddingTop() +
|
|
610
|
+
", right=" + webView.getPaddingRight() +
|
|
611
|
+
", bottom=" + webView.getPaddingBottom());
|
|
377
612
|
|
|
613
|
+
Log.d("CameraPreview", " - Using webViewTopInset: " + webViewTopInset);
|
|
614
|
+
Log.d("CameraPreview", " - isEdgeToEdgeActive: " + isEdgeToEdgeActive);
|
|
615
|
+
|
|
616
|
+
// Calculate position - center if x or y is -1
|
|
617
|
+
int computedX;
|
|
618
|
+
int computedY;
|
|
619
|
+
|
|
620
|
+
// Calculate dimensions first
|
|
621
|
+
int computedWidth = width != 0
|
|
622
|
+
? (int) (width * pixelRatio)
|
|
623
|
+
: getBridge().getWebView().getWidth();
|
|
624
|
+
int computedHeight = height != 0
|
|
625
|
+
? (int) (height * pixelRatio)
|
|
626
|
+
: getBridge().getWebView().getHeight();
|
|
627
|
+
computedHeight -= (int) (paddingBottom * pixelRatio);
|
|
628
|
+
|
|
629
|
+
Log.d("CameraPreview", "========================");
|
|
630
|
+
Log.d("CameraPreview", "POSITIONING CALCULATIONS:");
|
|
631
|
+
Log.d("CameraPreview", "1. INPUT - x: " + x + ", y: " + y + ", width: " + width + ", height: " + height);
|
|
632
|
+
Log.d("CameraPreview", "2. PIXEL RATIO: " + pixelRatio);
|
|
633
|
+
Log.d("CameraPreview", "3. SCREEN - width: " + metrics.widthPixels + ", height: " + metrics.heightPixels);
|
|
634
|
+
Log.d("CameraPreview", "4. WEBVIEW - width: " + getBridge().getWebView().getWidth() + ", height: " + getBridge().getWebView().getHeight());
|
|
635
|
+
Log.d("CameraPreview", "5. COMPUTED DIMENSIONS - width: " + computedWidth + ", height: " + computedHeight);
|
|
636
|
+
|
|
637
|
+
if (x == -1) {
|
|
638
|
+
// Center horizontally
|
|
639
|
+
int screenWidth = metrics.widthPixels;
|
|
640
|
+
computedX = (screenWidth - computedWidth) / 2;
|
|
641
|
+
Log.d(
|
|
642
|
+
"CameraPreview",
|
|
643
|
+
"Centering horizontally: screenWidth=" +
|
|
644
|
+
screenWidth +
|
|
645
|
+
", computedWidth=" +
|
|
646
|
+
computedWidth +
|
|
647
|
+
", computedX=" +
|
|
648
|
+
computedX
|
|
649
|
+
);
|
|
650
|
+
} else {
|
|
651
|
+
computedX = (int) (x * pixelRatio);
|
|
652
|
+
Log.d(
|
|
653
|
+
"CameraPreview",
|
|
654
|
+
"Using provided X position: " +
|
|
655
|
+
x +
|
|
656
|
+
" * " +
|
|
657
|
+
pixelRatio +
|
|
658
|
+
" = " +
|
|
659
|
+
computedX
|
|
660
|
+
);
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
if (y == -1) {
|
|
664
|
+
// Position vertically based on positioning parameter
|
|
665
|
+
int screenHeight = metrics.heightPixels;
|
|
666
|
+
|
|
667
|
+
switch (positioning) {
|
|
668
|
+
case "top":
|
|
669
|
+
computedY = 0;
|
|
670
|
+
Log.d(
|
|
671
|
+
"CameraPreview",
|
|
672
|
+
"Positioning at top: computedY=0"
|
|
673
|
+
);
|
|
674
|
+
break;
|
|
675
|
+
case "bottom":
|
|
676
|
+
computedY = screenHeight - computedHeight;
|
|
677
|
+
Log.d(
|
|
678
|
+
"CameraPreview",
|
|
679
|
+
"Positioning at bottom: screenHeight=" +
|
|
680
|
+
screenHeight +
|
|
681
|
+
", computedHeight=" +
|
|
682
|
+
computedHeight +
|
|
683
|
+
", computedY=" +
|
|
684
|
+
computedY
|
|
685
|
+
);
|
|
686
|
+
break;
|
|
687
|
+
case "center":
|
|
688
|
+
default:
|
|
689
|
+
// Center vertically
|
|
690
|
+
if (isEdgeToEdgeActive) {
|
|
691
|
+
// When WebView is offset from top, center within the available space
|
|
692
|
+
// The camera should be centered in the full screen, not just the WebView area
|
|
693
|
+
computedY = (screenHeight - computedHeight) / 2;
|
|
694
|
+
Log.d(
|
|
695
|
+
"CameraPreview",
|
|
696
|
+
"Centering vertically with WebView offset: screenHeight=" +
|
|
697
|
+
screenHeight +
|
|
698
|
+
", webViewTop=" +
|
|
699
|
+
webViewTopInset +
|
|
700
|
+
", computedHeight=" +
|
|
701
|
+
computedHeight +
|
|
702
|
+
", computedY=" +
|
|
703
|
+
computedY
|
|
704
|
+
);
|
|
705
|
+
} else {
|
|
706
|
+
// Normal mode - use full screen height
|
|
707
|
+
computedY = (screenHeight - computedHeight) / 2;
|
|
708
|
+
Log.d(
|
|
709
|
+
"CameraPreview",
|
|
710
|
+
"Centering vertically (normal): screenHeight=" +
|
|
711
|
+
screenHeight +
|
|
712
|
+
", computedHeight=" +
|
|
713
|
+
computedHeight +
|
|
714
|
+
", computedY=" +
|
|
715
|
+
computedY
|
|
716
|
+
);
|
|
717
|
+
}
|
|
718
|
+
break;
|
|
719
|
+
}
|
|
720
|
+
} else {
|
|
721
|
+
computedY = (int) (y * pixelRatio);
|
|
722
|
+
// If edge-to-edge is active, JavaScript Y is relative to WebView content area
|
|
723
|
+
// We need to add the inset to get absolute screen position
|
|
724
|
+
if (isEdgeToEdgeActive) {
|
|
725
|
+
computedY += webViewTopInset;
|
|
726
|
+
Log.d(
|
|
727
|
+
"CameraPreview",
|
|
728
|
+
"Edge-to-edge adjustment: Y position " +
|
|
729
|
+
(int)(y * pixelRatio) +
|
|
730
|
+
" + inset " +
|
|
731
|
+
webViewTopInset +
|
|
732
|
+
" = " +
|
|
733
|
+
computedY
|
|
734
|
+
);
|
|
735
|
+
}
|
|
736
|
+
Log.d(
|
|
737
|
+
"CameraPreview",
|
|
738
|
+
"Using provided Y position: " +
|
|
739
|
+
y +
|
|
740
|
+
" * " +
|
|
741
|
+
pixelRatio +
|
|
742
|
+
" = " +
|
|
743
|
+
computedY +
|
|
744
|
+
(isEdgeToEdgeActive ? " (adjusted for edge-to-edge)" : "")
|
|
745
|
+
);
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
Log.d(
|
|
749
|
+
"CameraPreview",
|
|
750
|
+
"2b. EDGE-TO-EDGE - " + (isEdgeToEdgeActive ? "ACTIVE (inset=" + webViewTopInset + ")" : "INACTIVE")
|
|
751
|
+
);
|
|
752
|
+
Log.d(
|
|
753
|
+
"CameraPreview",
|
|
754
|
+
"3. COMPUTED POSITION - x=" + computedX + ", y=" + computedY
|
|
755
|
+
);
|
|
756
|
+
Log.d(
|
|
757
|
+
"CameraPreview",
|
|
758
|
+
"4. COMPUTED SIZE - width=" +
|
|
759
|
+
computedWidth +
|
|
760
|
+
", height=" +
|
|
761
|
+
computedHeight
|
|
762
|
+
);
|
|
763
|
+
Log.d("CameraPreview", "=== COORDINATE DEBUG ===");
|
|
764
|
+
Log.d(
|
|
765
|
+
"CameraPreview",
|
|
766
|
+
"WebView getLeft/getTop: (" + webViewLeft + ", " + webViewTop + ")"
|
|
767
|
+
);
|
|
768
|
+
Log.d(
|
|
769
|
+
"CameraPreview",
|
|
770
|
+
"WebView locationInWindow: (" +
|
|
771
|
+
webViewLocationInWindow[0] +
|
|
772
|
+
", " +
|
|
773
|
+
webViewLocationInWindow[1] +
|
|
774
|
+
")"
|
|
775
|
+
);
|
|
776
|
+
Log.d(
|
|
777
|
+
"CameraPreview",
|
|
778
|
+
"WebView locationOnScreen: (" +
|
|
779
|
+
webViewLocationOnScreen[0] +
|
|
780
|
+
", " +
|
|
781
|
+
webViewLocationOnScreen[1] +
|
|
782
|
+
")"
|
|
783
|
+
);
|
|
784
|
+
Log.d(
|
|
785
|
+
"CameraPreview",
|
|
786
|
+
"Parent locationInWindow: (" +
|
|
787
|
+
parentLocationInWindow[0] +
|
|
788
|
+
", " +
|
|
789
|
+
parentLocationInWindow[1] +
|
|
790
|
+
")"
|
|
791
|
+
);
|
|
792
|
+
Log.d(
|
|
793
|
+
"CameraPreview",
|
|
794
|
+
"Parent locationOnScreen: (" +
|
|
795
|
+
parentLocationOnScreen[0] +
|
|
796
|
+
", " +
|
|
797
|
+
parentLocationOnScreen[1] +
|
|
798
|
+
")"
|
|
799
|
+
);
|
|
800
|
+
Log.d(
|
|
801
|
+
"CameraPreview",
|
|
802
|
+
"Parent class: " + webViewParent.getClass().getSimpleName()
|
|
803
|
+
);
|
|
804
|
+
Log.d(
|
|
805
|
+
"CameraPreview",
|
|
806
|
+
"Requested position (logical): (" + x + ", " + y + ")"
|
|
807
|
+
);
|
|
808
|
+
Log.d("CameraPreview", "Pixel ratio: " + pixelRatio);
|
|
809
|
+
Log.d(
|
|
810
|
+
"CameraPreview",
|
|
811
|
+
"Final computed position (no offset): (" +
|
|
812
|
+
computedX +
|
|
813
|
+
", " +
|
|
814
|
+
computedY +
|
|
815
|
+
")"
|
|
816
|
+
);
|
|
817
|
+
Log.d("CameraPreview", "5. IS_CENTERED - " + (x == -1 || y == -1));
|
|
818
|
+
Log.d("CameraPreview", "========================");
|
|
819
|
+
|
|
820
|
+
// Pass along whether we're centering so CameraXView knows not to add insets
|
|
821
|
+
boolean isCentered = (x == -1 || y == -1);
|
|
822
|
+
|
|
823
|
+
CameraSessionConfiguration config = new CameraSessionConfiguration(
|
|
824
|
+
finalDeviceId,
|
|
825
|
+
position,
|
|
826
|
+
computedX,
|
|
827
|
+
computedY,
|
|
828
|
+
computedWidth,
|
|
829
|
+
computedHeight,
|
|
830
|
+
paddingBottom,
|
|
831
|
+
toBack,
|
|
832
|
+
storeToFile,
|
|
833
|
+
enableOpacity,
|
|
834
|
+
enableZoom,
|
|
835
|
+
disableExifHeaderStripping,
|
|
836
|
+
disableAudio,
|
|
837
|
+
1.0f,
|
|
838
|
+
aspectRatio,
|
|
839
|
+
gridMode
|
|
840
|
+
);
|
|
841
|
+
config.setTargetZoom(finalTargetZoom);
|
|
842
|
+
config.setCentered(isCentered);
|
|
843
|
+
|
|
378
844
|
bridge.saveCall(call);
|
|
379
845
|
cameraStartCallbackId = call.getCallbackId();
|
|
380
846
|
cameraXView.startSession(config);
|
|
381
|
-
}
|
|
382
|
-
);
|
|
847
|
+
});
|
|
383
848
|
}
|
|
384
849
|
|
|
385
850
|
@Override
|
|
@@ -407,34 +872,245 @@ public class CameraPreview
|
|
|
407
872
|
bridge.releaseCall(pluginCall);
|
|
408
873
|
}
|
|
409
874
|
|
|
875
|
+
@Override
|
|
876
|
+
public void onCameraStarted(int width, int height, int x, int y) {
|
|
877
|
+
PluginCall call = bridge.getSavedCall(cameraStartCallbackId);
|
|
878
|
+
if (call != null) {
|
|
879
|
+
// Convert pixel values back to logical units
|
|
880
|
+
DisplayMetrics metrics = getBridge()
|
|
881
|
+
.getActivity()
|
|
882
|
+
.getResources()
|
|
883
|
+
.getDisplayMetrics();
|
|
884
|
+
float pixelRatio = metrics.density;
|
|
885
|
+
|
|
886
|
+
// When WebView is offset from the top (e.g., below status bar),
|
|
887
|
+
// we need to convert between JavaScript coordinates (relative to WebView)
|
|
888
|
+
// and native coordinates (relative to screen)
|
|
889
|
+
WebView webView = getBridge().getWebView();
|
|
890
|
+
int webViewTopInset = 0;
|
|
891
|
+
boolean isEdgeToEdgeActive = false;
|
|
892
|
+
if (webView != null) {
|
|
893
|
+
int[] location = new int[2];
|
|
894
|
+
webView.getLocationOnScreen(location);
|
|
895
|
+
webViewTopInset = location[1];
|
|
896
|
+
isEdgeToEdgeActive = webViewTopInset > 0;
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
// Only convert to relative position if edge-to-edge is active
|
|
900
|
+
int relativeY = isEdgeToEdgeActive ? (y - webViewTopInset) : y;
|
|
901
|
+
|
|
902
|
+
Log.d("CameraPreview", "========================");
|
|
903
|
+
Log.d("CameraPreview", "CAMERA STARTED - POSITION RETURNED:");
|
|
904
|
+
Log.d(
|
|
905
|
+
"CameraPreview",
|
|
906
|
+
"7. RETURNED (pixels) - x=" +
|
|
907
|
+
x +
|
|
908
|
+
", y=" +
|
|
909
|
+
y +
|
|
910
|
+
", width=" +
|
|
911
|
+
width +
|
|
912
|
+
", height=" +
|
|
913
|
+
height
|
|
914
|
+
);
|
|
915
|
+
Log.d(
|
|
916
|
+
"CameraPreview",
|
|
917
|
+
"8. EDGE-TO-EDGE - " + (isEdgeToEdgeActive ? "ACTIVE" : "INACTIVE")
|
|
918
|
+
);
|
|
919
|
+
Log.d("CameraPreview", "9. WEBVIEW INSET - " + webViewTopInset);
|
|
920
|
+
Log.d(
|
|
921
|
+
"CameraPreview",
|
|
922
|
+
"10. RELATIVE Y - " +
|
|
923
|
+
relativeY +
|
|
924
|
+
" (y=" +
|
|
925
|
+
y +
|
|
926
|
+
(isEdgeToEdgeActive ? " - inset=" + webViewTopInset : " unchanged") +
|
|
927
|
+
")"
|
|
928
|
+
);
|
|
929
|
+
Log.d(
|
|
930
|
+
"CameraPreview",
|
|
931
|
+
"11. RETURNED (logical) - x=" +
|
|
932
|
+
(x / pixelRatio) +
|
|
933
|
+
", y=" +
|
|
934
|
+
(relativeY / pixelRatio) +
|
|
935
|
+
", width=" +
|
|
936
|
+
(width / pixelRatio) +
|
|
937
|
+
", height=" +
|
|
938
|
+
(height / pixelRatio)
|
|
939
|
+
);
|
|
940
|
+
Log.d("CameraPreview", "12. PIXEL RATIO - " + pixelRatio);
|
|
941
|
+
Log.d("CameraPreview", "========================");
|
|
942
|
+
|
|
943
|
+
JSObject result = new JSObject();
|
|
944
|
+
result.put("width", width / pixelRatio);
|
|
945
|
+
result.put("height", height / pixelRatio);
|
|
946
|
+
result.put("x", x / pixelRatio);
|
|
947
|
+
result.put("y", relativeY / pixelRatio);
|
|
948
|
+
call.resolve(result);
|
|
949
|
+
bridge.releaseCall(call);
|
|
950
|
+
cameraStartCallbackId = null; // Prevent re-use
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
|
|
410
954
|
@Override
|
|
411
955
|
public void onSampleTaken(String result) {
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
bridge.getSavedCall(snapshotCallbackId).resolve(jsObject);
|
|
956
|
+
// Handle sample taken if needed
|
|
957
|
+
Log.i("CameraPreview", "Sample taken: " + result);
|
|
415
958
|
}
|
|
416
959
|
|
|
417
960
|
@Override
|
|
418
961
|
public void onSampleTakenError(String message) {
|
|
419
|
-
|
|
962
|
+
// Handle sample taken error if needed
|
|
963
|
+
Log.e("CameraPreview", "Sample taken error: " + message);
|
|
420
964
|
}
|
|
421
965
|
|
|
422
966
|
@Override
|
|
423
|
-
public void
|
|
424
|
-
PluginCall
|
|
425
|
-
if (
|
|
426
|
-
|
|
427
|
-
bridge.releaseCall(
|
|
967
|
+
public void onCameraStartError(String message) {
|
|
968
|
+
PluginCall call = bridge.getSavedCall(cameraStartCallbackId);
|
|
969
|
+
if (call != null) {
|
|
970
|
+
call.reject(message);
|
|
971
|
+
bridge.releaseCall(call);
|
|
972
|
+
cameraStartCallbackId = null;
|
|
428
973
|
}
|
|
429
974
|
}
|
|
430
975
|
|
|
431
|
-
@
|
|
432
|
-
public void
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
976
|
+
@PluginMethod
|
|
977
|
+
public void setAspectRatio(PluginCall call) {
|
|
978
|
+
if (cameraXView == null || !cameraXView.isRunning()) {
|
|
979
|
+
call.reject("Camera is not running");
|
|
980
|
+
return;
|
|
981
|
+
}
|
|
982
|
+
String aspectRatio = call.getString("aspectRatio", "4:3");
|
|
983
|
+
Float x = call.getFloat("x");
|
|
984
|
+
Float y = call.getFloat("y");
|
|
985
|
+
|
|
986
|
+
getActivity()
|
|
987
|
+
.runOnUiThread(() -> {
|
|
988
|
+
cameraXView.setAspectRatio(aspectRatio, x, y, () -> {
|
|
989
|
+
// Return the actual preview bounds after layout and camera operations are complete
|
|
990
|
+
int[] bounds = cameraXView.getCurrentPreviewBounds();
|
|
991
|
+
JSObject ret = new JSObject();
|
|
992
|
+
ret.put("x", bounds[0]);
|
|
993
|
+
ret.put("y", bounds[1]);
|
|
994
|
+
ret.put("width", bounds[2]);
|
|
995
|
+
ret.put("height", bounds[3]);
|
|
996
|
+
call.resolve(ret);
|
|
997
|
+
});
|
|
998
|
+
});
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
@PluginMethod
|
|
1002
|
+
public void getAspectRatio(PluginCall call) {
|
|
1003
|
+
if (cameraXView == null || !cameraXView.isRunning()) {
|
|
1004
|
+
call.reject("Camera is not running");
|
|
1005
|
+
return;
|
|
437
1006
|
}
|
|
1007
|
+
String aspectRatio = cameraXView.getAspectRatio();
|
|
1008
|
+
JSObject ret = new JSObject();
|
|
1009
|
+
ret.put("aspectRatio", aspectRatio);
|
|
1010
|
+
call.resolve(ret);
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
@PluginMethod
|
|
1014
|
+
public void setGridMode(PluginCall call) {
|
|
1015
|
+
if (cameraXView == null || !cameraXView.isRunning()) {
|
|
1016
|
+
call.reject("Camera is not running");
|
|
1017
|
+
return;
|
|
1018
|
+
}
|
|
1019
|
+
String gridMode = call.getString("gridMode", "none");
|
|
1020
|
+
getActivity()
|
|
1021
|
+
.runOnUiThread(() -> {
|
|
1022
|
+
cameraXView.setGridMode(gridMode);
|
|
1023
|
+
call.resolve();
|
|
1024
|
+
});
|
|
438
1025
|
}
|
|
439
1026
|
|
|
1027
|
+
@PluginMethod
|
|
1028
|
+
public void getGridMode(PluginCall call) {
|
|
1029
|
+
if (cameraXView == null || !cameraXView.isRunning()) {
|
|
1030
|
+
call.reject("Camera is not running");
|
|
1031
|
+
return;
|
|
1032
|
+
}
|
|
1033
|
+
JSObject ret = new JSObject();
|
|
1034
|
+
ret.put("gridMode", cameraXView.getGridMode());
|
|
1035
|
+
call.resolve(ret);
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
@PluginMethod
|
|
1039
|
+
public void getPreviewSize(PluginCall call) {
|
|
1040
|
+
if (cameraXView == null || !cameraXView.isRunning()) {
|
|
1041
|
+
call.reject("Camera is not running");
|
|
1042
|
+
return;
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
// Convert pixel values back to logical units
|
|
1046
|
+
DisplayMetrics metrics = getBridge()
|
|
1047
|
+
.getActivity()
|
|
1048
|
+
.getResources()
|
|
1049
|
+
.getDisplayMetrics();
|
|
1050
|
+
float pixelRatio = metrics.density;
|
|
1051
|
+
|
|
1052
|
+
JSObject ret = new JSObject();
|
|
1053
|
+
ret.put("x", cameraXView.getPreviewX() / pixelRatio);
|
|
1054
|
+
ret.put("y", cameraXView.getPreviewY() / pixelRatio);
|
|
1055
|
+
ret.put("width", cameraXView.getPreviewWidth() / pixelRatio);
|
|
1056
|
+
ret.put("height", cameraXView.getPreviewHeight() / pixelRatio);
|
|
1057
|
+
call.resolve(ret);
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
@PluginMethod
|
|
1061
|
+
public void setPreviewSize(PluginCall call) {
|
|
1062
|
+
if (cameraXView == null || !cameraXView.isRunning()) {
|
|
1063
|
+
call.reject("Camera is not running");
|
|
1064
|
+
return;
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
// Get values from call - null values will become 0
|
|
1068
|
+
Integer xParam = call.getInt("x");
|
|
1069
|
+
Integer yParam = call.getInt("y");
|
|
1070
|
+
Integer widthParam = call.getInt("width");
|
|
1071
|
+
Integer heightParam = call.getInt("height");
|
|
1072
|
+
|
|
1073
|
+
// Apply pixel ratio conversion to non-null values
|
|
1074
|
+
DisplayMetrics metrics = getBridge()
|
|
1075
|
+
.getActivity()
|
|
1076
|
+
.getResources()
|
|
1077
|
+
.getDisplayMetrics();
|
|
1078
|
+
float pixelRatio = metrics.density;
|
|
1079
|
+
|
|
1080
|
+
// Check if edge-to-edge mode is active
|
|
1081
|
+
WebView webView = getBridge().getWebView();
|
|
1082
|
+
int webViewTopInset = 0;
|
|
1083
|
+
boolean isEdgeToEdgeActive = false;
|
|
1084
|
+
if (webView != null) {
|
|
1085
|
+
int[] location = new int[2];
|
|
1086
|
+
webView.getLocationOnScreen(location);
|
|
1087
|
+
webViewTopInset = location[1];
|
|
1088
|
+
isEdgeToEdgeActive = webViewTopInset > 0;
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
int x = (xParam != null && xParam > 0) ? (int) (xParam * pixelRatio) : 0;
|
|
1092
|
+
int y = (yParam != null && yParam > 0) ? (int) (yParam * pixelRatio) : 0;
|
|
1093
|
+
|
|
1094
|
+
// Add edge-to-edge inset to Y if active
|
|
1095
|
+
if (isEdgeToEdgeActive && y > 0) {
|
|
1096
|
+
y += webViewTopInset;
|
|
1097
|
+
}
|
|
1098
|
+
int width = (widthParam != null && widthParam > 0)
|
|
1099
|
+
? (int) (widthParam * pixelRatio)
|
|
1100
|
+
: 0;
|
|
1101
|
+
int height = (heightParam != null && heightParam > 0)
|
|
1102
|
+
? (int) (heightParam * pixelRatio)
|
|
1103
|
+
: 0;
|
|
1104
|
+
|
|
1105
|
+
cameraXView.setPreviewSize(x, y, width, height, () -> {
|
|
1106
|
+
// Return the actual preview bounds after layout operations are complete
|
|
1107
|
+
int[] bounds = cameraXView.getCurrentPreviewBounds();
|
|
1108
|
+
JSObject ret = new JSObject();
|
|
1109
|
+
ret.put("x", bounds[0]);
|
|
1110
|
+
ret.put("y", bounds[1]);
|
|
1111
|
+
ret.put("width", bounds[2]);
|
|
1112
|
+
ret.put("height", bounds[3]);
|
|
1113
|
+
call.resolve(ret);
|
|
1114
|
+
});
|
|
1115
|
+
}
|
|
440
1116
|
}
|