@iternio/react-native-auto-play 0.6.1 → 0.7.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 (196) hide show
  1. package/README.md +3 -3
  2. package/android/src/automotive/AndroidManifest-nonnav.xml +0 -2
  3. package/android/src/automotive/AndroidManifest.xml +0 -2
  4. package/android/src/main/AndroidManifest-nonnav.xml +0 -2
  5. package/android/src/main/AndroidManifest.xml +0 -2
  6. package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/AndroidAutoService.kt +3 -27
  7. package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridAutoPlayTiming.kt +122 -0
  8. package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/template/Parser.kt +2 -2
  9. package/installTimers.ts +3 -0
  10. package/installTimers.web.ts +2 -0
  11. package/ios/hybrid/HybridAutoPlayTiming.swift +123 -0
  12. package/lib/components/SafeAreaView.js +1 -1
  13. package/lib/hybrid/HybridAutoPlayTiming.d.ts +2 -0
  14. package/lib/hybrid/HybridAutoPlayTiming.js +2 -0
  15. package/lib/hybrid/HybridVoice.js +2 -2
  16. package/lib/index.js +0 -2
  17. package/lib/index.web.d.ts +4 -2
  18. package/lib/installTimers.d.ts +1 -0
  19. package/lib/installTimers.js +8 -0
  20. package/lib/installTimers.web.d.ts +1 -0
  21. package/lib/installTimers.web.js +2 -0
  22. package/lib/scenes/CarPlayDashboardScene.d.ts +3 -3
  23. package/lib/specs/AutoPlayTiming.nitro.d.ts +27 -0
  24. package/lib/specs/AutoPlayTiming.nitro.js +1 -0
  25. package/lib/types/Telemetry.d.ts +1 -1
  26. package/lib/utils/AutoPlayTimers.d.ts +21 -0
  27. package/lib/utils/AutoPlayTimers.js +45 -0
  28. package/lib/utils/NitroImage.d.ts +5 -2
  29. package/lib/utils/NitroImage.js +1 -1
  30. package/lib-cjs/components/SafeAreaView.js +1 -1
  31. package/lib-cjs/hybrid/HybridVoice.js +2 -2
  32. package/lib-cjs/index.js +0 -5
  33. package/lib-cjs/utils/NitroImage.js +1 -1
  34. package/nitro.json +10 -0
  35. package/nitrogen/generated/android/ReactNativeAutoPlay+autolinking.cmake +2 -0
  36. package/nitrogen/generated/android/ReactNativeAutoPlayOnLoad.cpp +16 -0
  37. package/nitrogen/generated/android/c++/JActiveCarUxRestrictions.hpp +1 -1
  38. package/nitrogen/generated/android/c++/JAlertActionStyle.hpp +1 -1
  39. package/nitrogen/generated/android/c++/JAlertDismissalReason.hpp +1 -1
  40. package/nitrogen/generated/android/c++/JAppFocusState.hpp +1 -1
  41. package/nitrogen/generated/android/c++/JAssetImage.hpp +18 -18
  42. package/nitrogen/generated/android/c++/JAutoText.hpp +1 -1
  43. package/nitrogen/generated/android/c++/JBooleanTelemetryItem.hpp +1 -1
  44. package/nitrogen/generated/android/c++/JCarUxRestrictions.hpp +1 -1
  45. package/nitrogen/generated/android/c++/JChargingConnector.hpp +1 -1
  46. package/nitrogen/generated/android/c++/JClusterEventName.hpp +1 -1
  47. package/nitrogen/generated/android/c++/JColorScheme.hpp +1 -1
  48. package/nitrogen/generated/android/c++/JDistance.hpp +1 -1
  49. package/nitrogen/generated/android/c++/JDistanceUnits.hpp +1 -1
  50. package/nitrogen/generated/android/c++/JDurationWithTimeZone.hpp +1 -1
  51. package/nitrogen/generated/android/c++/JEventName.hpp +1 -1
  52. package/nitrogen/generated/android/c++/JForkType.hpp +1 -1
  53. package/nitrogen/generated/android/c++/JGlyphImage.hpp +1 -1
  54. package/nitrogen/generated/android/c++/JGoogleSignIn.hpp +1 -1
  55. package/nitrogen/generated/android/c++/JGoogleSignInAccount.hpp +1 -1
  56. package/nitrogen/generated/android/c++/JGridImageSize.hpp +1 -1
  57. package/nitrogen/generated/android/c++/JGridTemplateConfig.hpp +1 -1
  58. package/nitrogen/generated/android/c++/JHybridAutoPlayTimingSpec.cpp +59 -0
  59. package/nitrogen/generated/android/c++/JHybridAutoPlayTimingSpec.hpp +64 -0
  60. package/nitrogen/generated/android/c++/JImageLane.hpp +1 -1
  61. package/nitrogen/generated/android/c++/JInformationTemplateConfig.hpp +1 -1
  62. package/nitrogen/generated/android/c++/JInputSignIn.hpp +1 -1
  63. package/nitrogen/generated/android/c++/JKeepType.hpp +1 -1
  64. package/nitrogen/generated/android/c++/JKeyboardType.hpp +1 -1
  65. package/nitrogen/generated/android/c++/JLaneGuidance.hpp +1 -1
  66. package/nitrogen/generated/android/c++/JListImageType.hpp +1 -1
  67. package/nitrogen/generated/android/c++/JListTemplateConfig.hpp +1 -1
  68. package/nitrogen/generated/android/c++/JLocation.hpp +1 -1
  69. package/nitrogen/generated/android/c++/JManeuverState.hpp +1 -1
  70. package/nitrogen/generated/android/c++/JManeuverType.hpp +1 -1
  71. package/nitrogen/generated/android/c++/JMapTemplateConfig.hpp +1 -1
  72. package/nitrogen/generated/android/c++/JMessageTemplateConfig.hpp +1 -1
  73. package/nitrogen/generated/android/c++/JNavigationAlertAction.hpp +1 -1
  74. package/nitrogen/generated/android/c++/JNitroAction.hpp +1 -1
  75. package/nitrogen/generated/android/c++/JNitroActionType.hpp +1 -1
  76. package/nitrogen/generated/android/c++/JNitroAlignment.hpp +1 -1
  77. package/nitrogen/generated/android/c++/JNitroAttributedString.hpp +1 -1
  78. package/nitrogen/generated/android/c++/JNitroAttributedStringImage.hpp +1 -1
  79. package/nitrogen/generated/android/c++/JNitroBaseMapTemplateConfig.hpp +1 -1
  80. package/nitrogen/generated/android/c++/JNitroButtonStyle.hpp +1 -1
  81. package/nitrogen/generated/android/c++/JNitroChargerLocation.hpp +1 -1
  82. package/nitrogen/generated/android/c++/JNitroChargerOutlet.hpp +1 -1
  83. package/nitrogen/generated/android/c++/JNitroColor.hpp +1 -1
  84. package/nitrogen/generated/android/c++/JNitroGridButton.hpp +1 -1
  85. package/nitrogen/generated/android/c++/JNitroLoadingManeuver.hpp +1 -1
  86. package/nitrogen/generated/android/c++/JNitroMapButton.hpp +1 -1
  87. package/nitrogen/generated/android/c++/JNitroMapButtonType.hpp +1 -1
  88. package/nitrogen/generated/android/c++/JNitroMessageManeuver.hpp +1 -1
  89. package/nitrogen/generated/android/c++/JNitroNavigationAlert.hpp +1 -1
  90. package/nitrogen/generated/android/c++/JNitroOptionsPanelChargerSection.hpp +1 -1
  91. package/nitrogen/generated/android/c++/JNitroOptionsPanelConfig.hpp +1 -1
  92. package/nitrogen/generated/android/c++/JNitroOptionsPanelGridSection.hpp +1 -1
  93. package/nitrogen/generated/android/c++/JNitroRoutingManeuver.hpp +1 -1
  94. package/nitrogen/generated/android/c++/JNitroRow.hpp +1 -1
  95. package/nitrogen/generated/android/c++/JNitroSection.hpp +1 -1
  96. package/nitrogen/generated/android/c++/JNitroSectionType.hpp +1 -1
  97. package/nitrogen/generated/android/c++/JNumericTelemetryItem.hpp +1 -1
  98. package/nitrogen/generated/android/c++/JOffRampType.hpp +1 -1
  99. package/nitrogen/generated/android/c++/JOnRampType.hpp +1 -1
  100. package/nitrogen/generated/android/c++/JPermissionRequestResult.hpp +1 -1
  101. package/nitrogen/generated/android/c++/JPinSignIn.hpp +1 -1
  102. package/nitrogen/generated/android/c++/JPoint.hpp +1 -1
  103. package/nitrogen/generated/android/c++/JPreferredImageLane.hpp +1 -1
  104. package/nitrogen/generated/android/c++/JQrSignIn.hpp +1 -1
  105. package/nitrogen/generated/android/c++/JRemoteImage.hpp +1 -1
  106. package/nitrogen/generated/android/c++/JRouteChoice.hpp +1 -1
  107. package/nitrogen/generated/android/c++/JSafeAreaInsets.hpp +1 -1
  108. package/nitrogen/generated/android/c++/JSearchTemplateConfig.hpp +1 -1
  109. package/nitrogen/generated/android/c++/JSignInMethods.hpp +1 -1
  110. package/nitrogen/generated/android/c++/JSignInTemplateConfig.hpp +1 -1
  111. package/nitrogen/generated/android/c++/JStringTelemetryItem.hpp +1 -1
  112. package/nitrogen/generated/android/c++/JTelemetry.hpp +1 -1
  113. package/nitrogen/generated/android/c++/JTextInputType.hpp +1 -1
  114. package/nitrogen/generated/android/c++/JTrafficSide.hpp +1 -1
  115. package/nitrogen/generated/android/c++/JTravelEstimates.hpp +1 -1
  116. package/nitrogen/generated/android/c++/JTripConfig.hpp +1 -1
  117. package/nitrogen/generated/android/c++/JTripPoint.hpp +1 -1
  118. package/nitrogen/generated/android/c++/JTripPreviewTextConfiguration.hpp +1 -1
  119. package/nitrogen/generated/android/c++/JTripSelectorCallback.hpp +1 -1
  120. package/nitrogen/generated/android/c++/JTripsConfig.hpp +1 -1
  121. package/nitrogen/generated/android/c++/JTurnType.hpp +1 -1
  122. package/nitrogen/generated/android/c++/JVehicleTelemetryItem.hpp +1 -1
  123. package/nitrogen/generated/android/c++/JVisibilityState.hpp +1 -1
  124. package/nitrogen/generated/android/c++/JVisibleTravelEstimate.hpp +1 -1
  125. package/nitrogen/generated/android/c++/JVoiceAudioEncoding.hpp +1 -1
  126. package/nitrogen/generated/android/c++/JVoiceInputChunk.hpp +1 -1
  127. package/nitrogen/generated/android/c++/JVoiceInputResult.hpp +1 -1
  128. package/nitrogen/generated/android/c++/JWaypointCoordinate.hpp +1 -1
  129. package/nitrogen/generated/android/c++/JWindowInformation.hpp +1 -1
  130. package/nitrogen/generated/android/c++/JZoomEvent.hpp +1 -1
  131. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/AssetImage.kt +15 -15
  132. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void.kt +0 -2
  133. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_ActiveCarUxRestrictions.kt +0 -2
  134. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_AlertDismissalReason.kt +0 -2
  135. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_AppFocusState.kt +0 -2
  136. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_ColorScheme.kt +0 -2
  137. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_Point.kt +0 -2
  138. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_Point_double.kt +0 -2
  139. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_Point_std__optional_Point_.kt +0 -2
  140. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_SafeAreaInsets.kt +0 -2
  141. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_VisibilityState.kt +0 -2
  142. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_VoiceInputChunk.kt +0 -2
  143. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_WindowInformation.kt +0 -2
  144. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_bool.kt +0 -2
  145. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_std__optional_Location__std__optional_std__string_.kt +0 -2
  146. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_std__optional_Telemetry_.kt +0 -2
  147. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_std__optional_bool_.kt +0 -2
  148. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_std__optional_std__string__std__optional_GoogleSignInAccount_.kt +0 -2
  149. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_std__string.kt +0 -2
  150. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_std__string_ColorScheme.kt +0 -2
  151. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_std__string_ZoomEvent.kt +0 -2
  152. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_std__string_bool.kt +0 -2
  153. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_std__string_std__string.kt +0 -2
  154. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridAndroidAutoTelemetrySpec.kt +2 -0
  155. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridAndroidAutomotiveSpec.kt +2 -0
  156. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridAndroidWindowInformationSpec.kt +2 -0
  157. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridAutoPlaySpec.kt +2 -0
  158. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridAutoPlayTimingSpec.kt +65 -0
  159. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridClusterSpec.kt +2 -0
  160. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridGridTemplateSpec.kt +2 -0
  161. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridInformationTemplateSpec.kt +2 -0
  162. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridListTemplateSpec.kt +2 -0
  163. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridMapTemplateSpec.kt +2 -0
  164. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridMessageTemplateSpec.kt +2 -0
  165. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridSearchTemplateSpec.kt +2 -0
  166. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridSignInTemplateSpec.kt +2 -0
  167. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridVoiceSpec.kt +2 -0
  168. package/nitrogen/generated/ios/ReactNativeAutoPlay-Swift-Cxx-Bridge.cpp +17 -0
  169. package/nitrogen/generated/ios/ReactNativeAutoPlay-Swift-Cxx-Bridge.hpp +35 -9
  170. package/nitrogen/generated/ios/ReactNativeAutoPlay-Swift-Cxx-Umbrella.hpp +5 -0
  171. package/nitrogen/generated/ios/ReactNativeAutoPlayAutolinking.mm +8 -0
  172. package/nitrogen/generated/ios/ReactNativeAutoPlayAutolinking.swift +12 -0
  173. package/nitrogen/generated/ios/c++/HybridAutoPlayTimingSpecSwift.cpp +11 -0
  174. package/nitrogen/generated/ios/c++/HybridAutoPlayTimingSpecSwift.hpp +88 -0
  175. package/nitrogen/generated/ios/swift/AssetImage.swift +13 -13
  176. package/nitrogen/generated/ios/swift/HybridAutoPlayTimingSpec.swift +56 -0
  177. package/nitrogen/generated/ios/swift/HybridAutoPlayTimingSpec_cxx.swift +154 -0
  178. package/nitrogen/generated/shared/c++/AssetImage.hpp +18 -18
  179. package/nitrogen/generated/shared/c++/HybridAutoPlayTimingSpec.cpp +22 -0
  180. package/nitrogen/generated/shared/c++/HybridAutoPlayTimingSpec.hpp +63 -0
  181. package/package.json +6 -4
  182. package/src/components/SafeAreaView.tsx +1 -1
  183. package/src/hybrid/HybridAutoPlayTiming.ts +5 -0
  184. package/src/hybrid/HybridVoice.ts +2 -2
  185. package/src/index.ts +0 -3
  186. package/src/installTimers.ts +9 -0
  187. package/src/installTimers.web.ts +2 -0
  188. package/src/specs/AutoPlayTiming.nitro.ts +25 -0
  189. package/src/types/Telemetry.ts +1 -1
  190. package/src/utils/AutoPlayTimers.ts +60 -0
  191. package/src/utils/NitroImage.ts +13 -3
  192. package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/HeadlessTaskService.kt +0 -36
  193. package/lib/AutoPlayHeadlessJsTask.d.ts +0 -5
  194. package/lib/AutoPlayHeadlessJsTask.js +0 -14
  195. package/lib-cjs/AutoPlayHeadlessJsTask.js +0 -16
  196. package/src/AutoPlayHeadlessJsTask.ts +0 -22
package/README.md CHANGED
@@ -25,6 +25,7 @@
25
25
  ## Requirements
26
26
 
27
27
  - **iOS builds require Xcode 27+** (the iOS 27 SDK), even for apps that don't use any `mapConfig`/panel features — the library references `CPMapPanel`/`CPPanel` types internally behind `@available(iOS 27.0, *)` checks, but `@available` only defers *runtime* execution, not compile-time symbol resolution, so the SDK must be present to build at all.
28
+ - **`react-native-nitro-modules` 0.37.1 or newer** — the generated native bindings target that runtime shape; an older nitro-modules install fails at native build time.
28
29
 
29
30
  ## Installation
30
31
 
@@ -474,10 +475,11 @@ Use the color `'default'` for every monochrome icon that has to stay readable in
474
475
 
475
476
  ### 1. Register the AutoPlay Components
476
477
 
477
- You need to register your AutoPlay components in your app's entry file (e.g., `index.js`). This includes setting up the headless task that runs when CarPlay or Android Auto is connected.
478
+ You need to register your AutoPlay components in your app's entry file (e.g., `index.js`). Import `@iternio/react-native-auto-play/installTimers` — a side-effect-only module that replaces the global `setTimeout`/`setInterval`/`requestAnimationFrame` (and their `clear*`/`cancel*` counterparts) with versions that keep running while CarPlay/Android Auto is actively driving the car screen, even if the phone itself is backgrounded or its screen is locked. React Native's own timers throttle or pause in that state regardless of whether the app process is actually still alive, which would otherwise stall ETA updates and telemetry polling. It must run before any other module has a chance to capture a reference to the original globals, which means it must be your entry file's **first import** — ES import declarations are hoisted and evaluated in source order, so it needs to come before everything else, including `react-native` itself:
478
479
 
479
480
  ```javascript
480
481
  // index.js
482
+ import '@iternio/react-native-auto-play/installTimers';
481
483
  import { AppRegistry } from 'react-native';
482
484
  import { name as appName } from './app.json';
483
485
  import App from './src/App';
@@ -1314,8 +1316,6 @@ The same no-op surface is what `react-native-web` builds get automatically via `
1314
1316
 
1315
1317
  - **Broken exceptions with `react-native-skia`**: When using `react-native-skia` exceptions on iOS are not reported correctly. This is fixed since version `2.4.19` of `react-native-skia`. For more details, see this [pull request](https://github.com/Shopify/react-native-skia/pull/3595) and [issue](https://github.com/Shopify/react-native-skia/issues/3635).
1316
1318
  - **AppState on iOS**: The `AppState` module from React Native does not work correctly on iOS because this library uses scenes, which are not supported by the stock `AppState` module. This library provides a custom state listener that works for both Android and iOS. Use `HybridAutoPlay.addListenerRenderState` instead of `AppState`.
1317
- - **Timers stop on screen lock**: iOS stops all timers when the device main screen is turned off. To ensure timers continue to run (which is often necessary for background tasks related to autoplay), a patch for `react-native` is required. A patch is included in the root `patches/` directory and can be applied using `patch-package`.
1318
- In case you are using Expo SDK >= 56 make sure to set `buildReactNativeFromSource` to `true` in your app config for [expo-build-properties](https://docs.expo.dev/versions/latest/sdk/build-properties/#sharedbuildconfigfields), otherwise the patch can't be applied.
1319
1319
  - **expo-splash-screen stuck on iOS**: The `expo-splash-screen` module is broken on iOS because it does not support scenes, which are used by this library. This can cause the splash screen to be stuck on either the mobile device or on CarPlay. To fix this, a patch for `expo-splash-screen` is included in the root `patches/` directory and can be applied using `patch-package`. After applying the patch, you can hide the splash screen for a specific scene by passing the module name to the `hide` or `hideAsync` function. The module name can be one of the values from the `AutoPlayModules` enum or the UUID of a cluster screen.
1320
1320
  ```tsx
1321
1321
  import { hideAsync } from 'expo-splash-screen';
@@ -58,8 +58,6 @@
58
58
  </intent-filter>
59
59
  </service>
60
60
 
61
- <service android:name="com.margelo.nitro.swe.iternio.reactnativeautoplay.HeadlessTaskService" />
62
-
63
61
  <activity android:name="com.margelo.nitro.swe.iternio.reactnativeautoplay.SignInWithGoogleActivity" />
64
62
 
65
63
  <provider
@@ -74,8 +74,6 @@
74
74
  </intent-filter>
75
75
  </service>
76
76
 
77
- <service android:name="com.margelo.nitro.swe.iternio.reactnativeautoplay.HeadlessTaskService" />
78
-
79
77
  <activity android:name="com.margelo.nitro.swe.iternio.reactnativeautoplay.SignInWithGoogleActivity" />
80
78
 
81
79
  <provider
@@ -28,8 +28,6 @@
28
28
  <meta-data android:name="com.google.android.gms.car.application" android:resource="@xml/automotive_app_desc" tools:ignore="MetadataTagInsideApplicationTag" />
29
29
  <meta-data android:name="androidx.car.app.minCarApiLevel" android:value="1" />
30
30
 
31
- <service android:name="com.margelo.nitro.swe.iternio.reactnativeautoplay.HeadlessTaskService" />
32
-
33
31
  <provider android:name="com.margelo.nitro.swe.iternio.reactnativeautoplay.ActivityRenderStateProvider" android:authorities="${applicationId}.ActivityRenderStateProvider" android:exported="false" />
34
32
  </application>
35
33
  </manifest>
@@ -37,8 +37,6 @@
37
37
  <meta-data android:name="com.google.android.gms.car.application" android:resource="@xml/automotive_app_desc" tools:ignore="MetadataTagInsideApplicationTag" />
38
38
  <meta-data android:name="androidx.car.app.minCarApiLevel" android:value="1" />
39
39
 
40
- <service android:name="com.margelo.nitro.swe.iternio.reactnativeautoplay.HeadlessTaskService" />
41
-
42
40
  <provider android:name="com.margelo.nitro.swe.iternio.reactnativeautoplay.ActivityRenderStateProvider" android:authorities="${applicationId}.ActivityRenderStateProvider" android:exported="false" />
43
41
  </application>
44
42
  </manifest>
@@ -5,14 +5,10 @@ import android.annotation.SuppressLint
5
5
  import android.app.Notification
6
6
  import android.app.NotificationChannel
7
7
  import android.app.NotificationManager
8
- import android.content.ComponentName
9
- import android.content.Intent
10
- import android.content.ServiceConnection
11
8
  import android.content.pm.ApplicationInfo
12
9
  import android.content.pm.PackageManager
13
10
  import android.graphics.Bitmap
14
11
  import android.os.Build
15
- import android.os.IBinder
16
12
  import android.util.Log
17
13
  import androidx.car.app.CarAppService
18
14
  import androidx.car.app.Session
@@ -23,6 +19,7 @@ import androidx.core.app.NotificationCompat
23
19
  import androidx.core.app.NotificationManagerCompat
24
20
  import androidx.lifecycle.DefaultLifecycleObserver
25
21
  import androidx.lifecycle.LifecycleOwner
22
+ import com.facebook.react.ReactApplication
26
23
  import com.facebook.react.bridge.LifecycleEventListener
27
24
  import com.margelo.nitro.NitroModules
28
25
  import com.margelo.nitro.swe.iternio.reactnativeautoplay.utils.AppInfo
@@ -30,7 +27,6 @@ import com.margelo.nitro.swe.iternio.reactnativeautoplay.utils.AppInfo
30
27
  class AndroidAutoService : CarAppService() {
31
28
  private lateinit var notificationManager: NotificationManager
32
29
 
33
- private var isServiceBound = false
34
30
  private var isSessionStarted = false
35
31
  private var isReactAppStarted = false
36
32
 
@@ -48,6 +44,8 @@ class AndroidAutoService : CarAppService() {
48
44
  super.onCreate()
49
45
  instance = this
50
46
 
47
+ (application as? ReactApplication)?.reactHost?.start()
48
+
51
49
  NitroModules.applicationContext?.addLifecycleEventListener(reactLifecycleObserver)
52
50
 
53
51
  notificationManager = getSystemService(NotificationManager::class.java)
@@ -98,11 +96,6 @@ class AndroidAutoService : CarAppService() {
98
96
  }
99
97
 
100
98
  private val sessionLifecycleObserver = object : DefaultLifecycleObserver {
101
- override fun onCreate(owner: LifecycleOwner) {
102
- val serviceIntent = Intent(applicationContext, HeadlessTaskService::class.java)
103
- bindService(serviceIntent, connection, BIND_AUTO_CREATE)
104
- }
105
-
106
99
  override fun onResume(owner: LifecycleOwner) {
107
100
  isSessionStarted = true
108
101
  }
@@ -112,27 +105,10 @@ class AndroidAutoService : CarAppService() {
112
105
  }
113
106
 
114
107
  override fun onDestroy(owner: LifecycleOwner) {
115
- if (isServiceBound) {
116
- unbindService(connection)
117
- isServiceBound = false
118
- }
119
-
120
108
  this@AndroidAutoService.stopForeground(STOP_FOREGROUND_REMOVE)
121
109
  }
122
110
  }
123
111
 
124
- private val connection: ServiceConnection = object : ServiceConnection {
125
- override fun onServiceConnected(
126
- className: ComponentName, service: IBinder
127
- ) {
128
- isServiceBound = true
129
- }
130
-
131
- override fun onServiceDisconnected(arg0: ComponentName) {
132
- isServiceBound = false
133
- }
134
- }
135
-
136
112
  private fun createNotification(
137
113
  title: String?, text: String?, largeIcon: Bitmap?
138
114
  ): Notification {
@@ -0,0 +1,122 @@
1
+ package com.margelo.nitro.swe.iternio.reactnativeautoplay
2
+
3
+ import android.os.Handler
4
+ import android.os.Looper
5
+ import android.os.SystemClock
6
+ import java.lang.ref.WeakReference
7
+ import java.util.concurrent.ConcurrentHashMap
8
+ import java.util.concurrent.atomic.AtomicBoolean
9
+ import java.util.concurrent.atomic.AtomicLong
10
+
11
+ private class ScheduledTimer(
12
+ val callback: () -> Unit,
13
+ val interval: Long,
14
+ val repeats: Boolean,
15
+ var target: Long,
16
+ )
17
+
18
+ // Weak ref, so a stale instance (dev reload / host restart) can't tick forever in the queue.
19
+ private class TickRunnable(target: HybridAutoPlayTiming) : Runnable {
20
+ private val ref = WeakReference(target)
21
+
22
+ override fun run() {
23
+ ref.get()?.tick()
24
+ }
25
+ }
26
+
27
+ /**
28
+ * Backs setTimeout/setInterval (see AutoPlayTimers.ts) with a plain Handler loop on the main
29
+ * Looper -- not Choreographer, which JavaTimerManager itself uses and only keeps ticking while
30
+ * the host is resumed or a headless JS task is running. See AutoPlayTiming.nitro.ts.
31
+ *
32
+ * Ticks at a fixed ~60Hz while any timer is pending and stops entirely once idle, rather than
33
+ * scheduling a delay to the next due target: postDelayed's dispatch is gated on uptimeMillis(),
34
+ * which pauses during deep sleep, so a long pre-sleep delay would need that much *awake* time
35
+ * after waking. A short, repeated delay only needs ~16ms of awake time, so it fires within
36
+ * about one frame of the device waking regardless of sleep length -- due timers are then found
37
+ * correctly because target/now use elapsedRealtime(), which counts straight through sleep.
38
+ */
39
+ class HybridAutoPlayTiming : HybridAutoPlayTimingSpec() {
40
+ companion object {
41
+ private const val FRAME_DURATION_MS = 1000L / 60L
42
+
43
+ // RN's TimerManager also numbers ids from 1; offsetting avoids collisions with ids a
44
+ // pre-install caller (e.g. React's own scheduler) still holds against the original
45
+ // clearTimeout, now replaced.
46
+ private const val ID_OFFSET = 1_000_000_000L
47
+ }
48
+
49
+ private val handler = Handler(Looper.getMainLooper())
50
+ private val timers = ConcurrentHashMap<Double, ScheduledTimer>()
51
+ private val nextId = AtomicLong(ID_OFFSET)
52
+ private val isTicking = AtomicBoolean(false)
53
+ private val tickRunnable = TickRunnable(this)
54
+
55
+ private fun ensureTicking() {
56
+ if (isTicking.compareAndSet(false, true)) {
57
+ handler.postDelayed(tickRunnable, FRAME_DURATION_MS)
58
+ }
59
+ }
60
+
61
+ internal fun tick() {
62
+ // elapsedRealtime(), not uptimeMillis(): both are immune to NTP/manual clock changes,
63
+ // but unlike uptimeMillis() this one keeps counting through deep sleep.
64
+ val now = SystemClock.elapsedRealtime()
65
+
66
+ // Sort by (target, id): ConcurrentHashMap iteration order is unspecified, so
67
+ // setTimeout(a, 0); setTimeout(b, 0) could otherwise fire b before a.
68
+ val dueIds = timers.entries.filter { it.value.target <= now }
69
+ .sortedWith(compareBy({ it.value.target }, { it.key }))
70
+ .map { it.key }
71
+
72
+ for (id in dueIds) {
73
+ // Re-check membership: a same-tick callback may have cleared a later timer in
74
+ // this snapshotted list (e.g. `clearTimeout(t); t = setTimeout(...)`).
75
+ val timer = timers[id] ?: continue
76
+
77
+ if (timer.repeats) {
78
+ timer.target = now + timer.interval
79
+ } else {
80
+ timers.remove(id)
81
+ }
82
+
83
+ timer.callback()
84
+ }
85
+
86
+ if (timers.isNotEmpty()) {
87
+ handler.postDelayed(tickRunnable, FRAME_DURATION_MS)
88
+ return
89
+ }
90
+
91
+ isTicking.set(false)
92
+ // Reclaim: a concurrent createTimer() may have inserted an entry and found `isTicking`
93
+ // still true (skipping its own post) in the gap before the flag was cleared above.
94
+ if (timers.isNotEmpty()) {
95
+ ensureTicking()
96
+ }
97
+ }
98
+
99
+ override fun createTimer(callback: () -> Unit, durationMs: Double, repeats: Boolean): Double {
100
+ val interval = durationMs.toLong().coerceAtLeast(0)
101
+ val id = nextId.getAndIncrement().toDouble()
102
+ timers[id] = ScheduledTimer(
103
+ callback = callback,
104
+ interval = interval,
105
+ repeats = repeats,
106
+ target = SystemClock.elapsedRealtime() + interval,
107
+ )
108
+ ensureTicking()
109
+ return id
110
+ }
111
+
112
+ override fun deleteTimer(id: Double) {
113
+ timers.remove(id)
114
+ }
115
+
116
+ override fun dispose() {
117
+ handler.removeCallbacks(tickRunnable)
118
+ isTicking.set(false)
119
+ timers.clear()
120
+ super.dispose()
121
+ }
122
+ }
@@ -378,7 +378,7 @@ object Parser {
378
378
  }
379
379
  row.onPress?.let {
380
380
  setOnClickListener {
381
- row.onPress(null)
381
+ it(null)
382
382
  }
383
383
  }
384
384
  row.browsable?.let {
@@ -650,7 +650,7 @@ object Parser {
650
650
  // whose backing bitmap has already been recycled or failed to allocate;
651
651
  // copy() can also throw (e.g., OOM on very large remote images). Either
652
652
  // way we return null so the caller falls back to a placeholder icon.
653
- return image.underlyingBitmap.copy(Bitmap.Config.ARGB_8888, false)
653
+ return image.underlyingBitmap?.copy(Bitmap.Config.ARGB_8888, false)
654
654
  } else if (image is CloseableXml) {
655
655
  val drawable = image.buildDrawable()
656
656
  return drawable?.toBitmap(
@@ -0,0 +1,3 @@
1
+ // Root re-export so `@iternio/react-native-auto-play/installTimers` is a deliberate, explicitly
2
+ // published public entry point rather than a reach into src/ internals -- see src/installTimers.ts.
3
+ import './src/installTimers';
@@ -0,0 +1,2 @@
1
+ // Web/Jest counterpart to installTimers.ts, picked by Metro's platform resolution.
2
+ import './src/installTimers.web';
@@ -0,0 +1,123 @@
1
+ import Foundation
2
+ import NitroModules
3
+
4
+ private struct ScheduledTimer {
5
+ let callback: () -> Void
6
+ let interval: TimeInterval
7
+ let repeats: Bool
8
+ var target: TimeInterval
9
+ }
10
+
11
+ // Unlike ProcessInfo.systemUptime/mach_absolute_time(), keeps counting through sleep. RAW over
12
+ // plain CLOCK_MONOTONIC: also immune to NTP frequency-discipline adjustments.
13
+ private func now() -> TimeInterval {
14
+ TimeInterval(clock_gettime_nsec_np(CLOCK_MONOTONIC_RAW)) / 1_000_000_000
15
+ }
16
+
17
+ /// Backs setTimeout/setInterval (see AutoPlayTimers.ts) with a plain `Timer` -- not tied to
18
+ /// `CADisplayLink`/screen refresh, so it keeps firing while the phone screen is locked and
19
+ /// CarPlay is actively driving the external screen. See AutoPlayTiming.nitro.ts.
20
+ ///
21
+ /// Ticks at a fixed ~60Hz while any timer is pending and stops entirely once idle, rather than
22
+ /// scheduling a delay to the next due target: a `Timer`'s dispatch is gated on the run loop's
23
+ /// own monotonic clock, which (like `mach_absolute_time()`) pauses during sleep, so a long
24
+ /// pre-sleep delay would need that much *awake* time after waking. A short, repeated delay only
25
+ /// needs ~16ms of awake time, so it fires within about one frame of the device waking
26
+ /// regardless of sleep length.
27
+ class HybridAutoPlayTiming: HybridAutoPlayTimingSpec {
28
+ private static let frameDuration: TimeInterval = 1.0 / 60.0
29
+
30
+ // RN's TimerManager also numbers ids from 1; offsetting avoids collisions with ids a
31
+ // pre-install caller (e.g. React's own scheduler) still holds against the original
32
+ // clearTimeout, now replaced.
33
+ private static let idOffset: Double = 1_000_000_000
34
+
35
+ private let lock = NSLock()
36
+ private var timers = [Double: ScheduledTimer]()
37
+ private var nextId: Double = HybridAutoPlayTiming.idOffset
38
+ private var timer: Timer?
39
+
40
+ deinit {
41
+ timer?.invalidate()
42
+ }
43
+
44
+ private func withLock<T>(_ body: () -> T) -> T {
45
+ lock.lock()
46
+ defer { lock.unlock() }
47
+ return body()
48
+ }
49
+
50
+ // Must be called while already holding `lock`.
51
+ private func scheduleTick() {
52
+ let next = Timer(timeInterval: HybridAutoPlayTiming.frameDuration, repeats: false) { [weak self] _ in
53
+ self?.tick()
54
+ }
55
+ RunLoop.main.add(next, forMode: .common)
56
+ timer = next
57
+ }
58
+
59
+ private func tick() {
60
+ let currentTime = now()
61
+
62
+ // Sort by (target, id): Dictionary iteration order is unspecified, so
63
+ // setTimeout(a, 0); setTimeout(b, 0) could otherwise fire b before a.
64
+ let dueIds = withLock {
65
+ timers.filter { $0.value.target <= currentTime }
66
+ .sorted { lhs, rhs in
67
+ lhs.value.target != rhs.value.target
68
+ ? lhs.value.target < rhs.value.target
69
+ : lhs.key < rhs.key
70
+ }
71
+ .map(\.key)
72
+ }
73
+
74
+ for id in dueIds {
75
+ // Re-check membership: a same-tick callback may have cleared a later timer in
76
+ // this snapshotted list (e.g. `clearTimeout(t); t = setTimeout(...)`).
77
+ let callback: (() -> Void)? = withLock {
78
+ guard var entry = timers[id] else { return nil }
79
+ if entry.repeats {
80
+ entry.target = now() + entry.interval
81
+ timers[id] = entry
82
+ } else {
83
+ timers.removeValue(forKey: id)
84
+ }
85
+ return entry.callback
86
+ }
87
+
88
+ callback?()
89
+ }
90
+
91
+ withLock {
92
+ timer = nil
93
+ if !timers.isEmpty {
94
+ scheduleTick()
95
+ }
96
+ }
97
+ }
98
+
99
+ func createTimer(callback: @escaping () -> Void, durationMs: Double, repeats: Bool) throws -> Double {
100
+ let interval = max(durationMs, 0) / 1000.0
101
+
102
+ return withLock {
103
+ let id = nextId
104
+ nextId += 1
105
+ timers[id] = ScheduledTimer(
106
+ callback: callback,
107
+ interval: interval,
108
+ repeats: repeats,
109
+ target: now() + interval
110
+ )
111
+ if timer == nil {
112
+ scheduleTick()
113
+ }
114
+ return id
115
+ }
116
+ }
117
+
118
+ func deleteTimer(id: Double) throws {
119
+ withLock {
120
+ _ = timers.removeValue(forKey: id)
121
+ }
122
+ }
123
+ }
@@ -7,7 +7,7 @@ export const SafeAreaView = (props) => {
7
7
  return (_jsx(View, { style: [
8
8
  style,
9
9
  {
10
- ...StyleSheet.absoluteFillObject,
10
+ ...StyleSheet.absoluteFill,
11
11
  paddingTop: safeAreaInsets.top,
12
12
  paddingBottom: safeAreaInsets.bottom,
13
13
  paddingRight: safeAreaInsets.right,
@@ -0,0 +1,2 @@
1
+ import type { AutoPlayTiming } from '../specs/AutoPlayTiming.nitro';
2
+ export declare const HybridAutoPlayTiming: AutoPlayTiming;
@@ -0,0 +1,2 @@
1
+ import { NitroModules } from 'react-native-nitro-modules';
2
+ export const HybridAutoPlayTiming = NitroModules.createHybridObject('AutoPlayTiming');
@@ -5,8 +5,8 @@ const _native = NitroModules.createHybridObject('Voice');
5
5
  const startVoiceInput = async (options) => {
6
6
  const { onChunk, silenceThresholdMs, maxDurationMs, listeningText, listeningImage, preferSpeechToText, language, startSound, endSound, encoding, } = options ?? {};
7
7
  const listeningImageRepeats = listeningImage?.type === 'asset' ? listeningImage.repeats : undefined;
8
- const startSoundUri = startSound != null ? Image.resolveAssetSource(startSound).uri : undefined;
9
- const endSoundUri = endSound != null ? Image.resolveAssetSource(endSound).uri : undefined;
8
+ const startSoundUri = startSound != null ? Image.resolveAssetSource(startSound)?.uri : undefined;
9
+ const endSoundUri = endSound != null ? Image.resolveAssetSource(endSound)?.uri : undefined;
10
10
  return await _native.startVoiceInput(silenceThresholdMs, maxDurationMs, listeningText, NitroImageUtil.convert(listeningImage), listeningImageRepeats, preferSpeechToText, onChunk, language, startSoundUri, endSoundUri, encoding);
11
11
  };
12
12
  export const HybridVoice = {
package/lib/index.js CHANGED
@@ -1,11 +1,9 @@
1
1
  import { Platform } from 'react-native';
2
2
  import { NitroModules } from 'react-native-nitro-modules';
3
- import AutoPlayHeadlessJsTask from './AutoPlayHeadlessJsTask';
4
3
  import { HybridAndroidAutoTelemetry } from './hybrid/HybridAndroidAutoTelemetry';
5
4
  import { HybridAndroidWindowInformation } from './hybrid/HybridAndroidWindowInformation';
6
5
  import { HybridAutoPlay } from './hybrid/HybridAutoPlay';
7
6
  import { HybridVoice } from './hybrid/HybridVoice';
8
- AutoPlayHeadlessJsTask.registerHeadlessTask(HybridAutoPlay);
9
7
  export { HybridAndroidAutoTelemetry, HybridAndroidWindowInformation, HybridAutoPlay, HybridVoice };
10
8
  export const HybridAndroidAutomotive = Platform.OS === 'android'
11
9
  ? NitroModules.createHybridObject('AndroidAutomotive')
@@ -1,4 +1,4 @@
1
- import { View, type ViewProps } from 'react-native';
1
+ import { type ViewProps } from 'react-native';
2
2
  import type { AndroidAutomotive } from './specs/AndroidAutomotive.nitro';
3
3
  import type { AutoPlay } from './specs/AutoPlay.nitro';
4
4
  import type { Voice } from './specs/Voice.nitro';
@@ -44,7 +44,9 @@ export declare enum AutoPlayModules {
44
44
  CarPlayDashboard = "CarPlayDashboard"
45
45
  }
46
46
  export declare const useSafeAreaInsets: () => SafeAreaInsets;
47
- export declare const SafeAreaView: (props: ViewProps) => import("react").CElement<ViewProps, View>;
47
+ export declare const SafeAreaView: (props: ViewProps) => import("react").FunctionComponentElement<Omit<ViewProps, "ref"> & {
48
+ ref?: import("react").Ref<import("react-native").ViewInstance> | undefined;
49
+ }>;
48
50
  export declare function setIconFont(_name: string, _glyphMap?: Record<string, number>): void;
49
51
  export declare const useFocusedEffect: () => void;
50
52
  export declare const useVoiceInput: () => {
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,8 @@
1
+ // Side-effect-only entry point, re-exported at the package root as `installTimers` (see
2
+ // ../installTimers.ts) for `import '@iternio/react-native-auto-play/installTimers';` as the
3
+ // app's first import. installAutoPlayTimers() itself isn't part of the public API -- funneling
4
+ // installation through this one module is what actually guarantees "runs before anything else
5
+ // captures the original globals" (see the README) instead of just documenting it as a rule
6
+ // callers have to get right.
7
+ import { installAutoPlayTimers } from './utils/AutoPlayTimers';
8
+ installAutoPlayTimers();
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ // Web/Jest stub -- nothing to install there. See installTimers.ts.
2
+ export {};
@@ -28,9 +28,9 @@ declare class Dashboard {
28
28
  * @param eventType generic events
29
29
  * @returns callback to remove the listener
30
30
  */
31
- addListener(event: EventName, callback: () => void): import("../types/Event").CleanupCallback;
32
- addListenerRenderState(callback: (payload: VisibilityState) => void): import("../types/Event").CleanupCallback;
33
- addListenerColorScheme(callback: (payload: ColorScheme) => void): import("../types/Event").CleanupCallback;
31
+ addListener(event: EventName, callback: () => void): import("..").CleanupCallback;
32
+ addListenerRenderState(callback: (payload: VisibilityState) => void): import("..").CleanupCallback;
33
+ addListenerColorScheme(callback: (payload: ColorScheme) => void): import("..").CleanupCallback;
34
34
  }
35
35
  export declare const CarPlayDashboard: Dashboard;
36
36
  export {};
@@ -0,0 +1,27 @@
1
+ import type { HybridObject } from 'react-native-nitro-modules';
2
+ /**
3
+ * Backs setTimeout/setInterval with a scheduler that never pauses -- unlike RN's own JS
4
+ * timers, which RN throttles or pauses whenever the app backgrounds, regardless of whether
5
+ * the process is actually still running.
6
+ *
7
+ * iOS: CarPlay keeps this app's process alive and driving the external screen even when the
8
+ * phone's own screen is off, but RN's own RCTTiming still pauses in that state regardless.
9
+ *
10
+ * Android: JavaTimerManager only keeps ticking while the host is resumed *or* a headless JS
11
+ * task is running -- previously satisfied by registering a permanent no-op headless task
12
+ * (see AutoPlayHeadlessJsTask), which this replaces.
13
+ *
14
+ * All due-time bookkeeping lives here natively (mirroring RCTTiming's/JavaTimerManager's own
15
+ * architecture) so JS only crosses the bridge when a timer actually fires, not on every tick.
16
+ */
17
+ export interface AutoPlayTiming extends HybridObject<{
18
+ ios: 'swift';
19
+ android: 'kotlin';
20
+ }> {
21
+ /**
22
+ * Schedules `callback` to run after `durationMs`, repeating every `durationMs` if `repeats`
23
+ * is true. Returns an id to pass to `deleteTimer`.
24
+ */
25
+ createTimer(callback: () => void, durationMs: number, repeats: boolean): number;
26
+ deleteTimer(id: number): void;
27
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -1,4 +1,4 @@
1
- import type { Permission } from 'react-native/types';
1
+ import type { Permission } from 'react-native';
2
2
  export type AndroidAutoPermissions = Permission | AndroidAutoTelemetryPermissions | AndroidAutomotiveTelemetryPermissions;
3
3
  export declare enum AndroidAutoTelemetryPermissions {
4
4
  Speed = "com.google.android.gms.permission.CAR_SPEED",
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Replaces the global `setTimeout`/`setInterval`/`clearTimeout`/`clearInterval` and
3
+ * `requestAnimationFrame`/`cancelAnimationFrame` with implementations backed by the native
4
+ * `AutoPlayTiming` module, so they keep running while the app is actively driving a car
5
+ * surface even though the phone itself is backgrounded or its screen is locked. React
6
+ * Native's own timers throttle or pause in that state regardless of whether the process is
7
+ * actually still alive, which would otherwise stall ETA updates and telemetry polling.
8
+ *
9
+ * `requestIdleCallback`/`cancelIdleCallback` are deliberately not covered: bridgeless RN
10
+ * backs those with a separate native module unrelated to `setTimeout`/`requestAnimationFrame`
11
+ * (and its own callback delivery path is an unimplemented stub on iOS), so there is nothing
12
+ * for this library to intercept there.
13
+ *
14
+ * All due-time bookkeeping happens natively -- this is a thin pass-through, so JS only
15
+ * crosses the bridge when a timer actually fires, not on some fixed interval.
16
+ *
17
+ * Call this **once**, as early as possible in your app -- ideally the first line of your
18
+ * entry file, before any other import -- so nothing else has already captured a reference to
19
+ * the original globals. Safe to call more than once; only the first call has any effect.
20
+ */
21
+ export declare function installAutoPlayTimers(): void;
@@ -0,0 +1,45 @@
1
+ import { HybridAutoPlayTiming } from '../hybrid/HybridAutoPlayTiming';
2
+ let installed = false;
3
+ /**
4
+ * Replaces the global `setTimeout`/`setInterval`/`clearTimeout`/`clearInterval` and
5
+ * `requestAnimationFrame`/`cancelAnimationFrame` with implementations backed by the native
6
+ * `AutoPlayTiming` module, so they keep running while the app is actively driving a car
7
+ * surface even though the phone itself is backgrounded or its screen is locked. React
8
+ * Native's own timers throttle or pause in that state regardless of whether the process is
9
+ * actually still alive, which would otherwise stall ETA updates and telemetry polling.
10
+ *
11
+ * `requestIdleCallback`/`cancelIdleCallback` are deliberately not covered: bridgeless RN
12
+ * backs those with a separate native module unrelated to `setTimeout`/`requestAnimationFrame`
13
+ * (and its own callback delivery path is an unimplemented stub on iOS), so there is nothing
14
+ * for this library to intercept there.
15
+ *
16
+ * All due-time bookkeeping happens natively -- this is a thin pass-through, so JS only
17
+ * crosses the bridge when a timer actually fires, not on some fixed interval.
18
+ *
19
+ * Call this **once**, as early as possible in your app -- ideally the first line of your
20
+ * entry file, before any other import -- so nothing else has already captured a reference to
21
+ * the original globals. Safe to call more than once; only the first call has any effect.
22
+ */
23
+ export function installAutoPlayTimers() {
24
+ if (installed || HybridAutoPlayTiming == null) {
25
+ return;
26
+ }
27
+ installed = true;
28
+ const timing = HybridAutoPlayTiming;
29
+ const schedule = (repeats) => (callback, delay, ...args) => timing.createTimer(() => callback(...args), delay ?? 0, repeats);
30
+ const clear = (id) => {
31
+ if (typeof id === 'number') {
32
+ timing.deleteTimer(id);
33
+ }
34
+ };
35
+ globalThis.setTimeout = schedule(false);
36
+ globalThis.setInterval = schedule(true);
37
+ globalThis.clearTimeout = clear;
38
+ globalThis.clearInterval = clear;
39
+ // Mirrors bridgeless RN's own implementation: requestAnimationFrame is setTimeout(0) with
40
+ // a performance.now() timestamp handed to the callback, and cancelAnimationFrame deletes
41
+ // the same underlying timer clearTimeout would.
42
+ const now = () => globalThis.performance?.now() ?? Date.now();
43
+ globalThis.requestAnimationFrame = ((callback) => timing.createTimer(() => callback(now()), 0, false));
44
+ globalThis.cancelAnimationFrame = clear;
45
+ }
@@ -1,4 +1,3 @@
1
- import { type ImageResolvedAssetSource } from 'react-native';
2
1
  import type { AutoImage } from '../types/Image';
3
2
  import { type NitroColor } from './NitroColor';
4
3
  /**
@@ -22,7 +21,11 @@ import { type NitroColor } from './NitroColor';
22
21
  * ```
23
22
  */
24
23
  export declare function setIconFont(name: string, glyphMap?: Record<string, number>): void;
25
- interface AssetImage extends ImageResolvedAssetSource {
24
+ interface AssetImage {
25
+ uri: string;
26
+ width: number;
27
+ height: number;
28
+ scale: number;
26
29
  color?: NitroColor;
27
30
  packager_asset: boolean;
28
31
  }