@capgo/camera-preview 7.4.0-beta.2 → 7.4.0-beta.20
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 +212 -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 +731 -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 +292 -29
- package/dist/esm/definitions.d.ts +148 -13
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/web.d.ts +52 -3
- package/dist/esm/web.js +555 -97
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +553 -97
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +553 -97
- package/dist/plugin.js.map +1 -1
- package/ios/Sources/CapgoCameraPreview/CameraController.swift +888 -214
- package/ios/Sources/CapgoCameraPreview/GridOverlayView.swift +65 -0
- package/ios/Sources/CapgoCameraPreview/Plugin.swift +967 -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,384 @@ 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 float initialZoomLevel = call.getFloat("initialZoomLevel", 1.0f);
|
|
497
|
+
|
|
498
|
+
// Check for conflict between aspectRatio and size
|
|
499
|
+
if (
|
|
500
|
+
call.getData().has("aspectRatio") &&
|
|
501
|
+
(call.getData().has("width") || call.getData().has("height"))
|
|
502
|
+
) {
|
|
503
|
+
call.reject(
|
|
504
|
+
"Cannot set both aspectRatio and size (width/height). Use setPreviewSize after start."
|
|
505
|
+
);
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
float targetZoom = initialZoomLevel;
|
|
339
510
|
// Check if the selected device is a physical ultra-wide
|
|
340
511
|
if (originalDeviceId != null) {
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
512
|
+
List<CameraDevice> devices = CameraXView.getAvailableDevicesStatic(
|
|
513
|
+
getContext()
|
|
514
|
+
);
|
|
515
|
+
for (CameraDevice device : devices) {
|
|
516
|
+
if (
|
|
517
|
+
originalDeviceId.equals(device.getDeviceId()) && !device.isLogical()
|
|
518
|
+
) {
|
|
519
|
+
for (LensInfo lens : device.getLenses()) {
|
|
520
|
+
if ("ultraWide".equals(lens.getDeviceType())) {
|
|
521
|
+
Log.d(
|
|
522
|
+
"CameraPreview",
|
|
523
|
+
"Ultra-wide lens selected. Targeting 0.5x zoom on logical camera."
|
|
524
|
+
);
|
|
525
|
+
targetZoom = 0.5f;
|
|
526
|
+
// Force the use of the logical camera by clearing the specific deviceId
|
|
527
|
+
deviceId = null;
|
|
528
|
+
break;
|
|
353
529
|
}
|
|
354
|
-
|
|
530
|
+
}
|
|
355
531
|
}
|
|
532
|
+
if (deviceId == null) break; // Exit outer loop once we've made our decision
|
|
533
|
+
}
|
|
356
534
|
}
|
|
357
535
|
|
|
358
|
-
previousOrientationRequest = getBridge()
|
|
536
|
+
previousOrientationRequest = getBridge()
|
|
537
|
+
.getActivity()
|
|
538
|
+
.getRequestedOrientation();
|
|
359
539
|
cameraXView = new CameraXView(getContext(), getBridge().getWebView());
|
|
360
540
|
cameraXView.setListener(this);
|
|
361
541
|
|
|
362
542
|
String finalDeviceId = deviceId;
|
|
363
543
|
float finalTargetZoom = targetZoom;
|
|
364
|
-
getBridge()
|
|
365
|
-
|
|
544
|
+
getBridge()
|
|
545
|
+
.getActivity()
|
|
546
|
+
.runOnUiThread(() -> {
|
|
547
|
+
DisplayMetrics metrics = getBridge()
|
|
548
|
+
.getActivity()
|
|
549
|
+
.getResources()
|
|
550
|
+
.getDisplayMetrics();
|
|
366
551
|
if (lockOrientation) {
|
|
367
|
-
getBridge()
|
|
552
|
+
getBridge()
|
|
553
|
+
.getActivity()
|
|
554
|
+
.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED);
|
|
368
555
|
}
|
|
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
556
|
|
|
375
|
-
|
|
376
|
-
|
|
557
|
+
// Debug: Let's check all the positioning information
|
|
558
|
+
ViewGroup webViewParent = (ViewGroup) getBridge()
|
|
559
|
+
.getWebView()
|
|
560
|
+
.getParent();
|
|
561
|
+
|
|
562
|
+
// Get webview position in different coordinate systems
|
|
563
|
+
int[] webViewLocationInWindow = new int[2];
|
|
564
|
+
int[] webViewLocationOnScreen = new int[2];
|
|
565
|
+
getBridge().getWebView().getLocationInWindow(webViewLocationInWindow);
|
|
566
|
+
getBridge().getWebView().getLocationOnScreen(webViewLocationOnScreen);
|
|
567
|
+
|
|
568
|
+
int webViewLeft = getBridge().getWebView().getLeft();
|
|
569
|
+
int webViewTop = getBridge().getWebView().getTop();
|
|
570
|
+
|
|
571
|
+
// Check parent position too
|
|
572
|
+
int[] parentLocationInWindow = new int[2];
|
|
573
|
+
int[] parentLocationOnScreen = new int[2];
|
|
574
|
+
webViewParent.getLocationInWindow(parentLocationInWindow);
|
|
575
|
+
webViewParent.getLocationOnScreen(parentLocationOnScreen);
|
|
576
|
+
|
|
577
|
+
// Calculate pixel ratio
|
|
578
|
+
float pixelRatio = metrics.density;
|
|
579
|
+
|
|
580
|
+
// The key insight: JavaScript coordinates are relative to the WebView's viewport
|
|
581
|
+
// If the WebView is positioned below the status bar (webViewLocationOnScreen[1] > 0),
|
|
582
|
+
// we need to add that offset when placing native views
|
|
583
|
+
int webViewTopInset = webViewLocationOnScreen[1];
|
|
584
|
+
boolean isEdgeToEdgeActive = webViewLocationOnScreen[1] > 0;
|
|
585
|
+
|
|
586
|
+
// Log all the positioning information for debugging
|
|
587
|
+
Log.d("CameraPreview", "WebView Position Debug:");
|
|
588
|
+
Log.d("CameraPreview", " - webView.getTop(): " + webViewTop);
|
|
589
|
+
Log.d("CameraPreview", " - webView.getLeft(): " + webViewLeft);
|
|
590
|
+
Log.d("CameraPreview", " - webView locationInWindow: (" + webViewLocationInWindow[0] + ", " + webViewLocationInWindow[1] + ")");
|
|
591
|
+
Log.d("CameraPreview", " - webView locationOnScreen: (" + webViewLocationOnScreen[0] + ", " + webViewLocationOnScreen[1] + ")");
|
|
592
|
+
Log.d("CameraPreview", " - parent locationInWindow: (" + parentLocationInWindow[0] + ", " + parentLocationInWindow[1] + ")");
|
|
593
|
+
Log.d("CameraPreview", " - parent locationOnScreen: (" + parentLocationOnScreen[0] + ", " + parentLocationOnScreen[1] + ")");
|
|
594
|
+
|
|
595
|
+
// Check if WebView has margins
|
|
596
|
+
View webView = getBridge().getWebView();
|
|
597
|
+
ViewGroup.LayoutParams webViewLayoutParams = webView.getLayoutParams();
|
|
598
|
+
if (webViewLayoutParams instanceof ViewGroup.MarginLayoutParams) {
|
|
599
|
+
ViewGroup.MarginLayoutParams marginParams = (ViewGroup.MarginLayoutParams) webViewLayoutParams;
|
|
600
|
+
Log.d("CameraPreview", " - webView margins: left=" + marginParams.leftMargin +
|
|
601
|
+
", top=" + marginParams.topMargin +
|
|
602
|
+
", right=" + marginParams.rightMargin +
|
|
603
|
+
", bottom=" + marginParams.bottomMargin);
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
// Check WebView padding
|
|
607
|
+
Log.d("CameraPreview", " - webView padding: left=" + webView.getPaddingLeft() +
|
|
608
|
+
", top=" + webView.getPaddingTop() +
|
|
609
|
+
", right=" + webView.getPaddingRight() +
|
|
610
|
+
", bottom=" + webView.getPaddingBottom());
|
|
377
611
|
|
|
612
|
+
Log.d("CameraPreview", " - Using webViewTopInset: " + webViewTopInset);
|
|
613
|
+
Log.d("CameraPreview", " - isEdgeToEdgeActive: " + isEdgeToEdgeActive);
|
|
614
|
+
|
|
615
|
+
// Calculate position - center if x or y is -1
|
|
616
|
+
int computedX;
|
|
617
|
+
int computedY;
|
|
618
|
+
|
|
619
|
+
// Calculate dimensions first
|
|
620
|
+
int computedWidth = width != 0
|
|
621
|
+
? (int) (width * pixelRatio)
|
|
622
|
+
: getBridge().getWebView().getWidth();
|
|
623
|
+
int computedHeight = height != 0
|
|
624
|
+
? (int) (height * pixelRatio)
|
|
625
|
+
: getBridge().getWebView().getHeight();
|
|
626
|
+
computedHeight -= (int) (paddingBottom * pixelRatio);
|
|
627
|
+
|
|
628
|
+
Log.d("CameraPreview", "========================");
|
|
629
|
+
Log.d("CameraPreview", "POSITIONING CALCULATIONS:");
|
|
630
|
+
Log.d("CameraPreview", "1. INPUT - x: " + x + ", y: " + y + ", width: " + width + ", height: " + height);
|
|
631
|
+
Log.d("CameraPreview", "2. PIXEL RATIO: " + pixelRatio);
|
|
632
|
+
Log.d("CameraPreview", "3. SCREEN - width: " + metrics.widthPixels + ", height: " + metrics.heightPixels);
|
|
633
|
+
Log.d("CameraPreview", "4. WEBVIEW - width: " + getBridge().getWebView().getWidth() + ", height: " + getBridge().getWebView().getHeight());
|
|
634
|
+
Log.d("CameraPreview", "5. COMPUTED DIMENSIONS - width: " + computedWidth + ", height: " + computedHeight);
|
|
635
|
+
|
|
636
|
+
if (x == -1) {
|
|
637
|
+
// Center horizontally
|
|
638
|
+
int screenWidth = metrics.widthPixels;
|
|
639
|
+
computedX = (screenWidth - computedWidth) / 2;
|
|
640
|
+
Log.d(
|
|
641
|
+
"CameraPreview",
|
|
642
|
+
"Centering horizontally: screenWidth=" +
|
|
643
|
+
screenWidth +
|
|
644
|
+
", computedWidth=" +
|
|
645
|
+
computedWidth +
|
|
646
|
+
", computedX=" +
|
|
647
|
+
computedX
|
|
648
|
+
);
|
|
649
|
+
} else {
|
|
650
|
+
computedX = (int) (x * pixelRatio);
|
|
651
|
+
Log.d(
|
|
652
|
+
"CameraPreview",
|
|
653
|
+
"Using provided X position: " +
|
|
654
|
+
x +
|
|
655
|
+
" * " +
|
|
656
|
+
pixelRatio +
|
|
657
|
+
" = " +
|
|
658
|
+
computedX
|
|
659
|
+
);
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
if (y == -1) {
|
|
663
|
+
// Center vertically
|
|
664
|
+
if (isEdgeToEdgeActive) {
|
|
665
|
+
// When WebView is offset from top, center within the available space
|
|
666
|
+
// The camera should be centered in the full screen, not just the WebView area
|
|
667
|
+
computedY = (metrics.heightPixels - computedHeight) / 2;
|
|
668
|
+
Log.d(
|
|
669
|
+
"CameraPreview",
|
|
670
|
+
"Centering vertically with WebView offset: screenHeight=" +
|
|
671
|
+
metrics.heightPixels +
|
|
672
|
+
", webViewTop=" +
|
|
673
|
+
webViewTopInset +
|
|
674
|
+
", computedHeight=" +
|
|
675
|
+
computedHeight +
|
|
676
|
+
", computedY=" +
|
|
677
|
+
computedY
|
|
678
|
+
);
|
|
679
|
+
} else {
|
|
680
|
+
// Normal mode - use full screen height
|
|
681
|
+
computedY = (metrics.heightPixels - computedHeight) / 2;
|
|
682
|
+
Log.d(
|
|
683
|
+
"CameraPreview",
|
|
684
|
+
"Centering vertically (normal): screenHeight=" +
|
|
685
|
+
metrics.heightPixels +
|
|
686
|
+
", computedHeight=" +
|
|
687
|
+
computedHeight +
|
|
688
|
+
", computedY=" +
|
|
689
|
+
computedY
|
|
690
|
+
);
|
|
691
|
+
}
|
|
692
|
+
} else {
|
|
693
|
+
computedY = (int) (y * pixelRatio);
|
|
694
|
+
// If edge-to-edge is active, JavaScript Y is relative to WebView content area
|
|
695
|
+
// We need to add the inset to get absolute screen position
|
|
696
|
+
if (isEdgeToEdgeActive) {
|
|
697
|
+
computedY += webViewTopInset;
|
|
698
|
+
Log.d(
|
|
699
|
+
"CameraPreview",
|
|
700
|
+
"Edge-to-edge adjustment: Y position " +
|
|
701
|
+
(int)(y * pixelRatio) +
|
|
702
|
+
" + inset " +
|
|
703
|
+
webViewTopInset +
|
|
704
|
+
" = " +
|
|
705
|
+
computedY
|
|
706
|
+
);
|
|
707
|
+
}
|
|
708
|
+
Log.d(
|
|
709
|
+
"CameraPreview",
|
|
710
|
+
"Using provided Y position: " +
|
|
711
|
+
y +
|
|
712
|
+
" * " +
|
|
713
|
+
pixelRatio +
|
|
714
|
+
" = " +
|
|
715
|
+
computedY +
|
|
716
|
+
(isEdgeToEdgeActive ? " (adjusted for edge-to-edge)" : "")
|
|
717
|
+
);
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
Log.d(
|
|
721
|
+
"CameraPreview",
|
|
722
|
+
"2b. EDGE-TO-EDGE - " + (isEdgeToEdgeActive ? "ACTIVE (inset=" + webViewTopInset + ")" : "INACTIVE")
|
|
723
|
+
);
|
|
724
|
+
Log.d(
|
|
725
|
+
"CameraPreview",
|
|
726
|
+
"3. COMPUTED POSITION - x=" + computedX + ", y=" + computedY
|
|
727
|
+
);
|
|
728
|
+
Log.d(
|
|
729
|
+
"CameraPreview",
|
|
730
|
+
"4. COMPUTED SIZE - width=" +
|
|
731
|
+
computedWidth +
|
|
732
|
+
", height=" +
|
|
733
|
+
computedHeight
|
|
734
|
+
);
|
|
735
|
+
Log.d("CameraPreview", "=== COORDINATE DEBUG ===");
|
|
736
|
+
Log.d(
|
|
737
|
+
"CameraPreview",
|
|
738
|
+
"WebView getLeft/getTop: (" + webViewLeft + ", " + webViewTop + ")"
|
|
739
|
+
);
|
|
740
|
+
Log.d(
|
|
741
|
+
"CameraPreview",
|
|
742
|
+
"WebView locationInWindow: (" +
|
|
743
|
+
webViewLocationInWindow[0] +
|
|
744
|
+
", " +
|
|
745
|
+
webViewLocationInWindow[1] +
|
|
746
|
+
")"
|
|
747
|
+
);
|
|
748
|
+
Log.d(
|
|
749
|
+
"CameraPreview",
|
|
750
|
+
"WebView locationOnScreen: (" +
|
|
751
|
+
webViewLocationOnScreen[0] +
|
|
752
|
+
", " +
|
|
753
|
+
webViewLocationOnScreen[1] +
|
|
754
|
+
")"
|
|
755
|
+
);
|
|
756
|
+
Log.d(
|
|
757
|
+
"CameraPreview",
|
|
758
|
+
"Parent locationInWindow: (" +
|
|
759
|
+
parentLocationInWindow[0] +
|
|
760
|
+
", " +
|
|
761
|
+
parentLocationInWindow[1] +
|
|
762
|
+
")"
|
|
763
|
+
);
|
|
764
|
+
Log.d(
|
|
765
|
+
"CameraPreview",
|
|
766
|
+
"Parent locationOnScreen: (" +
|
|
767
|
+
parentLocationOnScreen[0] +
|
|
768
|
+
", " +
|
|
769
|
+
parentLocationOnScreen[1] +
|
|
770
|
+
")"
|
|
771
|
+
);
|
|
772
|
+
Log.d(
|
|
773
|
+
"CameraPreview",
|
|
774
|
+
"Parent class: " + webViewParent.getClass().getSimpleName()
|
|
775
|
+
);
|
|
776
|
+
Log.d(
|
|
777
|
+
"CameraPreview",
|
|
778
|
+
"Requested position (logical): (" + x + ", " + y + ")"
|
|
779
|
+
);
|
|
780
|
+
Log.d("CameraPreview", "Pixel ratio: " + pixelRatio);
|
|
781
|
+
Log.d(
|
|
782
|
+
"CameraPreview",
|
|
783
|
+
"Final computed position (no offset): (" +
|
|
784
|
+
computedX +
|
|
785
|
+
", " +
|
|
786
|
+
computedY +
|
|
787
|
+
")"
|
|
788
|
+
);
|
|
789
|
+
Log.d("CameraPreview", "5. IS_CENTERED - " + (x == -1 || y == -1));
|
|
790
|
+
Log.d("CameraPreview", "========================");
|
|
791
|
+
|
|
792
|
+
// Pass along whether we're centering so CameraXView knows not to add insets
|
|
793
|
+
boolean isCentered = (x == -1 || y == -1);
|
|
794
|
+
|
|
795
|
+
CameraSessionConfiguration config = new CameraSessionConfiguration(
|
|
796
|
+
finalDeviceId,
|
|
797
|
+
position,
|
|
798
|
+
computedX,
|
|
799
|
+
computedY,
|
|
800
|
+
computedWidth,
|
|
801
|
+
computedHeight,
|
|
802
|
+
paddingBottom,
|
|
803
|
+
toBack,
|
|
804
|
+
storeToFile,
|
|
805
|
+
enableOpacity,
|
|
806
|
+
enableZoom,
|
|
807
|
+
disableExifHeaderStripping,
|
|
808
|
+
disableAudio,
|
|
809
|
+
1.0f,
|
|
810
|
+
aspectRatio,
|
|
811
|
+
gridMode
|
|
812
|
+
);
|
|
813
|
+
config.setTargetZoom(finalTargetZoom);
|
|
814
|
+
config.setCentered(isCentered);
|
|
815
|
+
|
|
378
816
|
bridge.saveCall(call);
|
|
379
817
|
cameraStartCallbackId = call.getCallbackId();
|
|
380
818
|
cameraXView.startSession(config);
|
|
381
|
-
}
|
|
382
|
-
);
|
|
819
|
+
});
|
|
383
820
|
}
|
|
384
821
|
|
|
385
822
|
@Override
|
|
@@ -407,34 +844,245 @@ public class CameraPreview
|
|
|
407
844
|
bridge.releaseCall(pluginCall);
|
|
408
845
|
}
|
|
409
846
|
|
|
847
|
+
@Override
|
|
848
|
+
public void onCameraStarted(int width, int height, int x, int y) {
|
|
849
|
+
PluginCall call = bridge.getSavedCall(cameraStartCallbackId);
|
|
850
|
+
if (call != null) {
|
|
851
|
+
// Convert pixel values back to logical units
|
|
852
|
+
DisplayMetrics metrics = getBridge()
|
|
853
|
+
.getActivity()
|
|
854
|
+
.getResources()
|
|
855
|
+
.getDisplayMetrics();
|
|
856
|
+
float pixelRatio = metrics.density;
|
|
857
|
+
|
|
858
|
+
// When WebView is offset from the top (e.g., below status bar),
|
|
859
|
+
// we need to convert between JavaScript coordinates (relative to WebView)
|
|
860
|
+
// and native coordinates (relative to screen)
|
|
861
|
+
WebView webView = getBridge().getWebView();
|
|
862
|
+
int webViewTopInset = 0;
|
|
863
|
+
boolean isEdgeToEdgeActive = false;
|
|
864
|
+
if (webView != null) {
|
|
865
|
+
int[] location = new int[2];
|
|
866
|
+
webView.getLocationOnScreen(location);
|
|
867
|
+
webViewTopInset = location[1];
|
|
868
|
+
isEdgeToEdgeActive = webViewTopInset > 0;
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
// Only convert to relative position if edge-to-edge is active
|
|
872
|
+
int relativeY = isEdgeToEdgeActive ? (y - webViewTopInset) : y;
|
|
873
|
+
|
|
874
|
+
Log.d("CameraPreview", "========================");
|
|
875
|
+
Log.d("CameraPreview", "CAMERA STARTED - POSITION RETURNED:");
|
|
876
|
+
Log.d(
|
|
877
|
+
"CameraPreview",
|
|
878
|
+
"7. RETURNED (pixels) - x=" +
|
|
879
|
+
x +
|
|
880
|
+
", y=" +
|
|
881
|
+
y +
|
|
882
|
+
", width=" +
|
|
883
|
+
width +
|
|
884
|
+
", height=" +
|
|
885
|
+
height
|
|
886
|
+
);
|
|
887
|
+
Log.d(
|
|
888
|
+
"CameraPreview",
|
|
889
|
+
"8. EDGE-TO-EDGE - " + (isEdgeToEdgeActive ? "ACTIVE" : "INACTIVE")
|
|
890
|
+
);
|
|
891
|
+
Log.d("CameraPreview", "9. WEBVIEW INSET - " + webViewTopInset);
|
|
892
|
+
Log.d(
|
|
893
|
+
"CameraPreview",
|
|
894
|
+
"10. RELATIVE Y - " +
|
|
895
|
+
relativeY +
|
|
896
|
+
" (y=" +
|
|
897
|
+
y +
|
|
898
|
+
(isEdgeToEdgeActive ? " - inset=" + webViewTopInset : " unchanged") +
|
|
899
|
+
")"
|
|
900
|
+
);
|
|
901
|
+
Log.d(
|
|
902
|
+
"CameraPreview",
|
|
903
|
+
"11. RETURNED (logical) - x=" +
|
|
904
|
+
(x / pixelRatio) +
|
|
905
|
+
", y=" +
|
|
906
|
+
(relativeY / pixelRatio) +
|
|
907
|
+
", width=" +
|
|
908
|
+
(width / pixelRatio) +
|
|
909
|
+
", height=" +
|
|
910
|
+
(height / pixelRatio)
|
|
911
|
+
);
|
|
912
|
+
Log.d("CameraPreview", "12. PIXEL RATIO - " + pixelRatio);
|
|
913
|
+
Log.d("CameraPreview", "========================");
|
|
914
|
+
|
|
915
|
+
JSObject result = new JSObject();
|
|
916
|
+
result.put("width", width / pixelRatio);
|
|
917
|
+
result.put("height", height / pixelRatio);
|
|
918
|
+
result.put("x", x / pixelRatio);
|
|
919
|
+
result.put("y", relativeY / pixelRatio);
|
|
920
|
+
call.resolve(result);
|
|
921
|
+
bridge.releaseCall(call);
|
|
922
|
+
cameraStartCallbackId = null; // Prevent re-use
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
|
|
410
926
|
@Override
|
|
411
927
|
public void onSampleTaken(String result) {
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
bridge.getSavedCall(snapshotCallbackId).resolve(jsObject);
|
|
928
|
+
// Handle sample taken if needed
|
|
929
|
+
Log.i("CameraPreview", "Sample taken: " + result);
|
|
415
930
|
}
|
|
416
931
|
|
|
417
932
|
@Override
|
|
418
933
|
public void onSampleTakenError(String message) {
|
|
419
|
-
|
|
934
|
+
// Handle sample taken error if needed
|
|
935
|
+
Log.e("CameraPreview", "Sample taken error: " + message);
|
|
420
936
|
}
|
|
421
937
|
|
|
422
938
|
@Override
|
|
423
|
-
public void
|
|
424
|
-
PluginCall
|
|
425
|
-
if (
|
|
426
|
-
|
|
427
|
-
bridge.releaseCall(
|
|
939
|
+
public void onCameraStartError(String message) {
|
|
940
|
+
PluginCall call = bridge.getSavedCall(cameraStartCallbackId);
|
|
941
|
+
if (call != null) {
|
|
942
|
+
call.reject(message);
|
|
943
|
+
bridge.releaseCall(call);
|
|
944
|
+
cameraStartCallbackId = null;
|
|
428
945
|
}
|
|
429
946
|
}
|
|
430
947
|
|
|
431
|
-
@
|
|
432
|
-
public void
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
948
|
+
@PluginMethod
|
|
949
|
+
public void setAspectRatio(PluginCall call) {
|
|
950
|
+
if (cameraXView == null || !cameraXView.isRunning()) {
|
|
951
|
+
call.reject("Camera is not running");
|
|
952
|
+
return;
|
|
953
|
+
}
|
|
954
|
+
String aspectRatio = call.getString("aspectRatio", "4:3");
|
|
955
|
+
Float x = call.getFloat("x");
|
|
956
|
+
Float y = call.getFloat("y");
|
|
957
|
+
|
|
958
|
+
getActivity()
|
|
959
|
+
.runOnUiThread(() -> {
|
|
960
|
+
cameraXView.setAspectRatio(aspectRatio, x, y, () -> {
|
|
961
|
+
// Return the actual preview bounds after layout and camera operations are complete
|
|
962
|
+
int[] bounds = cameraXView.getCurrentPreviewBounds();
|
|
963
|
+
JSObject ret = new JSObject();
|
|
964
|
+
ret.put("x", bounds[0]);
|
|
965
|
+
ret.put("y", bounds[1]);
|
|
966
|
+
ret.put("width", bounds[2]);
|
|
967
|
+
ret.put("height", bounds[3]);
|
|
968
|
+
call.resolve(ret);
|
|
969
|
+
});
|
|
970
|
+
});
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
@PluginMethod
|
|
974
|
+
public void getAspectRatio(PluginCall call) {
|
|
975
|
+
if (cameraXView == null || !cameraXView.isRunning()) {
|
|
976
|
+
call.reject("Camera is not running");
|
|
977
|
+
return;
|
|
437
978
|
}
|
|
979
|
+
String aspectRatio = cameraXView.getAspectRatio();
|
|
980
|
+
JSObject ret = new JSObject();
|
|
981
|
+
ret.put("aspectRatio", aspectRatio);
|
|
982
|
+
call.resolve(ret);
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
@PluginMethod
|
|
986
|
+
public void setGridMode(PluginCall call) {
|
|
987
|
+
if (cameraXView == null || !cameraXView.isRunning()) {
|
|
988
|
+
call.reject("Camera is not running");
|
|
989
|
+
return;
|
|
990
|
+
}
|
|
991
|
+
String gridMode = call.getString("gridMode", "none");
|
|
992
|
+
getActivity()
|
|
993
|
+
.runOnUiThread(() -> {
|
|
994
|
+
cameraXView.setGridMode(gridMode);
|
|
995
|
+
call.resolve();
|
|
996
|
+
});
|
|
438
997
|
}
|
|
439
998
|
|
|
999
|
+
@PluginMethod
|
|
1000
|
+
public void getGridMode(PluginCall call) {
|
|
1001
|
+
if (cameraXView == null || !cameraXView.isRunning()) {
|
|
1002
|
+
call.reject("Camera is not running");
|
|
1003
|
+
return;
|
|
1004
|
+
}
|
|
1005
|
+
JSObject ret = new JSObject();
|
|
1006
|
+
ret.put("gridMode", cameraXView.getGridMode());
|
|
1007
|
+
call.resolve(ret);
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
@PluginMethod
|
|
1011
|
+
public void getPreviewSize(PluginCall call) {
|
|
1012
|
+
if (cameraXView == null || !cameraXView.isRunning()) {
|
|
1013
|
+
call.reject("Camera is not running");
|
|
1014
|
+
return;
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
// Convert pixel values back to logical units
|
|
1018
|
+
DisplayMetrics metrics = getBridge()
|
|
1019
|
+
.getActivity()
|
|
1020
|
+
.getResources()
|
|
1021
|
+
.getDisplayMetrics();
|
|
1022
|
+
float pixelRatio = metrics.density;
|
|
1023
|
+
|
|
1024
|
+
JSObject ret = new JSObject();
|
|
1025
|
+
ret.put("x", cameraXView.getPreviewX() / pixelRatio);
|
|
1026
|
+
ret.put("y", cameraXView.getPreviewY() / pixelRatio);
|
|
1027
|
+
ret.put("width", cameraXView.getPreviewWidth() / pixelRatio);
|
|
1028
|
+
ret.put("height", cameraXView.getPreviewHeight() / pixelRatio);
|
|
1029
|
+
call.resolve(ret);
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
@PluginMethod
|
|
1033
|
+
public void setPreviewSize(PluginCall call) {
|
|
1034
|
+
if (cameraXView == null || !cameraXView.isRunning()) {
|
|
1035
|
+
call.reject("Camera is not running");
|
|
1036
|
+
return;
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
// Get values from call - null values will become 0
|
|
1040
|
+
Integer xParam = call.getInt("x");
|
|
1041
|
+
Integer yParam = call.getInt("y");
|
|
1042
|
+
Integer widthParam = call.getInt("width");
|
|
1043
|
+
Integer heightParam = call.getInt("height");
|
|
1044
|
+
|
|
1045
|
+
// Apply pixel ratio conversion to non-null values
|
|
1046
|
+
DisplayMetrics metrics = getBridge()
|
|
1047
|
+
.getActivity()
|
|
1048
|
+
.getResources()
|
|
1049
|
+
.getDisplayMetrics();
|
|
1050
|
+
float pixelRatio = metrics.density;
|
|
1051
|
+
|
|
1052
|
+
// Check if edge-to-edge mode is active
|
|
1053
|
+
WebView webView = getBridge().getWebView();
|
|
1054
|
+
int webViewTopInset = 0;
|
|
1055
|
+
boolean isEdgeToEdgeActive = false;
|
|
1056
|
+
if (webView != null) {
|
|
1057
|
+
int[] location = new int[2];
|
|
1058
|
+
webView.getLocationOnScreen(location);
|
|
1059
|
+
webViewTopInset = location[1];
|
|
1060
|
+
isEdgeToEdgeActive = webViewTopInset > 0;
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
int x = (xParam != null && xParam > 0) ? (int) (xParam * pixelRatio) : 0;
|
|
1064
|
+
int y = (yParam != null && yParam > 0) ? (int) (yParam * pixelRatio) : 0;
|
|
1065
|
+
|
|
1066
|
+
// Add edge-to-edge inset to Y if active
|
|
1067
|
+
if (isEdgeToEdgeActive && y > 0) {
|
|
1068
|
+
y += webViewTopInset;
|
|
1069
|
+
}
|
|
1070
|
+
int width = (widthParam != null && widthParam > 0)
|
|
1071
|
+
? (int) (widthParam * pixelRatio)
|
|
1072
|
+
: 0;
|
|
1073
|
+
int height = (heightParam != null && heightParam > 0)
|
|
1074
|
+
? (int) (heightParam * pixelRatio)
|
|
1075
|
+
: 0;
|
|
1076
|
+
|
|
1077
|
+
cameraXView.setPreviewSize(x, y, width, height, () -> {
|
|
1078
|
+
// Return the actual preview bounds after layout operations are complete
|
|
1079
|
+
int[] bounds = cameraXView.getCurrentPreviewBounds();
|
|
1080
|
+
JSObject ret = new JSObject();
|
|
1081
|
+
ret.put("x", bounds[0]);
|
|
1082
|
+
ret.put("y", bounds[1]);
|
|
1083
|
+
ret.put("width", bounds[2]);
|
|
1084
|
+
ret.put("height", bounds[3]);
|
|
1085
|
+
call.resolve(ret);
|
|
1086
|
+
});
|
|
1087
|
+
}
|
|
440
1088
|
}
|