@capgo/camera-preview 7.4.0-beta.1 → 7.4.0-beta.11
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 +195 -31
- 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 +5 -3
- package/android/src/main/java/com/ahm/capacitor/camera/preview/CameraPreview.java +473 -88
- package/android/src/main/java/com/ahm/capacitor/camera/preview/CameraXView.java +2065 -704
- package/android/src/main/java/com/ahm/capacitor/camera/preview/GridOverlayView.java +95 -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 +152 -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 +235 -6
- package/dist/esm/definitions.d.ts +119 -3
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/web.d.ts +47 -3
- package/dist/esm/web.js +297 -96
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +293 -96
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +293 -96
- package/dist/plugin.js.map +1 -1
- package/ios/Sources/CapgoCameraPreview/CameraController.swift +364 -218
- package/ios/Sources/CapgoCameraPreview/GridOverlayView.swift +65 -0
- package/ios/Sources/CapgoCameraPreview/Plugin.swift +886 -242
- package/package.json +1 -1
|
@@ -3,12 +3,17 @@ 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;
|
|
7
|
-
import android.
|
|
8
|
+
import android.location.Location;
|
|
8
9
|
import android.util.DisplayMetrics;
|
|
9
|
-
import android.util.
|
|
10
|
-
import android.
|
|
11
|
-
import
|
|
10
|
+
import android.util.Log;
|
|
11
|
+
import android.util.Size;
|
|
12
|
+
import android.view.ViewGroup;
|
|
13
|
+
import com.ahm.capacitor.camera.preview.model.CameraDevice;
|
|
14
|
+
import com.ahm.capacitor.camera.preview.model.CameraSessionConfiguration;
|
|
15
|
+
import com.ahm.capacitor.camera.preview.model.LensInfo;
|
|
16
|
+
import com.ahm.capacitor.camera.preview.model.ZoomFactors;
|
|
12
17
|
import com.getcapacitor.JSArray;
|
|
13
18
|
import com.getcapacitor.JSObject;
|
|
14
19
|
import com.getcapacitor.Logger;
|
|
@@ -19,14 +24,11 @@ import com.getcapacitor.PluginMethod;
|
|
|
19
24
|
import com.getcapacitor.annotation.CapacitorPlugin;
|
|
20
25
|
import com.getcapacitor.annotation.Permission;
|
|
21
26
|
import com.getcapacitor.annotation.PermissionCallback;
|
|
22
|
-
import com.
|
|
23
|
-
import com.
|
|
24
|
-
import com.ahm.capacitor.camera.preview.model.ZoomFactors;
|
|
27
|
+
import com.google.android.gms.location.FusedLocationProviderClient;
|
|
28
|
+
import com.google.android.gms.location.LocationServices;
|
|
25
29
|
import java.util.List;
|
|
26
30
|
import java.util.Objects;
|
|
27
|
-
import
|
|
28
|
-
import android.util.Log;
|
|
29
|
-
import com.ahm.capacitor.camera.preview.model.LensInfo;
|
|
31
|
+
import org.json.JSONObject;
|
|
30
32
|
|
|
31
33
|
@CapacitorPlugin(
|
|
32
34
|
name = "CameraPreview",
|
|
@@ -39,6 +41,13 @@ import com.ahm.capacitor.camera.preview.model.LensInfo;
|
|
|
39
41
|
strings = { CAMERA },
|
|
40
42
|
alias = CameraPreview.CAMERA_ONLY_PERMISSION_ALIAS
|
|
41
43
|
),
|
|
44
|
+
@Permission(
|
|
45
|
+
strings = {
|
|
46
|
+
Manifest.permission.ACCESS_COARSE_LOCATION,
|
|
47
|
+
Manifest.permission.ACCESS_FINE_LOCATION,
|
|
48
|
+
},
|
|
49
|
+
alias = CameraPreview.CAMERA_WITH_LOCATION_PERMISSION_ALIAS
|
|
50
|
+
),
|
|
42
51
|
}
|
|
43
52
|
)
|
|
44
53
|
public class CameraPreview
|
|
@@ -47,16 +56,23 @@ public class CameraPreview
|
|
|
47
56
|
|
|
48
57
|
static final String CAMERA_WITH_AUDIO_PERMISSION_ALIAS = "cameraWithAudio";
|
|
49
58
|
static final String CAMERA_ONLY_PERMISSION_ALIAS = "cameraOnly";
|
|
59
|
+
static final String CAMERA_WITH_LOCATION_PERMISSION_ALIAS =
|
|
60
|
+
"cameraWithLocation";
|
|
50
61
|
|
|
51
62
|
private String captureCallbackId = "";
|
|
52
63
|
private String snapshotCallbackId = "";
|
|
53
64
|
private String cameraStartCallbackId = "";
|
|
54
|
-
private int previousOrientationRequest =
|
|
65
|
+
private int previousOrientationRequest =
|
|
66
|
+
ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
|
|
55
67
|
private CameraXView cameraXView;
|
|
68
|
+
private FusedLocationProviderClient fusedLocationClient;
|
|
69
|
+
private Location lastLocation;
|
|
56
70
|
|
|
57
71
|
@PluginMethod
|
|
58
72
|
public void start(PluginCall call) {
|
|
59
|
-
boolean disableAudio = Boolean.TRUE.equals(
|
|
73
|
+
boolean disableAudio = Boolean.TRUE.equals(
|
|
74
|
+
call.getBoolean("disableAudio", true)
|
|
75
|
+
);
|
|
60
76
|
String permissionAlias = disableAudio
|
|
61
77
|
? CAMERA_ONLY_PERMISSION_ALIAS
|
|
62
78
|
: CAMERA_WITH_AUDIO_PERMISSION_ALIAS;
|
|
@@ -83,15 +99,79 @@ public class CameraPreview
|
|
|
83
99
|
}
|
|
84
100
|
|
|
85
101
|
@PluginMethod
|
|
86
|
-
public void capture(PluginCall call) {
|
|
102
|
+
public void capture(final PluginCall call) {
|
|
87
103
|
if (cameraXView == null || !cameraXView.isRunning()) {
|
|
88
104
|
call.reject("Camera is not running");
|
|
89
105
|
return;
|
|
90
106
|
}
|
|
107
|
+
|
|
108
|
+
final boolean withExifLocation = call.getBoolean("withExifLocation", false);
|
|
109
|
+
|
|
110
|
+
if (withExifLocation) {
|
|
111
|
+
if (
|
|
112
|
+
getPermissionState(CAMERA_WITH_LOCATION_PERMISSION_ALIAS) !=
|
|
113
|
+
PermissionState.GRANTED
|
|
114
|
+
) {
|
|
115
|
+
requestPermissionForAlias(
|
|
116
|
+
CAMERA_WITH_LOCATION_PERMISSION_ALIAS,
|
|
117
|
+
call,
|
|
118
|
+
"captureWithLocationPermission"
|
|
119
|
+
);
|
|
120
|
+
} else {
|
|
121
|
+
getLocationAndCapture(call);
|
|
122
|
+
}
|
|
123
|
+
} else {
|
|
124
|
+
captureWithoutLocation(call);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
@PermissionCallback
|
|
129
|
+
private void captureWithLocationPermission(PluginCall call) {
|
|
130
|
+
if (
|
|
131
|
+
getPermissionState(CAMERA_WITH_LOCATION_PERMISSION_ALIAS) ==
|
|
132
|
+
PermissionState.GRANTED
|
|
133
|
+
) {
|
|
134
|
+
getLocationAndCapture(call);
|
|
135
|
+
} else {
|
|
136
|
+
Logger.warn(
|
|
137
|
+
"Location permission denied. Capturing photo without location data."
|
|
138
|
+
);
|
|
139
|
+
captureWithoutLocation(call);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
private void getLocationAndCapture(PluginCall call) {
|
|
144
|
+
if (fusedLocationClient == null) {
|
|
145
|
+
fusedLocationClient = LocationServices.getFusedLocationProviderClient(
|
|
146
|
+
getContext()
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
fusedLocationClient
|
|
150
|
+
.getLastLocation()
|
|
151
|
+
.addOnSuccessListener(getActivity(), location -> {
|
|
152
|
+
lastLocation = location;
|
|
153
|
+
proceedWithCapture(call, lastLocation);
|
|
154
|
+
})
|
|
155
|
+
.addOnFailureListener(e -> {
|
|
156
|
+
Logger.error("Failed to get location: " + e.getMessage());
|
|
157
|
+
proceedWithCapture(call, null);
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
private void captureWithoutLocation(PluginCall call) {
|
|
162
|
+
proceedWithCapture(call, null);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
private void proceedWithCapture(PluginCall call, Location location) {
|
|
91
166
|
bridge.saveCall(call);
|
|
92
167
|
captureCallbackId = call.getCallbackId();
|
|
168
|
+
|
|
93
169
|
Integer quality = Objects.requireNonNull(call.getInt("quality", 85));
|
|
94
|
-
|
|
170
|
+
final boolean saveToGallery = call.getBoolean("saveToGallery", false);
|
|
171
|
+
Integer width = call.getInt("width");
|
|
172
|
+
Integer height = call.getInt("height");
|
|
173
|
+
|
|
174
|
+
cameraXView.capturePhoto(quality, saveToGallery, width, height, location);
|
|
95
175
|
}
|
|
96
176
|
|
|
97
177
|
@PluginMethod
|
|
@@ -110,19 +190,17 @@ public class CameraPreview
|
|
|
110
190
|
public void stop(final PluginCall call) {
|
|
111
191
|
bridge
|
|
112
192
|
.getActivity()
|
|
113
|
-
.runOnUiThread(
|
|
114
|
-
()
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
cameraXView = null;
|
|
122
|
-
}
|
|
123
|
-
call.resolve();
|
|
193
|
+
.runOnUiThread(() -> {
|
|
194
|
+
getBridge()
|
|
195
|
+
.getActivity()
|
|
196
|
+
.setRequestedOrientation(previousOrientationRequest);
|
|
197
|
+
|
|
198
|
+
if (cameraXView != null && cameraXView.isRunning()) {
|
|
199
|
+
cameraXView.stopSession();
|
|
200
|
+
cameraXView = null;
|
|
124
201
|
}
|
|
125
|
-
|
|
202
|
+
call.resolve();
|
|
203
|
+
});
|
|
126
204
|
}
|
|
127
205
|
|
|
128
206
|
@PluginMethod
|
|
@@ -150,7 +228,9 @@ public class CameraPreview
|
|
|
150
228
|
|
|
151
229
|
@PluginMethod
|
|
152
230
|
public void getAvailableDevices(PluginCall call) {
|
|
153
|
-
List<CameraDevice> devices = CameraXView.getAvailableDevicesStatic(
|
|
231
|
+
List<CameraDevice> devices = CameraXView.getAvailableDevicesStatic(
|
|
232
|
+
getContext()
|
|
233
|
+
);
|
|
154
234
|
JSArray devicesArray = new JSArray();
|
|
155
235
|
for (CameraDevice device : devices) {
|
|
156
236
|
JSObject deviceJson = new JSObject();
|
|
@@ -227,7 +307,7 @@ public class CameraPreview
|
|
|
227
307
|
JSObject rear = new JSObject();
|
|
228
308
|
rear.put("facing", "rear");
|
|
229
309
|
JSArray rearSizesJs = new JSArray();
|
|
230
|
-
for(Size size : rearSizes) {
|
|
310
|
+
for (Size size : rearSizes) {
|
|
231
311
|
JSObject sizeJs = new JSObject();
|
|
232
312
|
sizeJs.put("width", size.getWidth());
|
|
233
313
|
sizeJs.put("height", size.getHeight());
|
|
@@ -235,12 +315,12 @@ public class CameraPreview
|
|
|
235
315
|
}
|
|
236
316
|
rear.put("supportedPictureSizes", rearSizesJs);
|
|
237
317
|
supportedPictureSizesResult.put(rear);
|
|
238
|
-
|
|
318
|
+
|
|
239
319
|
List<Size> frontSizes = CameraXView.getSupportedPictureSizes("front");
|
|
240
320
|
JSObject front = new JSObject();
|
|
241
321
|
front.put("facing", "front");
|
|
242
322
|
JSArray frontSizesJs = new JSArray();
|
|
243
|
-
for(Size size : frontSizes) {
|
|
323
|
+
for (Size size : frontSizes) {
|
|
244
324
|
JSObject sizeJs = new JSObject();
|
|
245
325
|
sizeJs.put("width", size.getWidth());
|
|
246
326
|
sizeJs.put("height", size.getHeight());
|
|
@@ -248,7 +328,7 @@ public class CameraPreview
|
|
|
248
328
|
}
|
|
249
329
|
front.put("supportedPictureSizes", frontSizesJs);
|
|
250
330
|
supportedPictureSizesResult.put(front);
|
|
251
|
-
|
|
331
|
+
|
|
252
332
|
JSObject ret = new JSObject();
|
|
253
333
|
ret.put("supportedPictureSizes", supportedPictureSizesResult);
|
|
254
334
|
call.resolve(ret);
|
|
@@ -307,8 +387,14 @@ public class CameraPreview
|
|
|
307
387
|
|
|
308
388
|
@PermissionCallback
|
|
309
389
|
private void handleCameraPermissionResult(PluginCall call) {
|
|
310
|
-
if (
|
|
311
|
-
|
|
390
|
+
if (
|
|
391
|
+
PermissionState.GRANTED.equals(
|
|
392
|
+
getPermissionState(CAMERA_ONLY_PERMISSION_ALIAS)
|
|
393
|
+
) ||
|
|
394
|
+
PermissionState.GRANTED.equals(
|
|
395
|
+
getPermissionState(CAMERA_WITH_AUDIO_PERMISSION_ALIAS)
|
|
396
|
+
)
|
|
397
|
+
) {
|
|
312
398
|
startCamera(call);
|
|
313
399
|
} else {
|
|
314
400
|
call.reject("Permission failed");
|
|
@@ -320,106 +406,405 @@ public class CameraPreview
|
|
|
320
406
|
String originalDeviceId = call.getString("deviceId");
|
|
321
407
|
String deviceId = originalDeviceId; // Use a mutable variable
|
|
322
408
|
|
|
323
|
-
final String position = (positionParam == null ||
|
|
409
|
+
final String position = (positionParam == null ||
|
|
410
|
+
positionParam.isEmpty() ||
|
|
411
|
+
"rear".equals(positionParam) ||
|
|
412
|
+
"back".equals(positionParam))
|
|
413
|
+
? "back"
|
|
414
|
+
: "front";
|
|
324
415
|
final int x = call.getInt("x", 0);
|
|
325
416
|
final int y = call.getInt("y", 0);
|
|
326
417
|
final int width = call.getInt("width", 0);
|
|
327
418
|
final int height = call.getInt("height", 0);
|
|
328
419
|
final int paddingBottom = call.getInt("paddingBottom", 0);
|
|
329
|
-
final boolean toBack = call.getBoolean("toBack", true);
|
|
330
|
-
final boolean storeToFile =
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
final boolean
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
420
|
+
final boolean toBack = Boolean.TRUE.equals(call.getBoolean("toBack", true));
|
|
421
|
+
final boolean storeToFile = Boolean.TRUE.equals(
|
|
422
|
+
call.getBoolean("storeToFile", false)
|
|
423
|
+
);
|
|
424
|
+
final boolean enableOpacity = Boolean.TRUE.equals(
|
|
425
|
+
call.getBoolean("enableOpacity", false)
|
|
426
|
+
);
|
|
427
|
+
final boolean enableZoom = Boolean.TRUE.equals(
|
|
428
|
+
call.getBoolean("enableZoom", false)
|
|
429
|
+
);
|
|
430
|
+
final boolean disableExifHeaderStripping = Boolean.TRUE.equals(
|
|
431
|
+
call.getBoolean("disableExifHeaderStripping", false)
|
|
432
|
+
);
|
|
433
|
+
final boolean lockOrientation = Boolean.TRUE.equals(
|
|
434
|
+
call.getBoolean("lockAndroidOrientation", false)
|
|
435
|
+
);
|
|
436
|
+
final boolean disableAudio = Boolean.TRUE.equals(
|
|
437
|
+
call.getBoolean("disableAudio", true)
|
|
438
|
+
);
|
|
439
|
+
final String aspectRatio = call.getString("aspectRatio", "4:3");
|
|
440
|
+
final String gridMode = call.getString("gridMode", "none");
|
|
441
|
+
|
|
442
|
+
// Check for conflict between aspectRatio and size
|
|
443
|
+
if (
|
|
444
|
+
call.getData().has("aspectRatio") &&
|
|
445
|
+
(call.getData().has("width") || call.getData().has("height"))
|
|
446
|
+
) {
|
|
447
|
+
call.reject(
|
|
448
|
+
"Cannot set both aspectRatio and size (width/height). Use setPreviewSize after start."
|
|
449
|
+
);
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
|
|
337
453
|
float targetZoom = 1.0f;
|
|
338
454
|
// Check if the selected device is a physical ultra-wide
|
|
339
455
|
if (originalDeviceId != null) {
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
456
|
+
List<CameraDevice> devices = CameraXView.getAvailableDevicesStatic(
|
|
457
|
+
getContext()
|
|
458
|
+
);
|
|
459
|
+
for (CameraDevice device : devices) {
|
|
460
|
+
if (
|
|
461
|
+
originalDeviceId.equals(device.getDeviceId()) && !device.isLogical()
|
|
462
|
+
) {
|
|
463
|
+
for (LensInfo lens : device.getLenses()) {
|
|
464
|
+
if ("ultraWide".equals(lens.getDeviceType())) {
|
|
465
|
+
Log.d(
|
|
466
|
+
"CameraPreview",
|
|
467
|
+
"Ultra-wide lens selected. Targeting 0.5x zoom on logical camera."
|
|
468
|
+
);
|
|
469
|
+
targetZoom = 0.5f;
|
|
470
|
+
// Force the use of the logical camera by clearing the specific deviceId
|
|
471
|
+
deviceId = null;
|
|
472
|
+
break;
|
|
352
473
|
}
|
|
353
|
-
|
|
474
|
+
}
|
|
354
475
|
}
|
|
476
|
+
if (deviceId == null) break; // Exit outer loop once we've made our decision
|
|
477
|
+
}
|
|
355
478
|
}
|
|
356
479
|
|
|
357
|
-
previousOrientationRequest = getBridge()
|
|
480
|
+
previousOrientationRequest = getBridge()
|
|
481
|
+
.getActivity()
|
|
482
|
+
.getRequestedOrientation();
|
|
358
483
|
cameraXView = new CameraXView(getContext(), getBridge().getWebView());
|
|
359
484
|
cameraXView.setListener(this);
|
|
360
485
|
|
|
361
486
|
String finalDeviceId = deviceId;
|
|
362
487
|
float finalTargetZoom = targetZoom;
|
|
363
|
-
getBridge()
|
|
364
|
-
|
|
488
|
+
getBridge()
|
|
489
|
+
.getActivity()
|
|
490
|
+
.runOnUiThread(() -> {
|
|
491
|
+
DisplayMetrics metrics = getBridge()
|
|
492
|
+
.getActivity()
|
|
493
|
+
.getResources()
|
|
494
|
+
.getDisplayMetrics();
|
|
365
495
|
if (lockOrientation) {
|
|
366
|
-
getBridge()
|
|
496
|
+
getBridge()
|
|
497
|
+
.getActivity()
|
|
498
|
+
.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED);
|
|
367
499
|
}
|
|
368
|
-
int computedX = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, x, metrics);
|
|
369
|
-
int computedY = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, y, metrics);
|
|
370
|
-
int computedWidth = width != 0 ? (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, width, metrics) : (int) getBridge().getWebView().getWidth();
|
|
371
|
-
int computedHeight = height != 0 ? (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, height, metrics) : (int) getBridge().getWebView().getHeight();
|
|
372
|
-
computedHeight -= (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, paddingBottom, metrics);
|
|
373
500
|
|
|
374
|
-
|
|
501
|
+
// Debug: Let's check all the positioning information
|
|
502
|
+
ViewGroup webViewParent = (ViewGroup) getBridge()
|
|
503
|
+
.getWebView()
|
|
504
|
+
.getParent();
|
|
505
|
+
|
|
506
|
+
// Get webview position in different coordinate systems
|
|
507
|
+
int[] webViewLocationInWindow = new int[2];
|
|
508
|
+
int[] webViewLocationOnScreen = new int[2];
|
|
509
|
+
getBridge().getWebView().getLocationInWindow(webViewLocationInWindow);
|
|
510
|
+
getBridge().getWebView().getLocationOnScreen(webViewLocationOnScreen);
|
|
511
|
+
|
|
512
|
+
int webViewLeft = getBridge().getWebView().getLeft();
|
|
513
|
+
int webViewTop = getBridge().getWebView().getTop();
|
|
514
|
+
|
|
515
|
+
// Check parent position too
|
|
516
|
+
int[] parentLocationInWindow = new int[2];
|
|
517
|
+
int[] parentLocationOnScreen = new int[2];
|
|
518
|
+
webViewParent.getLocationInWindow(parentLocationInWindow);
|
|
519
|
+
webViewParent.getLocationOnScreen(parentLocationOnScreen);
|
|
520
|
+
|
|
521
|
+
// Calculate pixel ratio
|
|
522
|
+
float pixelRatio = metrics.density;
|
|
523
|
+
|
|
524
|
+
// Try using just the pixel ratio without any webview offset for now
|
|
525
|
+
int computedX = (int) (x * pixelRatio);
|
|
526
|
+
int computedY = (int) (y * pixelRatio);
|
|
527
|
+
|
|
528
|
+
Log.d("CameraPreview", "=== COORDINATE DEBUG ===");
|
|
529
|
+
Log.d(
|
|
530
|
+
"CameraPreview",
|
|
531
|
+
"WebView getLeft/getTop: (" + webViewLeft + ", " + webViewTop + ")"
|
|
532
|
+
);
|
|
533
|
+
Log.d(
|
|
534
|
+
"CameraPreview",
|
|
535
|
+
"WebView locationInWindow: (" +
|
|
536
|
+
webViewLocationInWindow[0] +
|
|
537
|
+
", " +
|
|
538
|
+
webViewLocationInWindow[1] +
|
|
539
|
+
")"
|
|
540
|
+
);
|
|
541
|
+
Log.d(
|
|
542
|
+
"CameraPreview",
|
|
543
|
+
"WebView locationOnScreen: (" +
|
|
544
|
+
webViewLocationOnScreen[0] +
|
|
545
|
+
", " +
|
|
546
|
+
webViewLocationOnScreen[1] +
|
|
547
|
+
")"
|
|
548
|
+
);
|
|
549
|
+
Log.d(
|
|
550
|
+
"CameraPreview",
|
|
551
|
+
"Parent locationInWindow: (" +
|
|
552
|
+
parentLocationInWindow[0] +
|
|
553
|
+
", " +
|
|
554
|
+
parentLocationInWindow[1] +
|
|
555
|
+
")"
|
|
556
|
+
);
|
|
557
|
+
Log.d(
|
|
558
|
+
"CameraPreview",
|
|
559
|
+
"Parent locationOnScreen: (" +
|
|
560
|
+
parentLocationOnScreen[0] +
|
|
561
|
+
", " +
|
|
562
|
+
parentLocationOnScreen[1] +
|
|
563
|
+
")"
|
|
564
|
+
);
|
|
565
|
+
Log.d(
|
|
566
|
+
"CameraPreview",
|
|
567
|
+
"Parent class: " + webViewParent.getClass().getSimpleName()
|
|
568
|
+
);
|
|
569
|
+
Log.d(
|
|
570
|
+
"CameraPreview",
|
|
571
|
+
"Requested position (logical): (" + x + ", " + y + ")"
|
|
572
|
+
);
|
|
573
|
+
Log.d("CameraPreview", "Pixel ratio: " + pixelRatio);
|
|
574
|
+
Log.d(
|
|
575
|
+
"CameraPreview",
|
|
576
|
+
"Final computed position (no offset): (" +
|
|
577
|
+
computedX +
|
|
578
|
+
", " +
|
|
579
|
+
computedY +
|
|
580
|
+
")"
|
|
581
|
+
);
|
|
582
|
+
Log.d("CameraPreview", "========================");
|
|
583
|
+
int computedWidth = width != 0
|
|
584
|
+
? (int) (width * pixelRatio)
|
|
585
|
+
: getBridge().getWebView().getWidth();
|
|
586
|
+
int computedHeight = height != 0
|
|
587
|
+
? (int) (height * pixelRatio)
|
|
588
|
+
: getBridge().getWebView().getHeight();
|
|
589
|
+
computedHeight -= (int) (paddingBottom * pixelRatio);
|
|
590
|
+
|
|
591
|
+
CameraSessionConfiguration config = new CameraSessionConfiguration(
|
|
592
|
+
finalDeviceId,
|
|
593
|
+
position,
|
|
594
|
+
computedX,
|
|
595
|
+
computedY,
|
|
596
|
+
computedWidth,
|
|
597
|
+
computedHeight,
|
|
598
|
+
paddingBottom,
|
|
599
|
+
toBack,
|
|
600
|
+
storeToFile,
|
|
601
|
+
enableOpacity,
|
|
602
|
+
enableZoom,
|
|
603
|
+
disableExifHeaderStripping,
|
|
604
|
+
disableAudio,
|
|
605
|
+
1.0f,
|
|
606
|
+
aspectRatio,
|
|
607
|
+
gridMode
|
|
608
|
+
);
|
|
375
609
|
config.setTargetZoom(finalTargetZoom);
|
|
376
|
-
|
|
610
|
+
|
|
377
611
|
bridge.saveCall(call);
|
|
378
612
|
cameraStartCallbackId = call.getCallbackId();
|
|
379
613
|
cameraXView.startSession(config);
|
|
380
|
-
}
|
|
381
|
-
);
|
|
614
|
+
});
|
|
382
615
|
}
|
|
383
616
|
|
|
384
617
|
@Override
|
|
385
|
-
public void onPictureTaken(String
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
618
|
+
public void onPictureTaken(String base64, JSONObject exif) {
|
|
619
|
+
PluginCall pluginCall = bridge.getSavedCall(captureCallbackId);
|
|
620
|
+
if (pluginCall == null) {
|
|
621
|
+
Log.e("CameraPreview", "onPictureTaken: captureCallbackId is null");
|
|
622
|
+
return;
|
|
623
|
+
}
|
|
624
|
+
JSObject result = new JSObject();
|
|
625
|
+
result.put("value", base64);
|
|
626
|
+
result.put("exif", exif);
|
|
627
|
+
pluginCall.resolve(result);
|
|
628
|
+
bridge.releaseCall(pluginCall);
|
|
389
629
|
}
|
|
390
630
|
|
|
391
631
|
@Override
|
|
392
632
|
public void onPictureTakenError(String message) {
|
|
393
|
-
bridge.getSavedCall(captureCallbackId)
|
|
633
|
+
PluginCall pluginCall = bridge.getSavedCall(captureCallbackId);
|
|
634
|
+
if (pluginCall == null) {
|
|
635
|
+
Log.e("CameraPreview", "onPictureTakenError: captureCallbackId is null");
|
|
636
|
+
return;
|
|
637
|
+
}
|
|
638
|
+
pluginCall.reject(message);
|
|
639
|
+
bridge.releaseCall(pluginCall);
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
@Override
|
|
643
|
+
public void onCameraStarted(int width, int height, int x, int y) {
|
|
644
|
+
PluginCall call = bridge.getSavedCall(cameraStartCallbackId);
|
|
645
|
+
if (call != null) {
|
|
646
|
+
// Convert pixel values back to logical units
|
|
647
|
+
DisplayMetrics metrics = getBridge()
|
|
648
|
+
.getActivity()
|
|
649
|
+
.getResources()
|
|
650
|
+
.getDisplayMetrics();
|
|
651
|
+
float pixelRatio = metrics.density;
|
|
652
|
+
|
|
653
|
+
JSObject result = new JSObject();
|
|
654
|
+
result.put("width", width / pixelRatio);
|
|
655
|
+
result.put("height", height / pixelRatio);
|
|
656
|
+
result.put("x", x / pixelRatio);
|
|
657
|
+
result.put("y", y / pixelRatio);
|
|
658
|
+
call.resolve(result);
|
|
659
|
+
bridge.releaseCall(call);
|
|
660
|
+
cameraStartCallbackId = null; // Prevent re-use
|
|
661
|
+
}
|
|
394
662
|
}
|
|
395
663
|
|
|
396
664
|
@Override
|
|
397
665
|
public void onSampleTaken(String result) {
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
bridge.getSavedCall(snapshotCallbackId).resolve(jsObject);
|
|
666
|
+
// Handle sample taken if needed
|
|
667
|
+
Log.i("CameraPreview", "Sample taken: " + result);
|
|
401
668
|
}
|
|
402
669
|
|
|
403
670
|
@Override
|
|
404
671
|
public void onSampleTakenError(String message) {
|
|
405
|
-
|
|
672
|
+
// Handle sample taken error if needed
|
|
673
|
+
Log.e("CameraPreview", "Sample taken error: " + message);
|
|
406
674
|
}
|
|
407
675
|
|
|
408
676
|
@Override
|
|
409
|
-
public void
|
|
410
|
-
PluginCall
|
|
411
|
-
if (
|
|
412
|
-
|
|
413
|
-
bridge.releaseCall(
|
|
677
|
+
public void onCameraStartError(String message) {
|
|
678
|
+
PluginCall call = bridge.getSavedCall(cameraStartCallbackId);
|
|
679
|
+
if (call != null) {
|
|
680
|
+
call.reject(message);
|
|
681
|
+
bridge.releaseCall(call);
|
|
682
|
+
cameraStartCallbackId = null;
|
|
414
683
|
}
|
|
415
684
|
}
|
|
416
685
|
|
|
417
|
-
@
|
|
418
|
-
public void
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
686
|
+
@PluginMethod
|
|
687
|
+
public void setAspectRatio(PluginCall call) {
|
|
688
|
+
if (cameraXView == null || !cameraXView.isRunning()) {
|
|
689
|
+
call.reject("Camera is not running");
|
|
690
|
+
return;
|
|
691
|
+
}
|
|
692
|
+
String aspectRatio = call.getString("aspectRatio", "4:3");
|
|
693
|
+
Float x = call.getFloat("x");
|
|
694
|
+
Float y = call.getFloat("y");
|
|
695
|
+
|
|
696
|
+
getActivity()
|
|
697
|
+
.runOnUiThread(() -> {
|
|
698
|
+
cameraXView.setAspectRatio(aspectRatio, x, y, () -> {
|
|
699
|
+
// Return the actual preview bounds after layout and camera operations are complete
|
|
700
|
+
int[] bounds = cameraXView.getCurrentPreviewBounds();
|
|
701
|
+
JSObject ret = new JSObject();
|
|
702
|
+
ret.put("x", bounds[0]);
|
|
703
|
+
ret.put("y", bounds[1]);
|
|
704
|
+
ret.put("width", bounds[2]);
|
|
705
|
+
ret.put("height", bounds[3]);
|
|
706
|
+
call.resolve(ret);
|
|
707
|
+
});
|
|
708
|
+
});
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
@PluginMethod
|
|
712
|
+
public void getAspectRatio(PluginCall call) {
|
|
713
|
+
if (cameraXView == null || !cameraXView.isRunning()) {
|
|
714
|
+
call.reject("Camera is not running");
|
|
715
|
+
return;
|
|
716
|
+
}
|
|
717
|
+
String aspectRatio = cameraXView.getAspectRatio();
|
|
718
|
+
JSObject ret = new JSObject();
|
|
719
|
+
ret.put("aspectRatio", aspectRatio);
|
|
720
|
+
call.resolve(ret);
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
@PluginMethod
|
|
724
|
+
public void setGridMode(PluginCall call) {
|
|
725
|
+
if (cameraXView == null || !cameraXView.isRunning()) {
|
|
726
|
+
call.reject("Camera is not running");
|
|
727
|
+
return;
|
|
728
|
+
}
|
|
729
|
+
String gridMode = call.getString("gridMode", "none");
|
|
730
|
+
getActivity()
|
|
731
|
+
.runOnUiThread(() -> {
|
|
732
|
+
cameraXView.setGridMode(gridMode);
|
|
733
|
+
call.resolve();
|
|
734
|
+
});
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
@PluginMethod
|
|
738
|
+
public void getGridMode(PluginCall call) {
|
|
739
|
+
if (cameraXView == null || !cameraXView.isRunning()) {
|
|
740
|
+
call.reject("Camera is not running");
|
|
741
|
+
return;
|
|
742
|
+
}
|
|
743
|
+
JSObject ret = new JSObject();
|
|
744
|
+
ret.put("gridMode", cameraXView.getGridMode());
|
|
745
|
+
call.resolve(ret);
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
@PluginMethod
|
|
749
|
+
public void getPreviewSize(PluginCall call) {
|
|
750
|
+
if (cameraXView == null || !cameraXView.isRunning()) {
|
|
751
|
+
call.reject("Camera is not running");
|
|
752
|
+
return;
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
// Convert pixel values back to logical units
|
|
756
|
+
DisplayMetrics metrics = getBridge()
|
|
757
|
+
.getActivity()
|
|
758
|
+
.getResources()
|
|
759
|
+
.getDisplayMetrics();
|
|
760
|
+
float pixelRatio = metrics.density;
|
|
761
|
+
|
|
762
|
+
JSObject ret = new JSObject();
|
|
763
|
+
ret.put("x", cameraXView.getPreviewX() / pixelRatio);
|
|
764
|
+
ret.put("y", cameraXView.getPreviewY() / pixelRatio);
|
|
765
|
+
ret.put("width", cameraXView.getPreviewWidth() / pixelRatio);
|
|
766
|
+
ret.put("height", cameraXView.getPreviewHeight() / pixelRatio);
|
|
767
|
+
call.resolve(ret);
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
@PluginMethod
|
|
771
|
+
public void setPreviewSize(PluginCall call) {
|
|
772
|
+
if (cameraXView == null || !cameraXView.isRunning()) {
|
|
773
|
+
call.reject("Camera is not running");
|
|
774
|
+
return;
|
|
423
775
|
}
|
|
776
|
+
|
|
777
|
+
// Get values from call - null values will become 0
|
|
778
|
+
Integer xParam = call.getInt("x");
|
|
779
|
+
Integer yParam = call.getInt("y");
|
|
780
|
+
Integer widthParam = call.getInt("width");
|
|
781
|
+
Integer heightParam = call.getInt("height");
|
|
782
|
+
|
|
783
|
+
// Apply pixel ratio conversion to non-null values
|
|
784
|
+
DisplayMetrics metrics = getBridge()
|
|
785
|
+
.getActivity()
|
|
786
|
+
.getResources()
|
|
787
|
+
.getDisplayMetrics();
|
|
788
|
+
float pixelRatio = metrics.density;
|
|
789
|
+
|
|
790
|
+
int x = (xParam != null && xParam > 0) ? (int) (xParam * pixelRatio) : 0;
|
|
791
|
+
int y = (yParam != null && yParam > 0) ? (int) (yParam * pixelRatio) : 0;
|
|
792
|
+
int width = (widthParam != null && widthParam > 0)
|
|
793
|
+
? (int) (widthParam * pixelRatio)
|
|
794
|
+
: 0;
|
|
795
|
+
int height = (heightParam != null && heightParam > 0)
|
|
796
|
+
? (int) (heightParam * pixelRatio)
|
|
797
|
+
: 0;
|
|
798
|
+
|
|
799
|
+
cameraXView.setPreviewSize(x, y, width, height, () -> {
|
|
800
|
+
// Return the actual preview bounds after layout operations are complete
|
|
801
|
+
int[] bounds = cameraXView.getCurrentPreviewBounds();
|
|
802
|
+
JSObject ret = new JSObject();
|
|
803
|
+
ret.put("x", bounds[0]);
|
|
804
|
+
ret.put("y", bounds[1]);
|
|
805
|
+
ret.put("width", bounds[2]);
|
|
806
|
+
ret.put("height", bounds[3]);
|
|
807
|
+
call.resolve(ret);
|
|
808
|
+
});
|
|
424
809
|
}
|
|
425
810
|
}
|