@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.
- package/README.md +3 -3
- package/android/src/automotive/AndroidManifest-nonnav.xml +0 -2
- package/android/src/automotive/AndroidManifest.xml +0 -2
- package/android/src/main/AndroidManifest-nonnav.xml +0 -2
- package/android/src/main/AndroidManifest.xml +0 -2
- package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/AndroidAutoService.kt +3 -27
- package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridAutoPlayTiming.kt +122 -0
- package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/template/Parser.kt +2 -2
- package/installTimers.ts +3 -0
- package/installTimers.web.ts +2 -0
- package/ios/hybrid/HybridAutoPlayTiming.swift +123 -0
- package/lib/components/SafeAreaView.js +1 -1
- package/lib/hybrid/HybridAutoPlayTiming.d.ts +2 -0
- package/lib/hybrid/HybridAutoPlayTiming.js +2 -0
- package/lib/hybrid/HybridVoice.js +2 -2
- package/lib/index.js +0 -2
- package/lib/index.web.d.ts +4 -2
- package/lib/installTimers.d.ts +1 -0
- package/lib/installTimers.js +8 -0
- package/lib/installTimers.web.d.ts +1 -0
- package/lib/installTimers.web.js +2 -0
- package/lib/scenes/CarPlayDashboardScene.d.ts +3 -3
- package/lib/specs/AutoPlayTiming.nitro.d.ts +27 -0
- package/lib/specs/AutoPlayTiming.nitro.js +1 -0
- package/lib/types/Telemetry.d.ts +1 -1
- package/lib/utils/AutoPlayTimers.d.ts +21 -0
- package/lib/utils/AutoPlayTimers.js +45 -0
- package/lib/utils/NitroImage.d.ts +5 -2
- package/lib/utils/NitroImage.js +1 -1
- package/lib-cjs/components/SafeAreaView.js +1 -1
- package/lib-cjs/hybrid/HybridVoice.js +2 -2
- package/lib-cjs/index.js +0 -5
- package/lib-cjs/utils/NitroImage.js +1 -1
- package/nitro.json +10 -0
- package/nitrogen/generated/android/ReactNativeAutoPlay+autolinking.cmake +2 -0
- package/nitrogen/generated/android/ReactNativeAutoPlayOnLoad.cpp +16 -0
- package/nitrogen/generated/android/c++/JActiveCarUxRestrictions.hpp +1 -1
- package/nitrogen/generated/android/c++/JAlertActionStyle.hpp +1 -1
- package/nitrogen/generated/android/c++/JAlertDismissalReason.hpp +1 -1
- package/nitrogen/generated/android/c++/JAppFocusState.hpp +1 -1
- package/nitrogen/generated/android/c++/JAssetImage.hpp +18 -18
- package/nitrogen/generated/android/c++/JAutoText.hpp +1 -1
- package/nitrogen/generated/android/c++/JBooleanTelemetryItem.hpp +1 -1
- package/nitrogen/generated/android/c++/JCarUxRestrictions.hpp +1 -1
- package/nitrogen/generated/android/c++/JChargingConnector.hpp +1 -1
- package/nitrogen/generated/android/c++/JClusterEventName.hpp +1 -1
- package/nitrogen/generated/android/c++/JColorScheme.hpp +1 -1
- package/nitrogen/generated/android/c++/JDistance.hpp +1 -1
- package/nitrogen/generated/android/c++/JDistanceUnits.hpp +1 -1
- package/nitrogen/generated/android/c++/JDurationWithTimeZone.hpp +1 -1
- package/nitrogen/generated/android/c++/JEventName.hpp +1 -1
- package/nitrogen/generated/android/c++/JForkType.hpp +1 -1
- package/nitrogen/generated/android/c++/JGlyphImage.hpp +1 -1
- package/nitrogen/generated/android/c++/JGoogleSignIn.hpp +1 -1
- package/nitrogen/generated/android/c++/JGoogleSignInAccount.hpp +1 -1
- package/nitrogen/generated/android/c++/JGridImageSize.hpp +1 -1
- package/nitrogen/generated/android/c++/JGridTemplateConfig.hpp +1 -1
- package/nitrogen/generated/android/c++/JHybridAutoPlayTimingSpec.cpp +59 -0
- package/nitrogen/generated/android/c++/JHybridAutoPlayTimingSpec.hpp +64 -0
- package/nitrogen/generated/android/c++/JImageLane.hpp +1 -1
- package/nitrogen/generated/android/c++/JInformationTemplateConfig.hpp +1 -1
- package/nitrogen/generated/android/c++/JInputSignIn.hpp +1 -1
- package/nitrogen/generated/android/c++/JKeepType.hpp +1 -1
- package/nitrogen/generated/android/c++/JKeyboardType.hpp +1 -1
- package/nitrogen/generated/android/c++/JLaneGuidance.hpp +1 -1
- package/nitrogen/generated/android/c++/JListImageType.hpp +1 -1
- package/nitrogen/generated/android/c++/JListTemplateConfig.hpp +1 -1
- package/nitrogen/generated/android/c++/JLocation.hpp +1 -1
- package/nitrogen/generated/android/c++/JManeuverState.hpp +1 -1
- package/nitrogen/generated/android/c++/JManeuverType.hpp +1 -1
- package/nitrogen/generated/android/c++/JMapTemplateConfig.hpp +1 -1
- package/nitrogen/generated/android/c++/JMessageTemplateConfig.hpp +1 -1
- package/nitrogen/generated/android/c++/JNavigationAlertAction.hpp +1 -1
- package/nitrogen/generated/android/c++/JNitroAction.hpp +1 -1
- package/nitrogen/generated/android/c++/JNitroActionType.hpp +1 -1
- package/nitrogen/generated/android/c++/JNitroAlignment.hpp +1 -1
- package/nitrogen/generated/android/c++/JNitroAttributedString.hpp +1 -1
- package/nitrogen/generated/android/c++/JNitroAttributedStringImage.hpp +1 -1
- package/nitrogen/generated/android/c++/JNitroBaseMapTemplateConfig.hpp +1 -1
- package/nitrogen/generated/android/c++/JNitroButtonStyle.hpp +1 -1
- package/nitrogen/generated/android/c++/JNitroChargerLocation.hpp +1 -1
- package/nitrogen/generated/android/c++/JNitroChargerOutlet.hpp +1 -1
- package/nitrogen/generated/android/c++/JNitroColor.hpp +1 -1
- package/nitrogen/generated/android/c++/JNitroGridButton.hpp +1 -1
- package/nitrogen/generated/android/c++/JNitroLoadingManeuver.hpp +1 -1
- package/nitrogen/generated/android/c++/JNitroMapButton.hpp +1 -1
- package/nitrogen/generated/android/c++/JNitroMapButtonType.hpp +1 -1
- package/nitrogen/generated/android/c++/JNitroMessageManeuver.hpp +1 -1
- package/nitrogen/generated/android/c++/JNitroNavigationAlert.hpp +1 -1
- package/nitrogen/generated/android/c++/JNitroOptionsPanelChargerSection.hpp +1 -1
- package/nitrogen/generated/android/c++/JNitroOptionsPanelConfig.hpp +1 -1
- package/nitrogen/generated/android/c++/JNitroOptionsPanelGridSection.hpp +1 -1
- package/nitrogen/generated/android/c++/JNitroRoutingManeuver.hpp +1 -1
- package/nitrogen/generated/android/c++/JNitroRow.hpp +1 -1
- package/nitrogen/generated/android/c++/JNitroSection.hpp +1 -1
- package/nitrogen/generated/android/c++/JNitroSectionType.hpp +1 -1
- package/nitrogen/generated/android/c++/JNumericTelemetryItem.hpp +1 -1
- package/nitrogen/generated/android/c++/JOffRampType.hpp +1 -1
- package/nitrogen/generated/android/c++/JOnRampType.hpp +1 -1
- package/nitrogen/generated/android/c++/JPermissionRequestResult.hpp +1 -1
- package/nitrogen/generated/android/c++/JPinSignIn.hpp +1 -1
- package/nitrogen/generated/android/c++/JPoint.hpp +1 -1
- package/nitrogen/generated/android/c++/JPreferredImageLane.hpp +1 -1
- package/nitrogen/generated/android/c++/JQrSignIn.hpp +1 -1
- package/nitrogen/generated/android/c++/JRemoteImage.hpp +1 -1
- package/nitrogen/generated/android/c++/JRouteChoice.hpp +1 -1
- package/nitrogen/generated/android/c++/JSafeAreaInsets.hpp +1 -1
- package/nitrogen/generated/android/c++/JSearchTemplateConfig.hpp +1 -1
- package/nitrogen/generated/android/c++/JSignInMethods.hpp +1 -1
- package/nitrogen/generated/android/c++/JSignInTemplateConfig.hpp +1 -1
- package/nitrogen/generated/android/c++/JStringTelemetryItem.hpp +1 -1
- package/nitrogen/generated/android/c++/JTelemetry.hpp +1 -1
- package/nitrogen/generated/android/c++/JTextInputType.hpp +1 -1
- package/nitrogen/generated/android/c++/JTrafficSide.hpp +1 -1
- package/nitrogen/generated/android/c++/JTravelEstimates.hpp +1 -1
- package/nitrogen/generated/android/c++/JTripConfig.hpp +1 -1
- package/nitrogen/generated/android/c++/JTripPoint.hpp +1 -1
- package/nitrogen/generated/android/c++/JTripPreviewTextConfiguration.hpp +1 -1
- package/nitrogen/generated/android/c++/JTripSelectorCallback.hpp +1 -1
- package/nitrogen/generated/android/c++/JTripsConfig.hpp +1 -1
- package/nitrogen/generated/android/c++/JTurnType.hpp +1 -1
- package/nitrogen/generated/android/c++/JVehicleTelemetryItem.hpp +1 -1
- package/nitrogen/generated/android/c++/JVisibilityState.hpp +1 -1
- package/nitrogen/generated/android/c++/JVisibleTravelEstimate.hpp +1 -1
- package/nitrogen/generated/android/c++/JVoiceAudioEncoding.hpp +1 -1
- package/nitrogen/generated/android/c++/JVoiceInputChunk.hpp +1 -1
- package/nitrogen/generated/android/c++/JVoiceInputResult.hpp +1 -1
- package/nitrogen/generated/android/c++/JWaypointCoordinate.hpp +1 -1
- package/nitrogen/generated/android/c++/JWindowInformation.hpp +1 -1
- package/nitrogen/generated/android/c++/JZoomEvent.hpp +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/AssetImage.kt +15 -15
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_ActiveCarUxRestrictions.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_AlertDismissalReason.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_AppFocusState.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_ColorScheme.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_Point.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_Point_double.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_Point_std__optional_Point_.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_SafeAreaInsets.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_VisibilityState.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_VoiceInputChunk.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_WindowInformation.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_bool.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_std__optional_Location__std__optional_std__string_.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_std__optional_Telemetry_.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_std__optional_bool_.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_std__optional_std__string__std__optional_GoogleSignInAccount_.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_std__string.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_std__string_ColorScheme.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_std__string_ZoomEvent.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_std__string_bool.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_std__string_std__string.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridAndroidAutoTelemetrySpec.kt +2 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridAndroidAutomotiveSpec.kt +2 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridAndroidWindowInformationSpec.kt +2 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridAutoPlaySpec.kt +2 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridAutoPlayTimingSpec.kt +65 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridClusterSpec.kt +2 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridGridTemplateSpec.kt +2 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridInformationTemplateSpec.kt +2 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridListTemplateSpec.kt +2 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridMapTemplateSpec.kt +2 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridMessageTemplateSpec.kt +2 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridSearchTemplateSpec.kt +2 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridSignInTemplateSpec.kt +2 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridVoiceSpec.kt +2 -0
- package/nitrogen/generated/ios/ReactNativeAutoPlay-Swift-Cxx-Bridge.cpp +17 -0
- package/nitrogen/generated/ios/ReactNativeAutoPlay-Swift-Cxx-Bridge.hpp +35 -9
- package/nitrogen/generated/ios/ReactNativeAutoPlay-Swift-Cxx-Umbrella.hpp +5 -0
- package/nitrogen/generated/ios/ReactNativeAutoPlayAutolinking.mm +8 -0
- package/nitrogen/generated/ios/ReactNativeAutoPlayAutolinking.swift +12 -0
- package/nitrogen/generated/ios/c++/HybridAutoPlayTimingSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridAutoPlayTimingSpecSwift.hpp +88 -0
- package/nitrogen/generated/ios/swift/AssetImage.swift +13 -13
- package/nitrogen/generated/ios/swift/HybridAutoPlayTimingSpec.swift +56 -0
- package/nitrogen/generated/ios/swift/HybridAutoPlayTimingSpec_cxx.swift +154 -0
- package/nitrogen/generated/shared/c++/AssetImage.hpp +18 -18
- package/nitrogen/generated/shared/c++/HybridAutoPlayTimingSpec.cpp +22 -0
- package/nitrogen/generated/shared/c++/HybridAutoPlayTimingSpec.hpp +63 -0
- package/package.json +6 -4
- package/src/components/SafeAreaView.tsx +1 -1
- package/src/hybrid/HybridAutoPlayTiming.ts +5 -0
- package/src/hybrid/HybridVoice.ts +2 -2
- package/src/index.ts +0 -3
- package/src/installTimers.ts +9 -0
- package/src/installTimers.web.ts +2 -0
- package/src/specs/AutoPlayTiming.nitro.ts +25 -0
- package/src/types/Telemetry.ts +1 -1
- package/src/utils/AutoPlayTimers.ts +60 -0
- package/src/utils/NitroImage.ts +13 -3
- package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/HeadlessTaskService.kt +0 -36
- package/lib/AutoPlayHeadlessJsTask.d.ts +0 -5
- package/lib/AutoPlayHeadlessJsTask.js +0 -14
- package/lib-cjs/AutoPlayHeadlessJsTask.js +0 -16
- 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`).
|
|
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
|
+
}
|
package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/template/Parser.kt
CHANGED
|
@@ -378,7 +378,7 @@ object Parser {
|
|
|
378
378
|
}
|
|
379
379
|
row.onPress?.let {
|
|
380
380
|
setOnClickListener {
|
|
381
|
-
|
|
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
|
|
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(
|
package/installTimers.ts
ADDED
|
@@ -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.
|
|
10
|
+
...StyleSheet.absoluteFill,
|
|
11
11
|
paddingTop: safeAreaInsets.top,
|
|
12
12
|
paddingBottom: safeAreaInsets.bottom,
|
|
13
13
|
paddingRight: safeAreaInsets.right,
|
|
@@ -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)
|
|
9
|
-
const endSoundUri = endSound != null ? Image.resolveAssetSource(endSound)
|
|
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')
|
package/lib/index.web.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
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").
|
|
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 {};
|
|
@@ -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("
|
|
32
|
-
addListenerRenderState(callback: (payload: VisibilityState) => void): import("
|
|
33
|
-
addListenerColorScheme(callback: (payload: ColorScheme) => void): import("
|
|
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 {};
|
package/lib/types/Telemetry.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Permission } from 'react-native
|
|
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
|
|
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
|
}
|