@symbiote-native/engine 0.1.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.
Files changed (195) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +124 -0
  3. package/build/accessibility-info/index.android.d.ts +3 -0
  4. package/build/accessibility-info/index.android.js +166 -0
  5. package/build/accessibility-info/index.d.ts +1 -0
  6. package/build/accessibility-info/index.ios.d.ts +3 -0
  7. package/build/accessibility-info/index.ios.js +219 -0
  8. package/build/accessibility-info/index.js +5 -0
  9. package/build/accessibility-info/shared.d.ts +34 -0
  10. package/build/accessibility-info/shared.js +13 -0
  11. package/build/action-sheet-ios/index.d.ts +36 -0
  12. package/build/action-sheet-ios/index.js +74 -0
  13. package/build/alert/index.android.d.ts +5 -0
  14. package/build/alert/index.android.js +117 -0
  15. package/build/alert/index.d.ts +1 -0
  16. package/build/alert/index.ios.d.ts +7 -0
  17. package/build/alert/index.ios.js +83 -0
  18. package/build/alert/index.js +8 -0
  19. package/build/alert/shared.d.ts +19 -0
  20. package/build/alert/shared.js +17 -0
  21. package/build/animated/animated-component-shared.d.ts +5 -0
  22. package/build/animated/animated-component-shared.js +54 -0
  23. package/build/animated/animation.d.ts +9 -0
  24. package/build/animated/animation.js +6 -0
  25. package/build/animated/animations/base.d.ts +27 -0
  26. package/build/animated/animations/base.js +90 -0
  27. package/build/animated/animations/composition.d.ts +38 -0
  28. package/build/animated/animations/composition.js +236 -0
  29. package/build/animated/animations/decay.d.ts +22 -0
  30. package/build/animated/animations/decay.js +65 -0
  31. package/build/animated/animations/raf.d.ts +5 -0
  32. package/build/animated/animations/raf.js +39 -0
  33. package/build/animated/animations/spring-config.d.ts +6 -0
  34. package/build/animated/animations/spring-config.js +55 -0
  35. package/build/animated/animations/spring.d.ts +50 -0
  36. package/build/animated/animations/spring.js +207 -0
  37. package/build/animated/animations/timing.d.ts +27 -0
  38. package/build/animated/animations/timing.js +101 -0
  39. package/build/animated/animations/tracking.d.ts +14 -0
  40. package/build/animated/animations/tracking.js +43 -0
  41. package/build/animated/bezier.d.ts +1 -0
  42. package/build/animated/bezier.js +101 -0
  43. package/build/animated/color.d.ts +37 -0
  44. package/build/animated/color.js +183 -0
  45. package/build/animated/easing.d.ts +20 -0
  46. package/build/animated/easing.js +96 -0
  47. package/build/animated/event.d.ts +36 -0
  48. package/build/animated/event.js +252 -0
  49. package/build/animated/graph.d.ts +38 -0
  50. package/build/animated/graph.js +227 -0
  51. package/build/animated/index.d.ts +20 -0
  52. package/build/animated/index.js +28 -0
  53. package/build/animated/interpolation-node.d.ts +16 -0
  54. package/build/animated/interpolation-node.js +57 -0
  55. package/build/animated/interpolation.d.ts +22 -0
  56. package/build/animated/interpolation.js +199 -0
  57. package/build/animated/mock.d.ts +56 -0
  58. package/build/animated/mock.js +127 -0
  59. package/build/animated/native/native-animated.d.ts +43 -0
  60. package/build/animated/native/native-animated.js +146 -0
  61. package/build/animated/operators.d.ts +80 -0
  62. package/build/animated/operators.js +266 -0
  63. package/build/animated/props.d.ts +20 -0
  64. package/build/animated/props.js +187 -0
  65. package/build/animated/style.d.ts +26 -0
  66. package/build/animated/style.js +187 -0
  67. package/build/animated/value-xy.d.ts +35 -0
  68. package/build/animated/value-xy.js +106 -0
  69. package/build/animated/value.d.ts +36 -0
  70. package/build/animated/value.js +185 -0
  71. package/build/app-registry/index.d.ts +40 -0
  72. package/build/app-registry/index.js +144 -0
  73. package/build/app-state/index.d.ts +16 -0
  74. package/build/app-state/index.js +105 -0
  75. package/build/appearance/index.d.ts +12 -0
  76. package/build/appearance/index.js +84 -0
  77. package/build/back-handler/index.d.ts +14 -0
  78. package/build/back-handler/index.js +106 -0
  79. package/build/commit.d.ts +16 -0
  80. package/build/commit.js +678 -0
  81. package/build/debug.d.ts +5 -0
  82. package/build/debug.js +18 -0
  83. package/build/dimensions/index.d.ts +28 -0
  84. package/build/dimensions/index.js +148 -0
  85. package/build/dispatch.d.ts +2 -0
  86. package/build/dispatch.js +18 -0
  87. package/build/events/index.d.ts +1 -0
  88. package/build/events/index.js +691 -0
  89. package/build/fabric.d.ts +32 -0
  90. package/build/fabric.js +59 -0
  91. package/build/host-instance/index.d.ts +11 -0
  92. package/build/host-instance/index.js +49 -0
  93. package/build/i18n-manager/index.d.ts +13 -0
  94. package/build/i18n-manager/index.js +91 -0
  95. package/build/index.d.ts +80 -0
  96. package/build/index.js +72 -0
  97. package/build/interaction-manager/index.d.ts +45 -0
  98. package/build/interaction-manager/index.js +222 -0
  99. package/build/keyboard/index.d.ts +31 -0
  100. package/build/keyboard/index.js +142 -0
  101. package/build/layout-animation/index.d.ts +66 -0
  102. package/build/layout-animation/index.js +183 -0
  103. package/build/linking/index.android.d.ts +2 -0
  104. package/build/linking/index.android.js +18 -0
  105. package/build/linking/index.d.ts +1 -0
  106. package/build/linking/index.ios.d.ts +2 -0
  107. package/build/linking/index.ios.js +9 -0
  108. package/build/linking/index.js +6 -0
  109. package/build/linking/shared.d.ts +32 -0
  110. package/build/linking/shared.js +98 -0
  111. package/build/native-events.d.ts +24 -0
  112. package/build/native-events.js +129 -0
  113. package/build/native-modules.d.ts +6 -0
  114. package/build/native-modules.js +57 -0
  115. package/build/node.d.ts +36 -0
  116. package/build/node.js +194 -0
  117. package/build/pan-responder/index.d.ts +53 -0
  118. package/build/pan-responder/index.js +353 -0
  119. package/build/permissions-android/index.d.ts +115 -0
  120. package/build/permissions-android/index.js +185 -0
  121. package/build/pixel-ratio/index.d.ts +8 -0
  122. package/build/pixel-ratio/index.js +27 -0
  123. package/build/platform/index.android.d.ts +22 -0
  124. package/build/platform/index.android.js +60 -0
  125. package/build/platform/index.d.ts +1 -0
  126. package/build/platform/index.ios.d.ts +18 -0
  127. package/build/platform/index.ios.js +62 -0
  128. package/build/platform/index.js +5 -0
  129. package/build/platform/shared.d.ts +25 -0
  130. package/build/platform/shared.js +41 -0
  131. package/build/platform-color.d.ts +19 -0
  132. package/build/platform-color.js +25 -0
  133. package/build/post-commit.d.ts +4 -0
  134. package/build/post-commit.js +16 -0
  135. package/build/process-aspect-ratio.d.ts +1 -0
  136. package/build/process-aspect-ratio.js +34 -0
  137. package/build/process-background-image/index.d.ts +28 -0
  138. package/build/process-background-image/index.js +557 -0
  139. package/build/process-box-shadow/index.d.ts +11 -0
  140. package/build/process-box-shadow/index.js +193 -0
  141. package/build/process-filter.d.ts +31 -0
  142. package/build/process-filter.js +304 -0
  143. package/build/process-font-variant.d.ts +1 -0
  144. package/build/process-font-variant.js +17 -0
  145. package/build/process-transform/index.d.ts +5 -0
  146. package/build/process-transform/index.js +120 -0
  147. package/build/process-transform-origin/index.d.ts +3 -0
  148. package/build/process-transform-origin/index.js +108 -0
  149. package/build/registry.d.ts +31 -0
  150. package/build/registry.js +145 -0
  151. package/build/settings/index.d.ts +8 -0
  152. package/build/settings/index.js +126 -0
  153. package/build/share/index.android.d.ts +3 -0
  154. package/build/share/index.android.js +56 -0
  155. package/build/share/index.d.ts +1 -0
  156. package/build/share/index.ios.d.ts +3 -0
  157. package/build/share/index.ios.js +47 -0
  158. package/build/share/index.js +6 -0
  159. package/build/share/shared.d.ts +32 -0
  160. package/build/share/shared.js +32 -0
  161. package/build/status-bar/index.android.d.ts +5 -0
  162. package/build/status-bar/index.android.js +83 -0
  163. package/build/status-bar/index.d.ts +1 -0
  164. package/build/status-bar/index.ios.d.ts +5 -0
  165. package/build/status-bar/index.ios.js +66 -0
  166. package/build/status-bar/index.js +4 -0
  167. package/build/status-bar/shared.d.ts +22 -0
  168. package/build/status-bar/shared.js +22 -0
  169. package/build/style/index.d.ts +1 -0
  170. package/build/style/index.js +30 -0
  171. package/build/style-registry/index.d.ts +11 -0
  172. package/build/style-registry/index.js +165 -0
  173. package/build/style-sheet/index.d.ts +20 -0
  174. package/build/style-sheet/index.js +121 -0
  175. package/build/styles.d.ts +220 -0
  176. package/build/styles.js +7 -0
  177. package/build/surface.d.ts +16 -0
  178. package/build/surface.js +67 -0
  179. package/build/tags.d.ts +1 -0
  180. package/build/tags.js +10 -0
  181. package/build/text-input-state.d.ts +5 -0
  182. package/build/text-input-state.js +29 -0
  183. package/build/toast-android/index.d.ts +10 -0
  184. package/build/toast-android/index.js +108 -0
  185. package/build/vibration/index.android.d.ts +2 -0
  186. package/build/vibration/index.android.js +18 -0
  187. package/build/vibration/index.d.ts +1 -0
  188. package/build/vibration/index.ios.d.ts +2 -0
  189. package/build/vibration/index.ios.js +54 -0
  190. package/build/vibration/index.js +6 -0
  191. package/build/vibration/shared.d.ts +15 -0
  192. package/build/vibration/shared.js +68 -0
  193. package/build/view-config.d.ts +1 -0
  194. package/build/view-config.js +114 -0
  195. package/package.json +41 -0
@@ -0,0 +1,353 @@
1
+ // PanResponder: pure JS gesture recognition layered on the View responder event
2
+ // props. It reconciles a stream of touch events into one accumulative gesture and
3
+ // exposes a `panHandlers` object the caller spreads onto a View. There is no new
4
+ // native view and no core change: it only consumes the responder props shared
5
+ // already synthesizes (onStartShouldSetResponder / onResponderGrant /
6
+ // onResponderMove / onResponderRelease / onResponderTerminate / ...), exactly
7
+ // as RN's PanResponder consumes them.
8
+ //
9
+ // Ported from react-native/Libraries/Interaction/PanResponder.js. RN sources its
10
+ // touch geometry from a global ResponderTouchHistoryStore; symbiote's synthetic
11
+ // events instead carry the live touches on `event.nativeEvent.touches` (and the
12
+ // changed ones on `changedTouches`), so the centroid/velocity math here reads
13
+ // those directly while keeping RN's accumulate-deltas-over-time behavior.
14
+ import { dlog } from '../debug';
15
+ const SINGLE_TOUCH_COUNT = 1;
16
+ // onShouldBlockNativeResponder defaults to true (RN: block native by default).
17
+ const DEFAULT_BLOCK_NATIVE_RESPONDER = true;
18
+ function isRecord(value) {
19
+ return typeof value === 'object' && value !== null;
20
+ }
21
+ function toFiniteNumber(value) {
22
+ return typeof value === 'number' && Number.isFinite(value) ? value : undefined;
23
+ }
24
+ // Pull one touch out of an untyped array element, skipping anything that does not
25
+ // carry numeric pageX/pageY. `timestamp` falls back to 0 when absent so a touch
26
+ // with coordinates but no time still contributes to the centroid.
27
+ function toTouchPoint(raw) {
28
+ if (!isRecord(raw))
29
+ return undefined;
30
+ const pageX = toFiniteNumber(raw.pageX);
31
+ const pageY = toFiniteNumber(raw.pageY);
32
+ if (pageX === undefined || pageY === undefined)
33
+ return undefined;
34
+ return { pageX, pageY, timestamp: toFiniteNumber(raw.timestamp) ?? 0 };
35
+ }
36
+ // All current touches on screen, read off event.nativeEvent.touches.
37
+ function readTouches(event) {
38
+ const raw = event.nativeEvent.touches;
39
+ if (!Array.isArray(raw))
40
+ return [];
41
+ const points = [];
42
+ for (const entry of raw) {
43
+ const point = toTouchPoint(entry);
44
+ if (point !== undefined)
45
+ points.push(point);
46
+ }
47
+ return points;
48
+ }
49
+ // Mean of a coordinate across the active touches, the gesture centroid. RN's
50
+ // TouchHistoryMath does the same averaging over active touches.
51
+ function centroidX(touches) {
52
+ if (touches.length === 0)
53
+ return 0;
54
+ let sum = 0;
55
+ for (const touch of touches)
56
+ sum += touch.pageX;
57
+ return sum / touches.length;
58
+ }
59
+ function centroidY(touches) {
60
+ if (touches.length === 0)
61
+ return 0;
62
+ let sum = 0;
63
+ for (const touch of touches)
64
+ sum += touch.pageY;
65
+ return sum / touches.length;
66
+ }
67
+ // The most recent touch timestamp in the current frame, the clock PanResponder
68
+ // advances `_accountsForMovesUpTo` to and divides the velocity by.
69
+ function mostRecentTimestamp(touches) {
70
+ let latest = 0;
71
+ for (const touch of touches) {
72
+ if (touch.timestamp > latest)
73
+ latest = touch.timestamp;
74
+ }
75
+ return latest;
76
+ }
77
+ // #region touchHistory (RN-faithful multitouch geometry)
78
+ // shared attaches a touch-history bank onto nativeEvent (matching RN's
79
+ // ResponderEventPlugin). When present, the gesture math runs through RN's
80
+ // TouchHistoryMath instead of the all-touch centroid, so dx/vx counts only the touches
81
+ // that moved this frame, via each touch's own previous->current delta. Headless callers
82
+ // that invoke the handlers directly (no shared, no store) carry no touchHistory and fall
83
+ // back to the centroid path below, which keeps single-touch behavior.
84
+ function isTouchRecord(value) {
85
+ return (isRecord(value) &&
86
+ typeof value.touchActive === 'boolean' &&
87
+ typeof value.currentPageX === 'number' &&
88
+ typeof value.currentPageY === 'number' &&
89
+ typeof value.currentTimeStamp === 'number' &&
90
+ typeof value.previousPageX === 'number' &&
91
+ typeof value.previousPageY === 'number');
92
+ }
93
+ function isTouchHistory(value) {
94
+ return (isRecord(value) &&
95
+ Array.isArray(value.touchBank) &&
96
+ typeof value.numberActiveTouches === 'number' &&
97
+ typeof value.indexOfSingleActiveTouch === 'number' &&
98
+ typeof value.mostRecentTimeStamp === 'number');
99
+ }
100
+ function touchHistoryOf(event) {
101
+ const raw = event.nativeEvent.touchHistory;
102
+ return isTouchHistory(raw) ? raw : undefined;
103
+ }
104
+ // Ported from RN Interaction/TouchHistoryMath.js:centroidDimension (lines 30-85). Mean
105
+ // of one coordinate over the touches that moved after `touchesChangedAfter`, taking each
106
+ // touch's current or previous position. The single-active-touch fast path uses a strict
107
+ // `>`; the multi-touch scan uses `>=`, both kept from RN.
108
+ function centroidDimension(touchHistory, touchesChangedAfter, isXAxis, ofCurrent) {
109
+ const { touchBank } = touchHistory;
110
+ let total = 0;
111
+ let count = 0;
112
+ const single = touchHistory.numberActiveTouches === SINGLE_TOUCH_COUNT
113
+ ? touchBank[touchHistory.indexOfSingleActiveTouch]
114
+ : undefined;
115
+ if (isTouchRecord(single)) {
116
+ if (single.touchActive && single.currentTimeStamp > touchesChangedAfter) {
117
+ total += dimensionOf(single, isXAxis, ofCurrent);
118
+ count = 1;
119
+ }
120
+ }
121
+ else {
122
+ for (const record of touchBank) {
123
+ if (isTouchRecord(record) &&
124
+ record.touchActive &&
125
+ record.currentTimeStamp >= touchesChangedAfter) {
126
+ total += dimensionOf(record, isXAxis, ofCurrent);
127
+ count++;
128
+ }
129
+ }
130
+ }
131
+ return count > 0 ? total / count : NO_CENTROID;
132
+ }
133
+ const NO_CENTROID = -1;
134
+ function dimensionOf(record, isXAxis, ofCurrent) {
135
+ if (ofCurrent)
136
+ return isXAxis ? record.currentPageX : record.currentPageY;
137
+ return isXAxis ? record.previousPageX : record.previousPageY;
138
+ }
139
+ function currentCentroidXOfChanged(touchHistory, after) {
140
+ return centroidDimension(touchHistory, after, true, true);
141
+ }
142
+ function currentCentroidYOfChanged(touchHistory, after) {
143
+ return centroidDimension(touchHistory, after, false, true);
144
+ }
145
+ function previousCentroidXOfChanged(touchHistory, after) {
146
+ return centroidDimension(touchHistory, after, true, false);
147
+ }
148
+ function previousCentroidYOfChanged(touchHistory, after) {
149
+ return centroidDimension(touchHistory, after, false, false);
150
+ }
151
+ function currentCentroidXAll(touchHistory) {
152
+ return centroidDimension(touchHistory, 0, true, true);
153
+ }
154
+ function currentCentroidYAll(touchHistory) {
155
+ return centroidDimension(touchHistory, 0, false, true);
156
+ }
157
+ // RN PanResponder._updateGestureStateOnMove (Interaction/PanResponder.js lines 330-366):
158
+ // accumulate the centroid change of touches that moved after `_accountsForMovesUpTo`,
159
+ // rather than tracking the absolute centroid of all touches. This is what makes a
160
+ // stopped finger in a multi-finger drag stop contributing to dx.
161
+ function updateGestureStateFromHistory(gestureState, touchHistory) {
162
+ gestureState.numberActiveTouches = touchHistory.numberActiveTouches;
163
+ const movedAfter = gestureState._accountsForMovesUpTo;
164
+ gestureState.moveX = currentCentroidXOfChanged(touchHistory, movedAfter);
165
+ gestureState.moveY = currentCentroidYOfChanged(touchHistory, movedAfter);
166
+ const prevX = previousCentroidXOfChanged(touchHistory, movedAfter);
167
+ const x = currentCentroidXOfChanged(touchHistory, movedAfter);
168
+ const prevY = previousCentroidYOfChanged(touchHistory, movedAfter);
169
+ const y = currentCentroidYOfChanged(touchHistory, movedAfter);
170
+ const nextDx = gestureState.dx + (x - prevX);
171
+ const nextDy = gestureState.dy + (y - prevY);
172
+ const dt = touchHistory.mostRecentTimeStamp - gestureState._accountsForMovesUpTo;
173
+ if (dt > 0) {
174
+ gestureState.vx = (nextDx - gestureState.dx) / dt;
175
+ gestureState.vy = (nextDy - gestureState.dy) / dt;
176
+ }
177
+ else {
178
+ gestureState.vx = 0;
179
+ gestureState.vy = 0;
180
+ }
181
+ gestureState.dx = nextDx;
182
+ gestureState.dy = nextDy;
183
+ gestureState._accountsForMovesUpTo = touchHistory.mostRecentTimeStamp;
184
+ }
185
+ // #endregion
186
+ function initializeGestureState(gestureState) {
187
+ gestureState.moveX = 0;
188
+ gestureState.moveY = 0;
189
+ gestureState.x0 = 0;
190
+ gestureState.y0 = 0;
191
+ gestureState.dx = 0;
192
+ gestureState.dy = 0;
193
+ gestureState.vx = 0;
194
+ gestureState.vy = 0;
195
+ gestureState.numberActiveTouches = 0;
196
+ gestureState._accountsForMovesUpTo = 0;
197
+ }
198
+ // The timestamp this frame advances to: the touch-history clock when shared attached a
199
+ // store, else the most recent of the live touches (headless direct-call path).
200
+ function frameTimestampOf(event, touches) {
201
+ return touchHistoryOf(event)?.mostRecentTimeStamp ?? mostRecentTimestamp(touches);
202
+ }
203
+ // Advance the gesture for a move frame. With a touch-history store (the device / shared
204
+ // path) this defers to RN's accumulate-per-moved-touch math; without one it falls back to
205
+ // the all-touch centroid delta, correct for the single dragging finger the headless
206
+ // pan-responder smoke exercises. Guards dt === 0 so a zero-gap frame reports zero
207
+ // velocity instead of NaN.
208
+ function updateGestureStateOnMove(gestureState, event, touches) {
209
+ const touchHistory = touchHistoryOf(event);
210
+ if (touchHistory !== undefined) {
211
+ updateGestureStateFromHistory(gestureState, touchHistory);
212
+ return;
213
+ }
214
+ const currentX = centroidX(touches);
215
+ const currentY = centroidY(touches);
216
+ const frameTimestamp = mostRecentTimestamp(touches);
217
+ gestureState.numberActiveTouches = touches.length;
218
+ gestureState.moveX = currentX;
219
+ gestureState.moveY = currentY;
220
+ const nextDx = currentX - gestureState.x0;
221
+ const nextDy = currentY - gestureState.y0;
222
+ const dt = frameTimestamp - gestureState._accountsForMovesUpTo;
223
+ if (dt > 0) {
224
+ gestureState.vx = (nextDx - gestureState.dx) / dt;
225
+ gestureState.vy = (nextDy - gestureState.dy) / dt;
226
+ }
227
+ else {
228
+ gestureState.vx = 0;
229
+ gestureState.vy = 0;
230
+ }
231
+ gestureState.dx = nextDx;
232
+ gestureState.dy = nextDy;
233
+ gestureState._accountsForMovesUpTo = frameTimestamp;
234
+ }
235
+ const PanResponder = {
236
+ create(config) {
237
+ const gestureState = {
238
+ // Random per-gesture id, matching RN. Useful only for debugging.
239
+ stateID: Math.random(),
240
+ moveX: 0,
241
+ moveY: 0,
242
+ x0: 0,
243
+ y0: 0,
244
+ dx: 0,
245
+ dy: 0,
246
+ vx: 0,
247
+ vy: 0,
248
+ numberActiveTouches: 0,
249
+ _accountsForMovesUpTo: 0,
250
+ };
251
+ const panHandlers = {
252
+ onStartShouldSetResponder(event) {
253
+ return config.onStartShouldSetPanResponder === undefined
254
+ ? false
255
+ : config.onStartShouldSetPanResponder(event, gestureState);
256
+ },
257
+ onMoveShouldSetResponder(event) {
258
+ return config.onMoveShouldSetPanResponder === undefined
259
+ ? false
260
+ : config.onMoveShouldSetPanResponder(event, gestureState);
261
+ },
262
+ onStartShouldSetResponderCapture(event) {
263
+ // A fresh single touch begins a new gesture, so reset the accumulator
264
+ // before any should-set callback inspects it (RN does the same).
265
+ const touches = readTouches(event);
266
+ if (touches.length === SINGLE_TOUCH_COUNT) {
267
+ initializeGestureState(gestureState);
268
+ }
269
+ gestureState.numberActiveTouches =
270
+ touchHistoryOf(event)?.numberActiveTouches ?? touches.length;
271
+ return config.onStartShouldSetPanResponderCapture === undefined
272
+ ? false
273
+ : config.onStartShouldSetPanResponderCapture(event, gestureState);
274
+ },
275
+ onMoveShouldSetResponderCapture(event) {
276
+ const touches = readTouches(event);
277
+ // Skip a duplicate dispatch of the same frame: when two touches change at
278
+ // once the responder system fires twice, but the geometry was already
279
+ // folded in on the first call.
280
+ if (gestureState._accountsForMovesUpTo === frameTimestampOf(event, touches)) {
281
+ return false;
282
+ }
283
+ updateGestureStateOnMove(gestureState, event, touches);
284
+ return config.onMoveShouldSetPanResponderCapture === undefined
285
+ ? false
286
+ : config.onMoveShouldSetPanResponderCapture(event, gestureState);
287
+ },
288
+ onResponderGrant(event) {
289
+ dlog('PanResponder grant');
290
+ const touches = readTouches(event);
291
+ const touchHistory = touchHistoryOf(event);
292
+ // x0/y0 is the non-cumulative centroid at grant time (RN: currentCentroid).
293
+ gestureState.x0 = touchHistory ? currentCentroidXAll(touchHistory) : centroidX(touches);
294
+ gestureState.y0 = touchHistory ? currentCentroidYAll(touchHistory) : centroidY(touches);
295
+ gestureState.dx = 0;
296
+ gestureState.dy = 0;
297
+ // The grant frame is already accounted for, so the first move's velocity
298
+ // is measured from here, not from time 0.
299
+ gestureState._accountsForMovesUpTo = frameTimestampOf(event, touches);
300
+ gestureState.numberActiveTouches = touchHistory?.numberActiveTouches ?? touches.length;
301
+ config.onPanResponderGrant?.(event, gestureState);
302
+ return config.onShouldBlockNativeResponder === undefined
303
+ ? DEFAULT_BLOCK_NATIVE_RESPONDER
304
+ : config.onShouldBlockNativeResponder(event, gestureState);
305
+ },
306
+ onResponderReject(event) {
307
+ config.onPanResponderReject?.(event, gestureState);
308
+ },
309
+ onResponderStart(event) {
310
+ gestureState.numberActiveTouches =
311
+ touchHistoryOf(event)?.numberActiveTouches ?? readTouches(event).length;
312
+ config.onPanResponderStart?.(event, gestureState);
313
+ },
314
+ onResponderMove(event) {
315
+ const touches = readTouches(event);
316
+ // Same duplicate-frame guard as the capture path.
317
+ if (gestureState._accountsForMovesUpTo === frameTimestampOf(event, touches)) {
318
+ return;
319
+ }
320
+ updateGestureStateOnMove(gestureState, event, touches);
321
+ config.onPanResponderMove?.(event, gestureState);
322
+ },
323
+ onResponderEnd(event) {
324
+ gestureState.numberActiveTouches =
325
+ touchHistoryOf(event)?.numberActiveTouches ?? readTouches(event).length;
326
+ config.onPanResponderEnd?.(event, gestureState);
327
+ },
328
+ onResponderRelease(event) {
329
+ dlog('PanResponder release');
330
+ config.onPanResponderRelease?.(event, gestureState);
331
+ initializeGestureState(gestureState);
332
+ },
333
+ onResponderTerminate(event) {
334
+ dlog('PanResponder terminate');
335
+ config.onPanResponderTerminate?.(event, gestureState);
336
+ initializeGestureState(gestureState);
337
+ },
338
+ onResponderTerminationRequest(event) {
339
+ return config.onPanResponderTerminationRequest === undefined
340
+ ? true
341
+ : config.onPanResponderTerminationRequest(event, gestureState);
342
+ },
343
+ };
344
+ return {
345
+ panHandlers,
346
+ // Deprecated in RN; kept for shape parity. No InteractionManager handle.
347
+ getInteractionHandle() {
348
+ return null;
349
+ },
350
+ };
351
+ },
352
+ };
353
+ export default PanResponder;
@@ -0,0 +1,115 @@
1
+ export declare const RESULTS: Readonly<{
2
+ readonly GRANTED: "granted";
3
+ readonly DENIED: "denied";
4
+ readonly NEVER_ASK_AGAIN: "never_ask_again";
5
+ }>;
6
+ export type IPermissionStatus = (typeof RESULTS)[keyof typeof RESULTS];
7
+ export declare const PERMISSIONS: Readonly<{
8
+ readonly READ_CALENDAR: "android.permission.READ_CALENDAR";
9
+ readonly WRITE_CALENDAR: "android.permission.WRITE_CALENDAR";
10
+ readonly CAMERA: "android.permission.CAMERA";
11
+ readonly READ_CONTACTS: "android.permission.READ_CONTACTS";
12
+ readonly WRITE_CONTACTS: "android.permission.WRITE_CONTACTS";
13
+ readonly GET_ACCOUNTS: "android.permission.GET_ACCOUNTS";
14
+ readonly ACCESS_FINE_LOCATION: "android.permission.ACCESS_FINE_LOCATION";
15
+ readonly ACCESS_COARSE_LOCATION: "android.permission.ACCESS_COARSE_LOCATION";
16
+ readonly ACCESS_BACKGROUND_LOCATION: "android.permission.ACCESS_BACKGROUND_LOCATION";
17
+ readonly RECORD_AUDIO: "android.permission.RECORD_AUDIO";
18
+ readonly READ_PHONE_STATE: "android.permission.READ_PHONE_STATE";
19
+ readonly CALL_PHONE: "android.permission.CALL_PHONE";
20
+ readonly READ_CALL_LOG: "android.permission.READ_CALL_LOG";
21
+ readonly WRITE_CALL_LOG: "android.permission.WRITE_CALL_LOG";
22
+ readonly ADD_VOICEMAIL: "com.android.voicemail.permission.ADD_VOICEMAIL";
23
+ readonly READ_VOICEMAIL: "com.android.voicemail.permission.READ_VOICEMAIL";
24
+ readonly WRITE_VOICEMAIL: "com.android.voicemail.permission.WRITE_VOICEMAIL";
25
+ readonly USE_SIP: "android.permission.USE_SIP";
26
+ readonly PROCESS_OUTGOING_CALLS: "android.permission.PROCESS_OUTGOING_CALLS";
27
+ readonly BODY_SENSORS: "android.permission.BODY_SENSORS";
28
+ readonly BODY_SENSORS_BACKGROUND: "android.permission.BODY_SENSORS_BACKGROUND";
29
+ readonly SEND_SMS: "android.permission.SEND_SMS";
30
+ readonly RECEIVE_SMS: "android.permission.RECEIVE_SMS";
31
+ readonly READ_SMS: "android.permission.READ_SMS";
32
+ readonly RECEIVE_WAP_PUSH: "android.permission.RECEIVE_WAP_PUSH";
33
+ readonly RECEIVE_MMS: "android.permission.RECEIVE_MMS";
34
+ readonly READ_EXTERNAL_STORAGE: "android.permission.READ_EXTERNAL_STORAGE";
35
+ readonly READ_MEDIA_IMAGES: "android.permission.READ_MEDIA_IMAGES";
36
+ readonly READ_MEDIA_VIDEO: "android.permission.READ_MEDIA_VIDEO";
37
+ readonly READ_MEDIA_AUDIO: "android.permission.READ_MEDIA_AUDIO";
38
+ readonly READ_MEDIA_VISUAL_USER_SELECTED: "android.permission.READ_MEDIA_VISUAL_USER_SELECTED";
39
+ readonly WRITE_EXTERNAL_STORAGE: "android.permission.WRITE_EXTERNAL_STORAGE";
40
+ readonly BLUETOOTH_CONNECT: "android.permission.BLUETOOTH_CONNECT";
41
+ readonly BLUETOOTH_SCAN: "android.permission.BLUETOOTH_SCAN";
42
+ readonly BLUETOOTH_ADVERTISE: "android.permission.BLUETOOTH_ADVERTISE";
43
+ readonly ACCESS_MEDIA_LOCATION: "android.permission.ACCESS_MEDIA_LOCATION";
44
+ readonly ACCEPT_HANDOVER: "android.permission.ACCEPT_HANDOVER";
45
+ readonly ACTIVITY_RECOGNITION: "android.permission.ACTIVITY_RECOGNITION";
46
+ readonly ANSWER_PHONE_CALLS: "android.permission.ANSWER_PHONE_CALLS";
47
+ readonly READ_PHONE_NUMBERS: "android.permission.READ_PHONE_NUMBERS";
48
+ readonly UWB_RANGING: "android.permission.UWB_RANGING";
49
+ readonly POST_NOTIFICATIONS: "android.permission.POST_NOTIFICATIONS";
50
+ readonly NEARBY_WIFI_DEVICES: "android.permission.NEARBY_WIFI_DEVICES";
51
+ }>;
52
+ export type IPermission = (typeof PERMISSIONS)[keyof typeof PERMISSIONS];
53
+ export type IRationale = {
54
+ title: string;
55
+ message: string;
56
+ buttonPositive?: string;
57
+ buttonNegative?: string;
58
+ buttonNeutral?: string;
59
+ };
60
+ export declare const PermissionsAndroid: {
61
+ PERMISSIONS: Readonly<{
62
+ readonly READ_CALENDAR: "android.permission.READ_CALENDAR";
63
+ readonly WRITE_CALENDAR: "android.permission.WRITE_CALENDAR";
64
+ readonly CAMERA: "android.permission.CAMERA";
65
+ readonly READ_CONTACTS: "android.permission.READ_CONTACTS";
66
+ readonly WRITE_CONTACTS: "android.permission.WRITE_CONTACTS";
67
+ readonly GET_ACCOUNTS: "android.permission.GET_ACCOUNTS";
68
+ readonly ACCESS_FINE_LOCATION: "android.permission.ACCESS_FINE_LOCATION";
69
+ readonly ACCESS_COARSE_LOCATION: "android.permission.ACCESS_COARSE_LOCATION";
70
+ readonly ACCESS_BACKGROUND_LOCATION: "android.permission.ACCESS_BACKGROUND_LOCATION";
71
+ readonly RECORD_AUDIO: "android.permission.RECORD_AUDIO";
72
+ readonly READ_PHONE_STATE: "android.permission.READ_PHONE_STATE";
73
+ readonly CALL_PHONE: "android.permission.CALL_PHONE";
74
+ readonly READ_CALL_LOG: "android.permission.READ_CALL_LOG";
75
+ readonly WRITE_CALL_LOG: "android.permission.WRITE_CALL_LOG";
76
+ readonly ADD_VOICEMAIL: "com.android.voicemail.permission.ADD_VOICEMAIL";
77
+ readonly READ_VOICEMAIL: "com.android.voicemail.permission.READ_VOICEMAIL";
78
+ readonly WRITE_VOICEMAIL: "com.android.voicemail.permission.WRITE_VOICEMAIL";
79
+ readonly USE_SIP: "android.permission.USE_SIP";
80
+ readonly PROCESS_OUTGOING_CALLS: "android.permission.PROCESS_OUTGOING_CALLS";
81
+ readonly BODY_SENSORS: "android.permission.BODY_SENSORS";
82
+ readonly BODY_SENSORS_BACKGROUND: "android.permission.BODY_SENSORS_BACKGROUND";
83
+ readonly SEND_SMS: "android.permission.SEND_SMS";
84
+ readonly RECEIVE_SMS: "android.permission.RECEIVE_SMS";
85
+ readonly READ_SMS: "android.permission.READ_SMS";
86
+ readonly RECEIVE_WAP_PUSH: "android.permission.RECEIVE_WAP_PUSH";
87
+ readonly RECEIVE_MMS: "android.permission.RECEIVE_MMS";
88
+ readonly READ_EXTERNAL_STORAGE: "android.permission.READ_EXTERNAL_STORAGE";
89
+ readonly READ_MEDIA_IMAGES: "android.permission.READ_MEDIA_IMAGES";
90
+ readonly READ_MEDIA_VIDEO: "android.permission.READ_MEDIA_VIDEO";
91
+ readonly READ_MEDIA_AUDIO: "android.permission.READ_MEDIA_AUDIO";
92
+ readonly READ_MEDIA_VISUAL_USER_SELECTED: "android.permission.READ_MEDIA_VISUAL_USER_SELECTED";
93
+ readonly WRITE_EXTERNAL_STORAGE: "android.permission.WRITE_EXTERNAL_STORAGE";
94
+ readonly BLUETOOTH_CONNECT: "android.permission.BLUETOOTH_CONNECT";
95
+ readonly BLUETOOTH_SCAN: "android.permission.BLUETOOTH_SCAN";
96
+ readonly BLUETOOTH_ADVERTISE: "android.permission.BLUETOOTH_ADVERTISE";
97
+ readonly ACCESS_MEDIA_LOCATION: "android.permission.ACCESS_MEDIA_LOCATION";
98
+ readonly ACCEPT_HANDOVER: "android.permission.ACCEPT_HANDOVER";
99
+ readonly ACTIVITY_RECOGNITION: "android.permission.ACTIVITY_RECOGNITION";
100
+ readonly ANSWER_PHONE_CALLS: "android.permission.ANSWER_PHONE_CALLS";
101
+ readonly READ_PHONE_NUMBERS: "android.permission.READ_PHONE_NUMBERS";
102
+ readonly UWB_RANGING: "android.permission.UWB_RANGING";
103
+ readonly POST_NOTIFICATIONS: "android.permission.POST_NOTIFICATIONS";
104
+ readonly NEARBY_WIFI_DEVICES: "android.permission.NEARBY_WIFI_DEVICES";
105
+ }>;
106
+ RESULTS: Readonly<{
107
+ readonly GRANTED: "granted";
108
+ readonly DENIED: "denied";
109
+ readonly NEVER_ASK_AGAIN: "never_ask_again";
110
+ }>;
111
+ check(permission: IPermission): Promise<boolean>;
112
+ request(permission: IPermission, rationale?: IRationale): Promise<IPermissionStatus>;
113
+ requestMultiple(permissions: IPermission[]): Promise<Record<string, IPermissionStatus>>;
114
+ shouldShowRequestPermissionRationale(permission: IPermission): Promise<boolean>;
115
+ };
@@ -0,0 +1,185 @@
1
+ // PermissionsAndroid module: JS wrapper over Android's runtime-permissions
2
+ // model. Mirrors RN's Libraries/PermissionsAndroid/PermissionsAndroid.js,
3
+ // exposing the modern API: check / request / requestMultiple /
4
+ // shouldShowRequestPermissionRationale, plus the frozen PERMISSIONS and RESULTS
5
+ // constant maps. Imperative JS->native calls with no Fabric view of their own,
6
+ // like Vibration / Keyboard.
7
+ //
8
+ // symbiote is iOS-first and this module is Android-only, so it MUST degrade
9
+ // gracefully when the native module is absent (on iOS, or headless). RN throws
10
+ // "works only for Android"; we instead resolve a safe default + dlog so a
11
+ // cross-platform smoke never hard-crashes the process. Never reject/throw
12
+ // synchronously on a missing module.
13
+ //
14
+ // The native contract is confirmed from RN's TurboModule spec at
15
+ // specs_DEPRECATED/modules/INativePermissionsAndroid.js (`'PermissionsAndroid'`):
16
+ // checkPermission(permission): Promise<boolean>
17
+ // requestPermission(permission): Promise<string>
18
+ // shouldShowRequestPermissionRationale(permission): Promise<boolean>
19
+ // requestMultiplePermissions(permissions): Promise<{[permission]: string}>
20
+ import { getNativeModule } from '../native-modules';
21
+ import { dlog } from '../debug';
22
+ // The native module name RN registers this TurboModule under
23
+ // (`TurboModuleRegistry.get<Spec>('PermissionsAndroid')`). NOTE: per the
24
+ // symbiote invariant, a module name is only provable on a real host (a headless
25
+ // fake answers to any name); this name is device-verify-pending. See
26
+ // .docs/native-module-platform-routing.md.
27
+ const PERMISSIONS_ANDROID_MODULE = 'PermissionsAndroid';
28
+ // The runtime-permission result strings Android can return. Modeled as a frozen
29
+ // `as const` map: the generated-style constant-map exception to "no magic
30
+ // strings".
31
+ export const RESULTS = Object.freeze({
32
+ GRANTED: 'granted',
33
+ DENIED: 'denied',
34
+ NEVER_ASK_AGAIN: 'never_ask_again',
35
+ });
36
+ // The full Android permission-string map, copied verbatim from RN's source.
37
+ // Frozen `as const` constant map (the same string-map exception as RESULTS).
38
+ export const PERMISSIONS = Object.freeze({
39
+ READ_CALENDAR: 'android.permission.READ_CALENDAR',
40
+ WRITE_CALENDAR: 'android.permission.WRITE_CALENDAR',
41
+ CAMERA: 'android.permission.CAMERA',
42
+ READ_CONTACTS: 'android.permission.READ_CONTACTS',
43
+ WRITE_CONTACTS: 'android.permission.WRITE_CONTACTS',
44
+ GET_ACCOUNTS: 'android.permission.GET_ACCOUNTS',
45
+ ACCESS_FINE_LOCATION: 'android.permission.ACCESS_FINE_LOCATION',
46
+ ACCESS_COARSE_LOCATION: 'android.permission.ACCESS_COARSE_LOCATION',
47
+ ACCESS_BACKGROUND_LOCATION: 'android.permission.ACCESS_BACKGROUND_LOCATION',
48
+ RECORD_AUDIO: 'android.permission.RECORD_AUDIO',
49
+ READ_PHONE_STATE: 'android.permission.READ_PHONE_STATE',
50
+ CALL_PHONE: 'android.permission.CALL_PHONE',
51
+ READ_CALL_LOG: 'android.permission.READ_CALL_LOG',
52
+ WRITE_CALL_LOG: 'android.permission.WRITE_CALL_LOG',
53
+ ADD_VOICEMAIL: 'com.android.voicemail.permission.ADD_VOICEMAIL',
54
+ READ_VOICEMAIL: 'com.android.voicemail.permission.READ_VOICEMAIL',
55
+ WRITE_VOICEMAIL: 'com.android.voicemail.permission.WRITE_VOICEMAIL',
56
+ USE_SIP: 'android.permission.USE_SIP',
57
+ PROCESS_OUTGOING_CALLS: 'android.permission.PROCESS_OUTGOING_CALLS',
58
+ BODY_SENSORS: 'android.permission.BODY_SENSORS',
59
+ BODY_SENSORS_BACKGROUND: 'android.permission.BODY_SENSORS_BACKGROUND',
60
+ SEND_SMS: 'android.permission.SEND_SMS',
61
+ RECEIVE_SMS: 'android.permission.RECEIVE_SMS',
62
+ READ_SMS: 'android.permission.READ_SMS',
63
+ RECEIVE_WAP_PUSH: 'android.permission.RECEIVE_WAP_PUSH',
64
+ RECEIVE_MMS: 'android.permission.RECEIVE_MMS',
65
+ READ_EXTERNAL_STORAGE: 'android.permission.READ_EXTERNAL_STORAGE',
66
+ READ_MEDIA_IMAGES: 'android.permission.READ_MEDIA_IMAGES',
67
+ READ_MEDIA_VIDEO: 'android.permission.READ_MEDIA_VIDEO',
68
+ READ_MEDIA_AUDIO: 'android.permission.READ_MEDIA_AUDIO',
69
+ READ_MEDIA_VISUAL_USER_SELECTED: 'android.permission.READ_MEDIA_VISUAL_USER_SELECTED',
70
+ WRITE_EXTERNAL_STORAGE: 'android.permission.WRITE_EXTERNAL_STORAGE',
71
+ BLUETOOTH_CONNECT: 'android.permission.BLUETOOTH_CONNECT',
72
+ BLUETOOTH_SCAN: 'android.permission.BLUETOOTH_SCAN',
73
+ BLUETOOTH_ADVERTISE: 'android.permission.BLUETOOTH_ADVERTISE',
74
+ ACCESS_MEDIA_LOCATION: 'android.permission.ACCESS_MEDIA_LOCATION',
75
+ ACCEPT_HANDOVER: 'android.permission.ACCEPT_HANDOVER',
76
+ ACTIVITY_RECOGNITION: 'android.permission.ACTIVITY_RECOGNITION',
77
+ ANSWER_PHONE_CALLS: 'android.permission.ANSWER_PHONE_CALLS',
78
+ READ_PHONE_NUMBERS: 'android.permission.READ_PHONE_NUMBERS',
79
+ UWB_RANGING: 'android.permission.UWB_RANGING',
80
+ POST_NOTIFICATIONS: 'android.permission.POST_NOTIFICATIONS',
81
+ NEARBY_WIFI_DEVICES: 'android.permission.NEARBY_WIFI_DEVICES',
82
+ });
83
+ function isBoolean(value) {
84
+ return typeof value === 'boolean';
85
+ }
86
+ // Narrow the native string result into a known RESULTS value. Any unrecognized
87
+ // string is passed through as a IPermissionStatus only when it matches; otherwise
88
+ // we fall back to DENIED: a runtime guard at the trust boundary, not an `as`.
89
+ function toPermissionStatus(value) {
90
+ if (value === RESULTS.GRANTED || value === RESULTS.DENIED || value === RESULTS.NEVER_ASK_AGAIN) {
91
+ return value;
92
+ }
93
+ return RESULTS.DENIED;
94
+ }
95
+ // Narrow the native requestMultiplePermissions() return into a per-permission
96
+ // status map. Each value is run through toPermissionStatus; non-object returns
97
+ // yield an empty map.
98
+ function toStatusMap(value) {
99
+ const result = {};
100
+ if (typeof value !== 'object' || value === null)
101
+ return result;
102
+ for (const key of Object.keys(value)) {
103
+ result[key] = toPermissionStatus(Reflect.get(value, key));
104
+ }
105
+ return result;
106
+ }
107
+ // Resolved FRESH on every call, deliberately NOT memoized at module load. The original
108
+ // self-contained module resolved once at import, but moving it into the engine made it a
109
+ // shared singleton; a cached null would survive a module being linked later (or the headless
110
+ // smoke flipping a fake module on after its first import). getNativeModule is a cheap proxy
111
+ // lookup, so per-call resolution costs nothing and stays correct. Returns null on iOS / headless.
112
+ function getModule() {
113
+ const module = getNativeModule(PERMISSIONS_ANDROID_MODULE);
114
+ dlog(`PermissionsAndroid: module ${module ? 'resolved' : 'NOT resolved (null)'}`);
115
+ return module;
116
+ }
117
+ export const PermissionsAndroid = {
118
+ PERMISSIONS,
119
+ RESULTS,
120
+ // Resolve whether a permission has already been granted. Without a native
121
+ // module (iOS / headless) resolve false. Never throw.
122
+ async check(permission) {
123
+ const permissionsModule = getModule();
124
+ if (permissionsModule === null) {
125
+ dlog('PermissionsAndroid.check -> module unavailable, resolving false');
126
+ return false;
127
+ }
128
+ dlog(`PermissionsAndroid.check -> ${permission}`);
129
+ const granted = await permissionsModule.checkPermission(permission);
130
+ return isBoolean(granted) ? granted : false;
131
+ },
132
+ // Prompt the user for a permission, resolving a RESULTS status. If a rationale
133
+ // is supplied and DialogManagerAndroid is present, show it first; otherwise
134
+ // proceed straight to the native request (dlog the skip). Without the
135
+ // PermissionsAndroid module resolve RESULTS.DENIED. Never throw.
136
+ async request(permission, rationale) {
137
+ const permissionsModule = getModule();
138
+ if (permissionsModule === null) {
139
+ dlog('PermissionsAndroid.request -> module unavailable, resolving DENIED');
140
+ return RESULTS.DENIED;
141
+ }
142
+ dlog(`PermissionsAndroid.request -> ${permission}`);
143
+ if (rationale !== undefined) {
144
+ const shouldShow = await permissionsModule.shouldShowRequestPermissionRationale(permission);
145
+ const dialogModule = getNativeModule('DialogManagerAndroid');
146
+ if (isBoolean(shouldShow) && shouldShow && dialogModule !== null) {
147
+ return new Promise((resolve, reject) => {
148
+ dialogModule.showAlert(rationale, () => reject(new Error('Error showing rationale')), () => {
149
+ permissionsModule
150
+ .requestPermission(permission)
151
+ .then(status => resolve(toPermissionStatus(status)))
152
+ .catch(reject);
153
+ });
154
+ });
155
+ }
156
+ dlog('PermissionsAndroid.request -> rationale skipped (DialogManagerAndroid unavailable)');
157
+ }
158
+ const status = await permissionsModule.requestPermission(permission);
159
+ return toPermissionStatus(status);
160
+ },
161
+ // Prompt for several permissions at once, resolving a per-permission status
162
+ // map. Without a native module resolve an empty map. Never throw.
163
+ async requestMultiple(permissions) {
164
+ const permissionsModule = getModule();
165
+ if (permissionsModule === null) {
166
+ dlog('PermissionsAndroid.requestMultiple -> module unavailable, resolving {}');
167
+ return {};
168
+ }
169
+ dlog(`PermissionsAndroid.requestMultiple -> ${permissions.join(', ')}`);
170
+ const statuses = await permissionsModule.requestMultiplePermissions(permissions);
171
+ return toStatusMap(statuses);
172
+ },
173
+ // Whether the OS recommends showing a rationale before re-requesting. Without
174
+ // a native module resolve false. Never throw.
175
+ async shouldShowRequestPermissionRationale(permission) {
176
+ const permissionsModule = getModule();
177
+ if (permissionsModule === null) {
178
+ dlog('PermissionsAndroid.shouldShowRequestPermissionRationale -> module unavailable, resolving false');
179
+ return false;
180
+ }
181
+ dlog(`PermissionsAndroid.shouldShowRequestPermissionRationale -> ${permission}`);
182
+ const shouldShow = await permissionsModule.shouldShowRequestPermissionRationale(permission);
183
+ return isBoolean(shouldShow) ? shouldShow : false;
184
+ },
185
+ };
@@ -0,0 +1,8 @@
1
+ export interface IPixelRatioStatic {
2
+ get(): number;
3
+ getFontScale(): number;
4
+ getPixelSizeForLayoutSize(layoutSize: number): number;
5
+ roundToNearestPixel(layoutSize: number): number;
6
+ startDetecting(): void;
7
+ }
8
+ export declare const PixelRatio: IPixelRatioStatic;