@capgo/camera-preview 7.4.0-alpha.13 → 7.4.0-alpha.18
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 +118 -15
- package/android/src/main/java/com/ahm/capacitor/camera/preview/CameraPreview.java +223 -0
- package/dist/docs.json +275 -16
- package/dist/esm/definitions.d.ts +90 -11
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/web.d.ts +8 -1
- package/dist/esm/web.js +64 -0
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +64 -0
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +64 -0
- package/dist/plugin.js.map +1 -1
- package/ios/Sources/CapgoCameraPreviewPlugin/CameraController.swift +15 -3
- package/ios/Sources/CapgoCameraPreviewPlugin/Plugin.swift +32 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -262,6 +262,10 @@ Documentation for the [uploader](https://github.com/Cap-go/capacitor-uploader)
|
|
|
262
262
|
* [`setPreviewSize(...)`](#setpreviewsize)
|
|
263
263
|
* [`setFocus(...)`](#setfocus)
|
|
264
264
|
* [`addListener('screenResize', ...)`](#addlistenerscreenresize-)
|
|
265
|
+
* [`addListener('orientationChange', ...)`](#addlistenerorientationchange-)
|
|
266
|
+
* [`deleteFile(...)`](#deletefile)
|
|
267
|
+
* [`getSafeAreaInsets()`](#getsafeareainsets)
|
|
268
|
+
* [`getOrientation()`](#getorientation)
|
|
265
269
|
* [Interfaces](#interfaces)
|
|
266
270
|
* [Type Aliases](#type-aliases)
|
|
267
271
|
* [Enums](#enums)
|
|
@@ -372,7 +376,7 @@ Set the aspect ratio of the camera preview.
|
|
|
372
376
|
|
|
373
377
|
**Returns:** <code>Promise<{ width: number; height: number; x: number; y: number; }></code>
|
|
374
378
|
|
|
375
|
-
**Since:** 7.
|
|
379
|
+
**Since:** 7.5.0
|
|
376
380
|
|
|
377
381
|
--------------------
|
|
378
382
|
|
|
@@ -387,7 +391,7 @@ Gets the current aspect ratio of the camera preview.
|
|
|
387
391
|
|
|
388
392
|
**Returns:** <code>Promise<{ aspectRatio: '4:3' | '16:9'; }></code>
|
|
389
393
|
|
|
390
|
-
**Since:** 7.
|
|
394
|
+
**Since:** 7.5.0
|
|
391
395
|
|
|
392
396
|
--------------------
|
|
393
397
|
|
|
@@ -544,7 +548,7 @@ Checks if the camera preview is currently running.
|
|
|
544
548
|
|
|
545
549
|
**Returns:** <code>Promise<{ isRunning: boolean; }></code>
|
|
546
550
|
|
|
547
|
-
**Since:** 7.
|
|
551
|
+
**Since:** 7.5.0
|
|
548
552
|
|
|
549
553
|
--------------------
|
|
550
554
|
|
|
@@ -559,7 +563,7 @@ Gets all available camera devices.
|
|
|
559
563
|
|
|
560
564
|
**Returns:** <code>Promise<{ devices: CameraDevice[]; }></code>
|
|
561
565
|
|
|
562
|
-
**Since:** 7.
|
|
566
|
+
**Since:** 7.5.0
|
|
563
567
|
|
|
564
568
|
--------------------
|
|
565
569
|
|
|
@@ -574,7 +578,7 @@ Gets the current zoom state, including min/max and current lens info.
|
|
|
574
578
|
|
|
575
579
|
**Returns:** <code>Promise<{ min: number; max: number; current: number; lens: <a href="#lensinfo">LensInfo</a>; }></code>
|
|
576
580
|
|
|
577
|
-
**Since:** 7.
|
|
581
|
+
**Since:** 7.5.0
|
|
578
582
|
|
|
579
583
|
--------------------
|
|
580
584
|
|
|
@@ -591,6 +595,8 @@ Returns zoom button values for quick switching.
|
|
|
591
595
|
|
|
592
596
|
**Returns:** <code>Promise<{ values: number[]; }></code>
|
|
593
597
|
|
|
598
|
+
**Since:** 7.5.0
|
|
599
|
+
|
|
594
600
|
--------------------
|
|
595
601
|
|
|
596
602
|
|
|
@@ -606,7 +612,7 @@ Sets the zoom level of the camera.
|
|
|
606
612
|
| ------------- | -------------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
|
|
607
613
|
| **`options`** | <code>{ level: number; ramp?: boolean; autoFocus?: boolean; }</code> | - The desired zoom level. `ramp` is currently unused. `autoFocus` defaults to true. |
|
|
608
614
|
|
|
609
|
-
**Since:** 7.
|
|
615
|
+
**Since:** 7.5.0
|
|
610
616
|
|
|
611
617
|
--------------------
|
|
612
618
|
|
|
@@ -621,7 +627,7 @@ Gets the current flash mode.
|
|
|
621
627
|
|
|
622
628
|
**Returns:** <code>Promise<{ flashMode: <a href="#camerapreviewflashmode">CameraPreviewFlashMode</a>; }></code>
|
|
623
629
|
|
|
624
|
-
**Since:** 7.
|
|
630
|
+
**Since:** 7.5.0
|
|
625
631
|
|
|
626
632
|
--------------------
|
|
627
633
|
|
|
@@ -634,7 +640,7 @@ removeAllListeners() => Promise<void>
|
|
|
634
640
|
|
|
635
641
|
Removes all registered listeners.
|
|
636
642
|
|
|
637
|
-
**Since:** 7.
|
|
643
|
+
**Since:** 7.5.0
|
|
638
644
|
|
|
639
645
|
--------------------
|
|
640
646
|
|
|
@@ -651,7 +657,7 @@ Switches the active camera to the one with the specified `deviceId`.
|
|
|
651
657
|
| ------------- | ---------------------------------- | ------------------------------------ |
|
|
652
658
|
| **`options`** | <code>{ deviceId: string; }</code> | - The ID of the device to switch to. |
|
|
653
659
|
|
|
654
|
-
**Since:** 7.
|
|
660
|
+
**Since:** 7.5.0
|
|
655
661
|
|
|
656
662
|
--------------------
|
|
657
663
|
|
|
@@ -666,7 +672,7 @@ Gets the ID of the currently active camera device.
|
|
|
666
672
|
|
|
667
673
|
**Returns:** <code>Promise<{ deviceId: string; }></code>
|
|
668
674
|
|
|
669
|
-
**Since:** 7.
|
|
675
|
+
**Since:** 7.5.0
|
|
670
676
|
|
|
671
677
|
--------------------
|
|
672
678
|
|
|
@@ -681,6 +687,8 @@ Gets the current preview size and position.
|
|
|
681
687
|
|
|
682
688
|
**Returns:** <code>Promise<{ x: number; y: number; width: number; height: number; }></code>
|
|
683
689
|
|
|
690
|
+
**Since:** 7.5.0
|
|
691
|
+
|
|
684
692
|
--------------------
|
|
685
693
|
|
|
686
694
|
|
|
@@ -698,6 +706,8 @@ Sets the preview size and position.
|
|
|
698
706
|
|
|
699
707
|
**Returns:** <code>Promise<{ width: number; height: number; x: number; y: number; }></code>
|
|
700
708
|
|
|
709
|
+
**Since:** 7.5.0
|
|
710
|
+
|
|
701
711
|
--------------------
|
|
702
712
|
|
|
703
713
|
|
|
@@ -713,7 +723,7 @@ Sets the camera focus to a specific point in the preview.
|
|
|
713
723
|
| ------------- | -------------------------------------- | -------------------- |
|
|
714
724
|
| **`options`** | <code>{ x: number; y: number; }</code> | - The focus options. |
|
|
715
725
|
|
|
716
|
-
**Since:**
|
|
726
|
+
**Since:** 7.5.0
|
|
717
727
|
|
|
718
728
|
--------------------
|
|
719
729
|
|
|
@@ -724,13 +734,87 @@ Sets the camera focus to a specific point in the preview.
|
|
|
724
734
|
addListener(eventName: "screenResize", listenerFunc: (data: { width: number; height: number; x: number; y: number; }) => void) => Promise<PluginListenerHandle>
|
|
725
735
|
```
|
|
726
736
|
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
|
730
|
-
|
|
|
737
|
+
Adds a listener for screen resize events.
|
|
738
|
+
|
|
739
|
+
| Param | Type | Description |
|
|
740
|
+
| ------------------ | ---------------------------------------------------------------------------------------- | --------------------------------------------------- |
|
|
741
|
+
| **`eventName`** | <code>'screenResize'</code> | - The event name to listen for. |
|
|
742
|
+
| **`listenerFunc`** | <code>(data: { width: number; height: number; x: number; y: number; }) => void</code> | - The function to call when the event is triggered. |
|
|
731
743
|
|
|
732
744
|
**Returns:** <code>Promise<<a href="#pluginlistenerhandle">PluginListenerHandle</a>></code>
|
|
733
745
|
|
|
746
|
+
**Since:** 7.5.0
|
|
747
|
+
|
|
748
|
+
--------------------
|
|
749
|
+
|
|
750
|
+
|
|
751
|
+
### addListener('orientationChange', ...)
|
|
752
|
+
|
|
753
|
+
```typescript
|
|
754
|
+
addListener(eventName: "orientationChange", listenerFunc: (data: { orientation: DeviceOrientation; }) => void) => Promise<PluginListenerHandle>
|
|
755
|
+
```
|
|
756
|
+
|
|
757
|
+
Adds a listener for orientation change events.
|
|
758
|
+
|
|
759
|
+
| Param | Type | Description |
|
|
760
|
+
| ------------------ | ---------------------------------------------------------------------------------------------------- | --------------------------------------------------- |
|
|
761
|
+
| **`eventName`** | <code>'orientationChange'</code> | - The event name to listen for. |
|
|
762
|
+
| **`listenerFunc`** | <code>(data: { orientation: <a href="#deviceorientation">DeviceOrientation</a>; }) => void</code> | - The function to call when the event is triggered. |
|
|
763
|
+
|
|
764
|
+
**Returns:** <code>Promise<<a href="#pluginlistenerhandle">PluginListenerHandle</a>></code>
|
|
765
|
+
|
|
766
|
+
**Since:** 7.5.0
|
|
767
|
+
|
|
768
|
+
--------------------
|
|
769
|
+
|
|
770
|
+
|
|
771
|
+
### deleteFile(...)
|
|
772
|
+
|
|
773
|
+
```typescript
|
|
774
|
+
deleteFile(options: { path: string; }) => Promise<{ success: boolean; }>
|
|
775
|
+
```
|
|
776
|
+
|
|
777
|
+
Deletes a file at the given absolute path on the device.
|
|
778
|
+
Use this to quickly clean up temporary images created with `storeToFile`.
|
|
779
|
+
On web, this is not supported and will throw.
|
|
780
|
+
|
|
781
|
+
| Param | Type |
|
|
782
|
+
| ------------- | ------------------------------ |
|
|
783
|
+
| **`options`** | <code>{ path: string; }</code> |
|
|
784
|
+
|
|
785
|
+
**Returns:** <code>Promise<{ success: boolean; }></code>
|
|
786
|
+
|
|
787
|
+
**Since:** 7.5.0
|
|
788
|
+
|
|
789
|
+
--------------------
|
|
790
|
+
|
|
791
|
+
|
|
792
|
+
### getSafeAreaInsets()
|
|
793
|
+
|
|
794
|
+
```typescript
|
|
795
|
+
getSafeAreaInsets() => Promise<SafeAreaInsets>
|
|
796
|
+
```
|
|
797
|
+
|
|
798
|
+
Gets the safe area insets for Android devices.
|
|
799
|
+
Returns the top and bottom insets in dp and the current orientation.
|
|
800
|
+
|
|
801
|
+
**Returns:** <code>Promise<<a href="#safeareainsets">SafeAreaInsets</a>></code>
|
|
802
|
+
|
|
803
|
+
--------------------
|
|
804
|
+
|
|
805
|
+
|
|
806
|
+
### getOrientation()
|
|
807
|
+
|
|
808
|
+
```typescript
|
|
809
|
+
getOrientation() => Promise<{ orientation: DeviceOrientation; }>
|
|
810
|
+
```
|
|
811
|
+
|
|
812
|
+
Gets the current device orientation in a cross-platform format.
|
|
813
|
+
|
|
814
|
+
**Returns:** <code>Promise<{ orientation: <a href="#deviceorientation">DeviceOrientation</a>; }></code>
|
|
815
|
+
|
|
816
|
+
**Since:** 7.5.0
|
|
817
|
+
|
|
734
818
|
--------------------
|
|
735
819
|
|
|
736
820
|
|
|
@@ -874,6 +958,18 @@ Represents the detailed information of the currently active lens.
|
|
|
874
958
|
| **`remove`** | <code>() => Promise<void></code> |
|
|
875
959
|
|
|
876
960
|
|
|
961
|
+
#### SafeAreaInsets
|
|
962
|
+
|
|
963
|
+
Represents safe area insets on Android.
|
|
964
|
+
Values are expressed in logical pixels (dp) to match JS layout units.
|
|
965
|
+
|
|
966
|
+
| Prop | Type | Description |
|
|
967
|
+
| ----------------- | ------------------- | ---------------------------------------------------------------- |
|
|
968
|
+
| **`orientation`** | <code>number</code> | Current device orientation as reported by Android configuration. |
|
|
969
|
+
| **`top`** | <code>number</code> | Top inset (e.g., status bar or cutout) in dp. |
|
|
970
|
+
| **`bottom`** | <code>number</code> | Bottom inset (e.g., navigation bar) in dp. |
|
|
971
|
+
|
|
972
|
+
|
|
877
973
|
### Type Aliases
|
|
878
974
|
|
|
879
975
|
|
|
@@ -910,6 +1006,13 @@ The available flash modes for the camera.
|
|
|
910
1006
|
<code><a href="#camerapreviewflashmode">CameraPreviewFlashMode</a></code>
|
|
911
1007
|
|
|
912
1008
|
|
|
1009
|
+
#### DeviceOrientation
|
|
1010
|
+
|
|
1011
|
+
Canonical device orientation values across platforms.
|
|
1012
|
+
|
|
1013
|
+
<code>"portrait" | "landscape" | "landscape-left" | "landscape-right" | "portrait-upside-down" | "unknown"</code>
|
|
1014
|
+
|
|
1015
|
+
|
|
913
1016
|
### Enums
|
|
914
1017
|
|
|
915
1018
|
|
|
@@ -5,13 +5,18 @@ import static android.Manifest.permission.RECORD_AUDIO;
|
|
|
5
5
|
|
|
6
6
|
import android.Manifest;
|
|
7
7
|
import android.content.pm.ActivityInfo;
|
|
8
|
+
import android.content.res.Configuration;
|
|
8
9
|
import android.location.Location;
|
|
9
10
|
import android.util.DisplayMetrics;
|
|
10
11
|
import android.util.Log;
|
|
11
12
|
import android.util.Size;
|
|
13
|
+
import android.view.OrientationEventListener;
|
|
12
14
|
import android.view.View;
|
|
13
15
|
import android.view.ViewGroup;
|
|
14
16
|
import android.webkit.WebView;
|
|
17
|
+
import androidx.core.graphics.Insets;
|
|
18
|
+
import androidx.core.view.ViewCompat;
|
|
19
|
+
import androidx.core.view.WindowInsetsCompat;
|
|
15
20
|
import com.ahm.capacitor.camera.preview.model.CameraDevice;
|
|
16
21
|
import com.ahm.capacitor.camera.preview.model.CameraSessionConfiguration;
|
|
17
22
|
import com.ahm.capacitor.camera.preview.model.LensInfo;
|
|
@@ -69,6 +74,28 @@ public class CameraPreview
|
|
|
69
74
|
private CameraXView cameraXView;
|
|
70
75
|
private FusedLocationProviderClient fusedLocationClient;
|
|
71
76
|
private Location lastLocation;
|
|
77
|
+
private OrientationEventListener orientationListener;
|
|
78
|
+
private int lastOrientation = Configuration.ORIENTATION_UNDEFINED;
|
|
79
|
+
|
|
80
|
+
@PluginMethod
|
|
81
|
+
public void getOrientation(PluginCall call) {
|
|
82
|
+
int orientation = getContext()
|
|
83
|
+
.getResources()
|
|
84
|
+
.getConfiguration()
|
|
85
|
+
.orientation;
|
|
86
|
+
String o;
|
|
87
|
+
if (orientation == Configuration.ORIENTATION_PORTRAIT) {
|
|
88
|
+
// We don't distinguish upside-down reliably on Android, report generic portrait
|
|
89
|
+
o = "portrait";
|
|
90
|
+
} else if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
|
91
|
+
o = "landscape";
|
|
92
|
+
} else {
|
|
93
|
+
o = "unknown";
|
|
94
|
+
}
|
|
95
|
+
JSObject ret = new JSObject();
|
|
96
|
+
ret.put("orientation", o);
|
|
97
|
+
call.resolve(ret);
|
|
98
|
+
}
|
|
72
99
|
|
|
73
100
|
@PluginMethod
|
|
74
101
|
public void start(PluginCall call) {
|
|
@@ -205,6 +232,13 @@ public class CameraPreview
|
|
|
205
232
|
.getActivity()
|
|
206
233
|
.setRequestedOrientation(previousOrientationRequest);
|
|
207
234
|
|
|
235
|
+
// Disable and clear orientation listener
|
|
236
|
+
if (orientationListener != null) {
|
|
237
|
+
orientationListener.disable();
|
|
238
|
+
orientationListener = null;
|
|
239
|
+
lastOrientation = Configuration.ORIENTATION_UNDEFINED;
|
|
240
|
+
}
|
|
241
|
+
|
|
208
242
|
if (cameraXView != null && cameraXView.isRunning()) {
|
|
209
243
|
cameraXView.stopSession();
|
|
210
244
|
cameraXView = null;
|
|
@@ -215,6 +249,10 @@ public class CameraPreview
|
|
|
215
249
|
|
|
216
250
|
@PluginMethod
|
|
217
251
|
public void getSupportedFlashModes(PluginCall call) {
|
|
252
|
+
if (cameraXView == null || !cameraXView.isRunning()) {
|
|
253
|
+
call.reject("Camera is not running");
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
218
256
|
List<String> supportedFlashModes = cameraXView.getSupportedFlashModes();
|
|
219
257
|
JSArray jsonFlashModes = new JSArray();
|
|
220
258
|
for (String mode : supportedFlashModes) {
|
|
@@ -268,6 +306,10 @@ public class CameraPreview
|
|
|
268
306
|
|
|
269
307
|
@PluginMethod
|
|
270
308
|
public void getZoom(PluginCall call) {
|
|
309
|
+
if (cameraXView == null || !cameraXView.isRunning()) {
|
|
310
|
+
call.reject("Camera is not running");
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
271
313
|
ZoomFactors zoomFactors = cameraXView.getZoomFactors();
|
|
272
314
|
JSObject result = new JSObject();
|
|
273
315
|
result.put("min", zoomFactors.getMin());
|
|
@@ -278,6 +320,10 @@ public class CameraPreview
|
|
|
278
320
|
|
|
279
321
|
@PluginMethod
|
|
280
322
|
public void getZoomButtonValues(PluginCall call) {
|
|
323
|
+
if (cameraXView == null || !cameraXView.isRunning()) {
|
|
324
|
+
call.reject("Camera is not running");
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
281
327
|
// Build a sorted set to dedupe and order ascending
|
|
282
328
|
java.util.Set<Double> sorted = new java.util.TreeSet<>();
|
|
283
329
|
sorted.add(1.0);
|
|
@@ -968,6 +1014,67 @@ public class CameraPreview
|
|
|
968
1014
|
bridge.saveCall(call);
|
|
969
1015
|
cameraStartCallbackId = call.getCallbackId();
|
|
970
1016
|
cameraXView.startSession(config);
|
|
1017
|
+
|
|
1018
|
+
// Setup orientation listener to mirror iOS screenResize emission
|
|
1019
|
+
if (orientationListener == null) {
|
|
1020
|
+
lastOrientation = getContext()
|
|
1021
|
+
.getResources()
|
|
1022
|
+
.getConfiguration()
|
|
1023
|
+
.orientation;
|
|
1024
|
+
orientationListener = new OrientationEventListener(getContext()) {
|
|
1025
|
+
@Override
|
|
1026
|
+
public void onOrientationChanged(int orientation) {
|
|
1027
|
+
if (orientation == ORIENTATION_UNKNOWN) return;
|
|
1028
|
+
int current = getContext()
|
|
1029
|
+
.getResources()
|
|
1030
|
+
.getConfiguration()
|
|
1031
|
+
.orientation;
|
|
1032
|
+
if (current != lastOrientation) {
|
|
1033
|
+
lastOrientation = current;
|
|
1034
|
+
handleOrientationChange();
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
};
|
|
1038
|
+
if (orientationListener.canDetectOrientation()) {
|
|
1039
|
+
orientationListener.enable();
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
});
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
private void handleOrientationChange() {
|
|
1046
|
+
if (cameraXView == null || !cameraXView.isRunning()) return;
|
|
1047
|
+
getBridge()
|
|
1048
|
+
.getActivity()
|
|
1049
|
+
.runOnUiThread(() -> {
|
|
1050
|
+
// Reapply current aspect ratio to recompute layout, then emit screenResize
|
|
1051
|
+
String ar = cameraXView.getAspectRatio();
|
|
1052
|
+
cameraXView.setAspectRatio(ar, null, null, () -> {
|
|
1053
|
+
int[] bounds = cameraXView.getCurrentPreviewBounds();
|
|
1054
|
+
JSObject data = new JSObject();
|
|
1055
|
+
data.put("x", bounds[0]);
|
|
1056
|
+
data.put("y", bounds[1]);
|
|
1057
|
+
data.put("width", bounds[2]);
|
|
1058
|
+
data.put("height", bounds[3]);
|
|
1059
|
+
notifyListeners("screenResize", data);
|
|
1060
|
+
|
|
1061
|
+
// Also emit orientationChange with a unified string value
|
|
1062
|
+
int current = getContext()
|
|
1063
|
+
.getResources()
|
|
1064
|
+
.getConfiguration()
|
|
1065
|
+
.orientation;
|
|
1066
|
+
String o;
|
|
1067
|
+
if (current == Configuration.ORIENTATION_PORTRAIT) {
|
|
1068
|
+
o = "portrait";
|
|
1069
|
+
} else if (current == Configuration.ORIENTATION_LANDSCAPE) {
|
|
1070
|
+
o = "landscape";
|
|
1071
|
+
} else {
|
|
1072
|
+
o = "unknown";
|
|
1073
|
+
}
|
|
1074
|
+
JSObject oData = new JSObject();
|
|
1075
|
+
oData.put("orientation", o);
|
|
1076
|
+
notifyListeners("orientationChange", oData);
|
|
1077
|
+
});
|
|
971
1078
|
});
|
|
972
1079
|
}
|
|
973
1080
|
|
|
@@ -1255,4 +1362,120 @@ public class CameraPreview
|
|
|
1255
1362
|
call.reject("Failed to delete file: " + e.getMessage());
|
|
1256
1363
|
}
|
|
1257
1364
|
}
|
|
1365
|
+
|
|
1366
|
+
@PluginMethod
|
|
1367
|
+
public void getSafeAreaInsets(PluginCall call) {
|
|
1368
|
+
JSObject ret = new JSObject();
|
|
1369
|
+
int orientation = getContext()
|
|
1370
|
+
.getResources()
|
|
1371
|
+
.getConfiguration()
|
|
1372
|
+
.orientation;
|
|
1373
|
+
|
|
1374
|
+
int topPx = 0;
|
|
1375
|
+
int bottomPx = 0;
|
|
1376
|
+
try {
|
|
1377
|
+
View webView = getBridge().getWebView();
|
|
1378
|
+
if (webView != null) {
|
|
1379
|
+
DisplayMetrics metrics = getBridge()
|
|
1380
|
+
.getActivity()
|
|
1381
|
+
.getResources()
|
|
1382
|
+
.getDisplayMetrics();
|
|
1383
|
+
int screenHeight = metrics.heightPixels;
|
|
1384
|
+
int[] location = new int[2];
|
|
1385
|
+
webView.getLocationOnScreen(location);
|
|
1386
|
+
int webViewTop = location[1];
|
|
1387
|
+
int webViewBottom = webViewTop + webView.getHeight();
|
|
1388
|
+
int webViewBottomGap = Math.max(0, screenHeight - webViewBottom);
|
|
1389
|
+
|
|
1390
|
+
// System insets (status/navigation/cutout)
|
|
1391
|
+
int systemTop = 0;
|
|
1392
|
+
int systemBottom = 0;
|
|
1393
|
+
View decorView = getBridge().getActivity().getWindow().getDecorView();
|
|
1394
|
+
WindowInsetsCompat insets = ViewCompat.getRootWindowInsets(decorView);
|
|
1395
|
+
if (insets != null) {
|
|
1396
|
+
Insets sysBars = insets.getInsets(
|
|
1397
|
+
WindowInsetsCompat.Type.systemBars()
|
|
1398
|
+
);
|
|
1399
|
+
Insets cutout = insets.getInsets(
|
|
1400
|
+
WindowInsetsCompat.Type.displayCutout()
|
|
1401
|
+
);
|
|
1402
|
+
systemTop = Math.max(sysBars.top, cutout.top);
|
|
1403
|
+
systemBottom = Math.max(sysBars.bottom, cutout.bottom);
|
|
1404
|
+
} else {
|
|
1405
|
+
systemTop = getStatusBarHeightPx();
|
|
1406
|
+
systemBottom = getNavigationBarHeightPx();
|
|
1407
|
+
}
|
|
1408
|
+
|
|
1409
|
+
// Top: report the gap between screen and WebView (useful when not edge-to-edge)
|
|
1410
|
+
topPx = Math.max(0, webViewTop);
|
|
1411
|
+
|
|
1412
|
+
// Bottom logic:
|
|
1413
|
+
// - If WebView has a bottom gap equal to the system nav bar height (3-button mode),
|
|
1414
|
+
// it means layout already accounts for it -> return 0 as requested.
|
|
1415
|
+
// - If WebView has no gap (edge-to-edge or overlay), return system bottom inset.
|
|
1416
|
+
// - Otherwise, default to system bottom inset (avoid counting app UI like tab bars).
|
|
1417
|
+
if (
|
|
1418
|
+
webViewBottomGap > 0 && approxEqualPx(webViewBottomGap, systemBottom)
|
|
1419
|
+
) {
|
|
1420
|
+
bottomPx = 0; // already offset by system nav bar
|
|
1421
|
+
} else if (webViewBottomGap == 0) {
|
|
1422
|
+
bottomPx = systemBottom;
|
|
1423
|
+
} else {
|
|
1424
|
+
bottomPx = systemBottom;
|
|
1425
|
+
}
|
|
1426
|
+
} else {
|
|
1427
|
+
// Fallback if WebView is unavailable
|
|
1428
|
+
View decorView = getBridge().getActivity().getWindow().getDecorView();
|
|
1429
|
+
WindowInsetsCompat insets = ViewCompat.getRootWindowInsets(decorView);
|
|
1430
|
+
if (insets != null) {
|
|
1431
|
+
Insets sysBars = insets.getInsets(
|
|
1432
|
+
WindowInsetsCompat.Type.systemBars()
|
|
1433
|
+
);
|
|
1434
|
+
Insets cutout = insets.getInsets(
|
|
1435
|
+
WindowInsetsCompat.Type.displayCutout()
|
|
1436
|
+
);
|
|
1437
|
+
topPx = Math.max(sysBars.top, cutout.top);
|
|
1438
|
+
bottomPx = Math.max(sysBars.bottom, cutout.bottom);
|
|
1439
|
+
} else {
|
|
1440
|
+
topPx = getStatusBarHeightPx();
|
|
1441
|
+
bottomPx = getNavigationBarHeightPx();
|
|
1442
|
+
}
|
|
1443
|
+
}
|
|
1444
|
+
} catch (Exception e) {
|
|
1445
|
+
topPx = getStatusBarHeightPx();
|
|
1446
|
+
bottomPx = getNavigationBarHeightPx();
|
|
1447
|
+
}
|
|
1448
|
+
|
|
1449
|
+
float density = getContext().getResources().getDisplayMetrics().density;
|
|
1450
|
+
ret.put("orientation", orientation);
|
|
1451
|
+
ret.put("top", topPx / density);
|
|
1452
|
+
ret.put("bottom", bottomPx / density);
|
|
1453
|
+
call.resolve(ret);
|
|
1454
|
+
}
|
|
1455
|
+
|
|
1456
|
+
private boolean approxEqualPx(int a, int b) {
|
|
1457
|
+
return Math.abs(a - b) <= 2; // within 2px tolerance
|
|
1458
|
+
}
|
|
1459
|
+
|
|
1460
|
+
private int getStatusBarHeightPx() {
|
|
1461
|
+
int result = 0;
|
|
1462
|
+
int resourceId = getContext()
|
|
1463
|
+
.getResources()
|
|
1464
|
+
.getIdentifier("status_bar_height", "dimen", "android");
|
|
1465
|
+
if (resourceId > 0) {
|
|
1466
|
+
result = getContext().getResources().getDimensionPixelSize(resourceId);
|
|
1467
|
+
}
|
|
1468
|
+
return result;
|
|
1469
|
+
}
|
|
1470
|
+
|
|
1471
|
+
private int getNavigationBarHeightPx() {
|
|
1472
|
+
int result = 0;
|
|
1473
|
+
int resourceId = getContext()
|
|
1474
|
+
.getResources()
|
|
1475
|
+
.getIdentifier("navigation_bar_height", "dimen", "android");
|
|
1476
|
+
if (resourceId > 0) {
|
|
1477
|
+
result = getContext().getResources().getDimensionPixelSize(resourceId);
|
|
1478
|
+
}
|
|
1479
|
+
return result;
|
|
1480
|
+
}
|
|
1258
1481
|
}
|