@capgo/capacitor-screen-orientation 8.1.21 → 8.2.0

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.
@@ -0,0 +1,176 @@
1
+ package ee.forgr.capacitor.screenorientation;
2
+
3
+ import android.app.Activity;
4
+ import android.content.pm.PackageManager;
5
+ import android.graphics.Rect;
6
+ import android.os.Build;
7
+ import android.view.View;
8
+ import androidx.core.util.Consumer;
9
+ import androidx.window.java.layout.WindowInfoTrackerCallbackAdapter;
10
+ import androidx.window.layout.DisplayFeature;
11
+ import androidx.window.layout.FoldingFeature;
12
+ import androidx.window.layout.SupportedPosture;
13
+ import androidx.window.layout.WindowInfoTracker;
14
+ import androidx.window.layout.WindowLayoutInfo;
15
+ import androidx.window.layout.WindowMetricsCalculator;
16
+ import com.getcapacitor.JSObject;
17
+ import java.util.concurrent.Executor;
18
+
19
+ /**
20
+ * Reads Jetpack WindowManager fold state for the current activity.
21
+ * The hinge sensor itself stays in the plugin so it can run only while a listener is registered.
22
+ */
23
+ final class FoldLayout implements Consumer<WindowLayoutInfo> {
24
+
25
+ interface Callback {
26
+ void onFoldState(JSObject state);
27
+ }
28
+
29
+ private final Activity activity;
30
+ private final View webView;
31
+ private final WindowInfoTrackerCallbackAdapter adapter;
32
+ private final Executor executor;
33
+ private final Callback callback;
34
+ private final boolean supportsTabletop;
35
+ private JSObject current = flatState();
36
+ private boolean sawFold = false;
37
+
38
+ FoldLayout(Activity activity, View webView, Executor executor, Callback callback) {
39
+ this.activity = activity;
40
+ this.webView = webView;
41
+ this.executor = executor;
42
+ this.callback = callback;
43
+ WindowInfoTracker tracker = WindowInfoTracker.getOrCreate(activity);
44
+ this.adapter = new WindowInfoTrackerCallbackAdapter(tracker);
45
+ this.supportsTabletop = supportsTabletop(tracker);
46
+ this.current = toFoldState(firstFold());
47
+ this.adapter.addWindowLayoutInfoListener(activity, executor, this);
48
+ }
49
+
50
+ private FoldingFeature firstFold() {
51
+ WindowLayoutInfo info;
52
+ try {
53
+ info = adapter.getCurrentWindowLayoutInfo(activity);
54
+ } catch (UnsupportedOperationException ignored) {
55
+ return null;
56
+ }
57
+ for (DisplayFeature feature : info.getDisplayFeatures()) {
58
+ if (feature instanceof FoldingFeature) {
59
+ sawFold = true;
60
+ return (FoldingFeature) feature;
61
+ }
62
+ }
63
+ return null;
64
+ }
65
+
66
+ void stop() {
67
+ adapter.removeWindowLayoutInfoListener(this);
68
+ }
69
+
70
+ JSObject currentState() {
71
+ return current;
72
+ }
73
+
74
+ boolean isFoldable() {
75
+ if (sawFold || supportsTabletop) {
76
+ return true;
77
+ }
78
+ return (
79
+ Build.VERSION.SDK_INT >= Build.VERSION_CODES.R &&
80
+ activity.getPackageManager().hasSystemFeature(PackageManager.FEATURE_SENSOR_HINGE_ANGLE)
81
+ );
82
+ }
83
+
84
+ boolean supportsTabletop() {
85
+ return supportsTabletop;
86
+ }
87
+
88
+ JSObject sizeClass() {
89
+ Rect bounds = WindowMetricsCalculator.getOrCreate().computeCurrentWindowMetrics(activity).getBounds();
90
+ float density = activity.getResources().getDisplayMetrics().density;
91
+ return sizeClassOf(bounds.width() / density, bounds.height() / density);
92
+ }
93
+
94
+ static JSObject sizeClassOf(float widthDp, float heightDp) {
95
+ JSObject result = new JSObject();
96
+ result.put("horizontal", widthDp >= 600f ? "regular" : "compact");
97
+ result.put("vertical", heightDp >= 480f ? "regular" : "compact");
98
+ result.put("widthClass", widthClass(widthDp));
99
+ result.put("heightClass", heightDp >= 900f ? "expanded" : heightDp >= 480f ? "medium" : "compact");
100
+ return result;
101
+ }
102
+
103
+ @Override
104
+ public void accept(WindowLayoutInfo info) {
105
+ FoldingFeature fold = null;
106
+ for (DisplayFeature feature : info.getDisplayFeatures()) {
107
+ if (feature instanceof FoldingFeature) {
108
+ fold = (FoldingFeature) feature;
109
+ break;
110
+ }
111
+ }
112
+ if (fold != null) {
113
+ sawFold = true;
114
+ }
115
+ current = toFoldState(fold);
116
+ callback.onFoldState(current);
117
+ }
118
+
119
+ private JSObject toFoldState(FoldingFeature fold) {
120
+ if (fold == null) {
121
+ return flatState();
122
+ }
123
+
124
+ float density = activity.getResources().getDisplayMetrics().density;
125
+ int[] offset = new int[2];
126
+ webView.getLocationInWindow(offset);
127
+ JSObject bounds = boundsOf(fold.getBounds(), density, offset[0], offset[1]);
128
+
129
+ boolean halfOpened = FoldingFeature.State.HALF_OPENED.equals(fold.getState());
130
+ boolean horizontal = FoldingFeature.Orientation.HORIZONTAL.equals(fold.getOrientation());
131
+
132
+ JSObject state = new JSObject();
133
+ state.put("state", halfOpened ? "half-opened" : "flat");
134
+ state.put("isSeparating", fold.isSeparating());
135
+ state.put("posture", !halfOpened ? "flat" : horizontal ? "tabletop" : "book");
136
+ state.put("hingeOrientation", horizontal ? "horizontal" : "vertical");
137
+ state.put("hingeBounds", bounds);
138
+ if (FoldingFeature.OcclusionType.FULL.equals(fold.getOcclusionType())) {
139
+ state.put("occludedBounds", bounds);
140
+ }
141
+ return state;
142
+ }
143
+
144
+ private static JSObject boundsOf(Rect rect, float density, int offsetX, int offsetY) {
145
+ JSObject bounds = new JSObject();
146
+ bounds.put("x", Math.round((rect.left - offsetX) / density));
147
+ bounds.put("y", Math.round((rect.top - offsetY) / density));
148
+ bounds.put("width", Math.round(rect.width() / density));
149
+ bounds.put("height", Math.round(rect.height() / density));
150
+ return bounds;
151
+ }
152
+
153
+ private static JSObject flatState() {
154
+ JSObject state = new JSObject();
155
+ state.put("state", "flat");
156
+ state.put("isSeparating", false);
157
+ state.put("posture", "flat");
158
+ return state;
159
+ }
160
+
161
+ private static String widthClass(float widthDp) {
162
+ if (widthDp >= 1600f) return "extraLarge";
163
+ if (widthDp >= 1200f) return "large";
164
+ if (widthDp >= 840f) return "expanded";
165
+ if (widthDp >= 600f) return "medium";
166
+ return "compact";
167
+ }
168
+
169
+ private static boolean supportsTabletop(WindowInfoTracker tracker) {
170
+ try {
171
+ return tracker.getSupportedPostures().contains(SupportedPosture.TABLETOP);
172
+ } catch (RuntimeException ignored) {
173
+ return false;
174
+ }
175
+ }
176
+ }