@iternio/react-native-auto-play 0.6.0 → 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 +59 -10
- 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 +49 -14
- package/installTimers.ts +3 -0
- package/installTimers.web.ts +2 -0
- package/ios/hybrid/HybridAutoPlayTiming.swift +123 -0
- package/jest.js +2 -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 +75 -0
- package/lib/index.web.js +72 -1
- 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/Image.d.ts +6 -1
- 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/NitroColor.d.ts +1 -0
- package/lib/utils/NitroColor.js +8 -0
- package/lib/utils/NitroImage.d.ts +5 -2
- package/lib/utils/NitroImage.js +2 -2
- package/lib/utils/NitroManeuver.js +1 -3
- package/lib-cjs/Constants.js +9 -0
- package/lib-cjs/components/MapTemplateContext.js +10 -0
- package/lib-cjs/components/SafeAreaInsetsContext.js +21 -0
- package/lib-cjs/components/SafeAreaView.js +22 -0
- package/lib-cjs/components/WindowInformationWrapper.js +20 -0
- package/lib-cjs/hooks/useAndroidAutoTelemetry.js +115 -0
- package/lib-cjs/hooks/useFocusedEffect.js +35 -0
- package/lib-cjs/hooks/useMapTemplate.js +13 -0
- package/lib-cjs/hooks/useSafeAreaInsets.js +9 -0
- package/lib-cjs/hooks/useVoiceInput.js +42 -0
- package/lib-cjs/hybrid/HybridAndroidAutoTelemetry.js +4 -0
- package/lib-cjs/hybrid/HybridAndroidWindowInformation.js +4 -0
- package/lib-cjs/hybrid/HybridAutoPlay.js +5 -0
- package/lib-cjs/hybrid/HybridVoice.js +61 -0
- package/lib-cjs/index.js +71 -0
- package/lib-cjs/index.web.js +98 -0
- package/lib-cjs/scenes/AutoPlayCluster.js +140 -0
- package/lib-cjs/scenes/CarPlayDashboardScene.js +100 -0
- package/lib-cjs/specs/AndroidAutoTelemetry.nitro.js +2 -0
- package/lib-cjs/specs/AndroidAutomotive.nitro.js +16 -0
- package/lib-cjs/specs/AndroidWindowInformation.nitro.js +2 -0
- package/lib-cjs/specs/AutoPlay.nitro.js +2 -0
- package/lib-cjs/specs/CarPlayDashboard.nitro.js +2 -0
- package/lib-cjs/specs/Cluster.nitro.js +2 -0
- package/lib-cjs/specs/GridTemplate.nitro.js +2 -0
- package/lib-cjs/specs/InformationTemplate.nitro.js +2 -0
- package/lib-cjs/specs/ListTemplate.nitro.js +2 -0
- package/lib-cjs/specs/MapTemplate.nitro.js +2 -0
- package/lib-cjs/specs/MessageTemplate.nitro.js +2 -0
- package/lib-cjs/specs/SearchTemplate.nitro.js +2 -0
- package/lib-cjs/specs/SignInTemplate.nitro.js +2 -0
- package/lib-cjs/specs/Voice.nitro.js +2 -0
- package/lib-cjs/templates/GridTemplate.js +41 -0
- package/lib-cjs/templates/InformationTemplate.js +49 -0
- package/lib-cjs/templates/ListTemplate.js +33 -0
- package/lib-cjs/templates/MapTemplate.js +168 -0
- package/lib-cjs/templates/MessageTemplate.js +50 -0
- package/lib-cjs/templates/SearchTemplate.js +32 -0
- package/lib-cjs/templates/SignInTemplate.js +55 -0
- package/lib-cjs/templates/Template.js +40 -0
- package/lib-cjs/types/Button.js +12 -0
- package/lib-cjs/types/Event.js +2 -0
- package/lib-cjs/types/Image.js +2 -0
- package/lib-cjs/types/Maneuver.js +77 -0
- package/lib-cjs/types/RootComponent.js +2 -0
- package/lib-cjs/types/SignInMethod.js +22 -0
- package/lib-cjs/types/Telemetry.js +24 -0
- package/lib-cjs/types/Text.js +8 -0
- package/lib-cjs/types/Trip.js +2 -0
- package/lib-cjs/types/Voice.js +2 -0
- package/lib-cjs/utils/ErrorUtil.js +34 -0
- package/lib-cjs/utils/NitroAction.js +129 -0
- package/lib-cjs/utils/NitroAlert.js +19 -0
- package/lib-cjs/utils/NitroAttributedString.js +14 -0
- package/lib-cjs/utils/NitroColor.js +32 -0
- package/lib-cjs/utils/NitroGrid.js +12 -0
- package/lib-cjs/utils/NitroImage.js +97 -0
- package/lib-cjs/utils/NitroManeuver.js +79 -0
- package/lib-cjs/utils/NitroMapButton.js +33 -0
- package/lib-cjs/utils/NitroOptionsPanel.js +66 -0
- package/lib-cjs/utils/NitroSection.js +112 -0
- 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 +9 -5
- 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/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/NitroColor.kt +9 -4
- 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/ios/swift/NitroColor.swift +20 -2
- 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/nitrogen/generated/shared/c++/NitroColor.hpp +7 -3
- package/package.json +12 -6
- 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/index.web.ts +166 -0
- package/src/installTimers.ts +9 -0
- package/src/installTimers.web.ts +2 -0
- package/src/specs/AutoPlayTiming.nitro.ts +25 -0
- package/src/types/Image.ts +6 -1
- package/src/types/Telemetry.ts +1 -1
- package/src/utils/AutoPlayTimers.ts +60 -0
- package/src/utils/NitroColor.ts +10 -1
- package/src/utils/NitroImage.ts +14 -8
- package/src/utils/NitroManeuver.ts +1 -4
- 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/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
|
|
|
@@ -48,8 +49,8 @@
|
|
|
48
49
|
|
|
49
50
|
#### Bundle identifier
|
|
50
51
|
To get the CarPlay app showing up you need to set a proper Bundle Identifier:
|
|
51
|
-
- Open
|
|
52
|
-
- Select
|
|
52
|
+
- Open your app's `.xcodeproj` in Xcode.
|
|
53
|
+
- Select your app target, go to the **Signing & Capabilities** tab.
|
|
53
54
|
- Under **Signing > Bundle Identifier**, enter your unique bundle ID (e.g., `at.g4rb4g3.autoplay.example`).
|
|
54
55
|
|
|
55
56
|
#### Entitlements
|
|
@@ -178,7 +179,7 @@ This is an example that works for bare react-native (>= 0.82) and Expo SDK 57, c
|
|
|
178
179
|
It is recommended to attach a listener to MapTemplate.onAppearanceDidChange and send maneuver updates based on this to make sure the colors are applied properly.
|
|
179
180
|
Reason for this is that CarPlay does not allow for color updates on maneuvers shown on the screen. You need to send maneuvers with a new id to get them updated properly on the screen.
|
|
180
181
|
The color properties do not need to handle the mode change, best practice is to use ThemedColor whenever possible and set appropriate light and dark mode colors.
|
|
181
|
-
This is mainly required on CarPlay
|
|
182
|
+
This is mainly required on CarPlay. Android Auto redraws on its own when the day/night state changes, but note that Android Auto 17.8 introduced white templates in day mode while older versions always show dark templates. The car's day/night state (`isDarkMode`) is the same on both, so it does not tell you which template color you are drawn on. Use the `'default'` color for icons that have to stay readable in both cases, see **Icon colors and Android Auto light templates**.
|
|
182
183
|
|
|
183
184
|
#### CPListTemplate day/night header
|
|
184
185
|
|
|
@@ -293,13 +294,21 @@ This library also supports Android Automotive. To enable Android Automotive supp
|
|
|
293
294
|
|
|
294
295
|
- **`isAutomotiveApp` flag**: You need to inform the library if this is an Automotive app by setting the `isAutomotiveApp` property to `true`. For Android Auto, it should be `false`.
|
|
295
296
|
|
|
296
|
-
You can set these properties directly in your `android/gradle.properties` file
|
|
297
|
+
You can set these properties directly in your `android/gradle.properties` file. **Note the
|
|
298
|
+
`ReactNativeAutoPlay_` prefix** — the library reads `rootProject.ext.<name>` first and falls
|
|
299
|
+
back to the prefixed project property, so an unprefixed `isAutomotiveApp=true` in
|
|
300
|
+
`gradle.properties` is silently ignored and you get an Android Auto build instead:
|
|
301
|
+
|
|
297
302
|
```properties
|
|
298
303
|
# For Android Automotive
|
|
299
|
-
|
|
300
|
-
|
|
304
|
+
ReactNativeAutoPlay_minSdkVersion=29
|
|
305
|
+
ReactNativeAutoPlay_isAutomotiveApp=true
|
|
301
306
|
```
|
|
302
307
|
|
|
308
|
+
If your app's `android/build.gradle` already defines `ext.minSdkVersion` (the React Native
|
|
309
|
+
template does), that `rootProject.ext` value wins over the property above — raise it there
|
|
310
|
+
instead.
|
|
311
|
+
|
|
303
312
|
Alternatively, if you need to support different build variants (e.g., for both Android Auto and Android Automotive from the same codebase), using `react-native-config` is the recommended approach.
|
|
304
313
|
|
|
305
314
|
1. Install `react-native-config`:
|
|
@@ -443,14 +452,34 @@ It is also possible to use custom bundled images (e.g. PNG, WEBP or Vector Drawa
|
|
|
443
452
|
- iOS: Add to your `Images.xcassets`
|
|
444
453
|
- Android: Add to `res/drawable`
|
|
445
454
|
|
|
455
|
+
### Icon colors and Android Auto light templates
|
|
456
|
+
|
|
457
|
+
Starting with **Android Auto 17.8** the host can show white (light) templates in day mode. Older versions (e.g. 17.6) always use dark templates, even in day mode. Both report the same car app API level, so an app cannot tell them apart, and a fixed icon color that is readable on one (white on dark) can be invisible on the other (white on white).
|
|
458
|
+
|
|
459
|
+
Use the color `'default'` for every monochrome icon that has to stay readable in both cases:
|
|
460
|
+
|
|
461
|
+
```ts
|
|
462
|
+
{ type: 'glyph', name: 'search', color: 'default' }
|
|
463
|
+
{ type: 'asset', image: require('./icon.png'), color: 'default' }
|
|
464
|
+
{ type: 'remote', uri: 'https://example.com/icon.png', color: 'default' }
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
- **Android Auto**: the host tints the icon with its own default icon color for the template it is currently showing, so it follows dark and light templates on every Android Auto version.
|
|
468
|
+
- **CarPlay**: `'default'` resolves to black in light mode and white in dark mode, so it is safe to use on iOS and does not change anything there.
|
|
469
|
+
- **Glyphs** use `'default'` automatically when no `color` is set. Exception on Android Auto: a glyph with a non-transparent `backgroundColor` is not tinted, since the tint would recolor the background as well. It keeps the plain white (dark mode) / black (light mode) glyph color, so set `color` explicitly if that does not contrast with your background.
|
|
470
|
+
- **Asset and remote images** are not tinted unless you set a `color`, so colorful images such as a logo keep their original colors. Only pass `'default'` for monochrome icons.
|
|
471
|
+
- Any other color (a string or a `ThemedColor`) is applied as specified. Only use those where the color works on both dark and light templates, e.g. a colored icon.
|
|
472
|
+
- Known limitation: the host may not apply the tint to header action icons on Android Auto 17.8. That is an issue in Android Auto itself, not something the library can work around.
|
|
473
|
+
|
|
446
474
|
## Usage
|
|
447
475
|
|
|
448
476
|
### 1. Register the AutoPlay Components
|
|
449
477
|
|
|
450
|
-
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:
|
|
451
479
|
|
|
452
480
|
```javascript
|
|
453
481
|
// index.js
|
|
482
|
+
import '@iternio/react-native-auto-play/installTimers';
|
|
454
483
|
import { AppRegistry } from 'react-native';
|
|
455
484
|
import { name as appName } from './app.json';
|
|
456
485
|
import App from './src/App';
|
|
@@ -576,7 +605,7 @@ All root components rendered by templates/scenes receive `RootComponentInitialPr
|
|
|
576
605
|
|
|
577
606
|
- `id`: Module identifier (e.g. `AutoPlayRoot`, `CarPlayDashboard`, or a cluster UUID).
|
|
578
607
|
- `rootTag`: React Native root tag.
|
|
579
|
-
- `colorScheme`: `'light' | 'dark'` initial color scheme (listen to `onAppearanceDidChange` on `MapTemplate` for updates).
|
|
608
|
+
- `colorScheme`: `'light' | 'dark'` initial color scheme (listen to `onAppearanceDidChange` on `MapTemplate` for updates). On Android Auto this is the car's day/night state and does not tell you whether the templates are dark or white (17.8+ can show white templates in day mode, older versions never do).
|
|
580
609
|
- `window`: `{ width, height, scale }`.
|
|
581
610
|
|
|
582
611
|
### Template Configs (Props)
|
|
@@ -1259,14 +1288,34 @@ CarPlayDashboard.setButtons([
|
|
|
1259
1288
|
- `setAttributedInactiveDescriptionVariants(variants)` — iOS only inactive text.
|
|
1260
1289
|
- `addListenerColorScheme(cb)` / `addListenerZoom(cb)` / `addListenerCompass(cb)` / `addListenerSpeedLimit(cb)`.
|
|
1261
1290
|
|
|
1291
|
+
## Testing with Jest
|
|
1292
|
+
|
|
1293
|
+
The real package needs native modules and ships ESM, so it can't run under Jest. Use the bundled CommonJS mock instead, one line in your Jest setup file:
|
|
1294
|
+
|
|
1295
|
+
```js
|
|
1296
|
+
// jest.setup.js
|
|
1297
|
+
jest.mock('@iternio/react-native-auto-play', () =>
|
|
1298
|
+
require('@iternio/react-native-auto-play/jest')
|
|
1299
|
+
);
|
|
1300
|
+
```
|
|
1301
|
+
|
|
1302
|
+
Templates, `HybridAutoPlay`, `HybridVoice`, `AutoPlayCluster`, `CarPlayDashboard` and the hooks that need a car surface are safe no-ops (any method call returns `undefined`), `Constants.isIos27OrGreater` is `false`, and all types are unchanged. Tests that need to record constructions or assert on calls should extend it per test file:
|
|
1303
|
+
|
|
1304
|
+
```ts
|
|
1305
|
+
jest.mock('@iternio/react-native-auto-play', () => {
|
|
1306
|
+
const actual = jest.requireActual('@iternio/react-native-auto-play/jest');
|
|
1307
|
+
return { ...actual, ListTemplate: class { push = jest.fn(() => Promise.resolve()); } };
|
|
1308
|
+
});
|
|
1309
|
+
```
|
|
1310
|
+
|
|
1311
|
+
The same no-op surface is what `react-native-web` builds get automatically via `index.web.ts`.
|
|
1312
|
+
|
|
1262
1313
|
## Known Issues
|
|
1263
1314
|
|
|
1264
1315
|
### iOS
|
|
1265
1316
|
|
|
1266
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).
|
|
1267
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`.
|
|
1268
|
-
- **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`.
|
|
1269
|
-
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.
|
|
1270
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.
|
|
1271
1320
|
```tsx
|
|
1272
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
|
@@ -36,6 +36,7 @@ import androidx.car.app.navigation.model.TravelEstimate
|
|
|
36
36
|
import androidx.core.graphics.createBitmap
|
|
37
37
|
import androidx.core.graphics.drawable.IconCompat
|
|
38
38
|
import androidx.core.graphics.drawable.toBitmap
|
|
39
|
+
import androidx.core.net.toUri
|
|
39
40
|
import com.facebook.datasource.DataSources
|
|
40
41
|
import com.facebook.drawee.backends.pipeline.Fresco
|
|
41
42
|
import com.facebook.imagepipeline.image.CloseableBitmap
|
|
@@ -51,8 +52,8 @@ import com.margelo.nitro.swe.iternio.reactnativeautoplay.DurationWithTimeZone
|
|
|
51
52
|
import com.margelo.nitro.swe.iternio.reactnativeautoplay.ForkType
|
|
52
53
|
import com.margelo.nitro.swe.iternio.reactnativeautoplay.GlyphImage
|
|
53
54
|
import com.margelo.nitro.swe.iternio.reactnativeautoplay.KeepType
|
|
54
|
-
import com.margelo.nitro.swe.iternio.reactnativeautoplay.ListTemplateConfig
|
|
55
55
|
import com.margelo.nitro.swe.iternio.reactnativeautoplay.ListImageType
|
|
56
|
+
import com.margelo.nitro.swe.iternio.reactnativeautoplay.ListTemplateConfig
|
|
56
57
|
import com.margelo.nitro.swe.iternio.reactnativeautoplay.ManeuverType
|
|
57
58
|
import com.margelo.nitro.swe.iternio.reactnativeautoplay.NitroAction
|
|
58
59
|
import com.margelo.nitro.swe.iternio.reactnativeautoplay.NitroActionType
|
|
@@ -82,7 +83,6 @@ import java.util.Calendar
|
|
|
82
83
|
import java.util.Locale
|
|
83
84
|
import java.util.TimeZone
|
|
84
85
|
import kotlin.math.abs
|
|
85
|
-
import androidx.core.net.toUri
|
|
86
86
|
|
|
87
87
|
object Parser {
|
|
88
88
|
// IMAGE_TYPE_MEDIUM was added to androidx.car.app in 1.8.0. Keep the protocol value here
|
|
@@ -182,7 +182,11 @@ object Parser {
|
|
|
182
182
|
}.build()
|
|
183
183
|
}
|
|
184
184
|
|
|
185
|
-
fun parseAction(
|
|
185
|
+
fun parseAction(
|
|
186
|
+
context: CarContext,
|
|
187
|
+
action: NitroAction,
|
|
188
|
+
useParkedOnlyClickListener: Boolean = false
|
|
189
|
+
): Action {
|
|
186
190
|
if (action.type == NitroActionType.APPICON) {
|
|
187
191
|
return Action.APP_ICON
|
|
188
192
|
}
|
|
@@ -219,11 +223,21 @@ object Parser {
|
|
|
219
223
|
}
|
|
220
224
|
|
|
221
225
|
fun parseImage(context: CarContext, image: Variant_GlyphImage_AssetImage_RemoteImage): CarIcon {
|
|
222
|
-
return parseImage(
|
|
226
|
+
return parseImage(
|
|
227
|
+
context,
|
|
228
|
+
image.asFirstOrNull(),
|
|
229
|
+
image.asSecondOrNull(),
|
|
230
|
+
image.asThirdOrNull()
|
|
231
|
+
)
|
|
223
232
|
}
|
|
224
233
|
|
|
225
234
|
fun parseImage(context: CarContext, image: NitroImage): CarIcon {
|
|
226
|
-
return parseImage(
|
|
235
|
+
return parseImage(
|
|
236
|
+
context,
|
|
237
|
+
image.asFirstOrNull(),
|
|
238
|
+
image.asSecondOrNull(),
|
|
239
|
+
image.asThirdOrNull()
|
|
240
|
+
)
|
|
227
241
|
}
|
|
228
242
|
|
|
229
243
|
fun parseImage(
|
|
@@ -234,8 +248,19 @@ object Parser {
|
|
|
234
248
|
): CarIcon {
|
|
235
249
|
val bitmap = parseImageToBitmap(context, glyphImage, assetImage, remoteImage)
|
|
236
250
|
|
|
251
|
+
// the tint recolors every opaque pixel, so it would also fill the background drawn in SymbolFont
|
|
252
|
+
val hasGlyphBackground =
|
|
253
|
+
glyphImage != null && (glyphImage.backgroundColor.get(context) ushr 24) != 0
|
|
254
|
+
|
|
255
|
+
val applyDefaultTint = !hasGlyphBackground && (glyphImage?.color?.isDefault
|
|
256
|
+
?: assetImage?.color?.isDefault ?: remoteImage?.color?.isDefault ?: false)
|
|
257
|
+
|
|
237
258
|
bitmap?.let {
|
|
238
|
-
return CarIcon.Builder(IconCompat.createWithBitmap(it)).
|
|
259
|
+
return CarIcon.Builder(IconCompat.createWithBitmap(it)).apply {
|
|
260
|
+
if (applyDefaultTint) {
|
|
261
|
+
setTint(CarColor.DEFAULT)
|
|
262
|
+
}
|
|
263
|
+
}.build()
|
|
239
264
|
}
|
|
240
265
|
|
|
241
266
|
// remote images might fail to load so we provide some placeholder then
|
|
@@ -353,7 +378,7 @@ object Parser {
|
|
|
353
378
|
}
|
|
354
379
|
row.onPress?.let {
|
|
355
380
|
setOnClickListener {
|
|
356
|
-
|
|
381
|
+
it(null)
|
|
357
382
|
}
|
|
358
383
|
}
|
|
359
384
|
row.browsable?.let {
|
|
@@ -610,10 +635,14 @@ object Parser {
|
|
|
610
635
|
private fun fetchSync(context: CarContext, imageRequest: ImageRequest): Bitmap? {
|
|
611
636
|
val dataSource = try {
|
|
612
637
|
Fresco.getImagePipeline().fetchDecodedImage(imageRequest, context)
|
|
613
|
-
} catch (_: Exception) {
|
|
638
|
+
} catch (_: Exception) {
|
|
639
|
+
return null
|
|
640
|
+
}
|
|
614
641
|
val result = try {
|
|
615
642
|
DataSources.waitForFinalResult(dataSource)
|
|
616
|
-
} catch (_: Exception) {
|
|
643
|
+
} catch (_: Exception) {
|
|
644
|
+
dataSource.close(); return null
|
|
645
|
+
}
|
|
617
646
|
val image = result?.get()
|
|
618
647
|
try {
|
|
619
648
|
if (image is CloseableBitmap) {
|
|
@@ -624,7 +653,11 @@ object Parser {
|
|
|
624
653
|
return image.underlyingBitmap?.copy(Bitmap.Config.ARGB_8888, false)
|
|
625
654
|
} else if (image is CloseableXml) {
|
|
626
655
|
val drawable = image.buildDrawable()
|
|
627
|
-
return drawable?.toBitmap(
|
|
656
|
+
return drawable?.toBitmap(
|
|
657
|
+
width = image.width,
|
|
658
|
+
height = image.height,
|
|
659
|
+
Bitmap.Config.ARGB_8888
|
|
660
|
+
)
|
|
628
661
|
}
|
|
629
662
|
} catch (_: Exception) {
|
|
630
663
|
// Any decode/copy failure (OOM, recycled bitmap, invalid config, …) should
|
|
@@ -759,10 +792,12 @@ object Parser {
|
|
|
759
792
|
}
|
|
760
793
|
nitroManeuver.angle?.let { roundaboutExitAngle ->
|
|
761
794
|
if (nitroManeuver.trafficSide == TrafficSide.LEFT) {
|
|
762
|
-
val angle = ((180 + roundaboutExitAngle) % 360).toInt()
|
|
795
|
+
val angle = ((180 + roundaboutExitAngle) % 360).toInt()
|
|
796
|
+
.let { if (it == 0) 360 else it }
|
|
763
797
|
setRoundaboutExitAngle(angle)
|
|
764
798
|
} else {
|
|
765
|
-
val angle = ((180 - roundaboutExitAngle) % 360).toInt()
|
|
799
|
+
val angle = ((180 - roundaboutExitAngle) % 360).toInt()
|
|
800
|
+
.let { if (it == 0) 360 else it }
|
|
766
801
|
setRoundaboutExitAngle(angle)
|
|
767
802
|
}
|
|
768
803
|
}
|
|
@@ -841,7 +876,7 @@ object Parser {
|
|
|
841
876
|
mapConfig.mapButtons?.let { mapButtons ->
|
|
842
877
|
setMapController(
|
|
843
878
|
MapController.Builder().apply {
|
|
844
|
-
setMapActionStrip(
|
|
879
|
+
setMapActionStrip(parseMapActions(context, mapButtons)).build()
|
|
845
880
|
setPanModeListener { isInPanMode ->
|
|
846
881
|
mapConfig.onDidChangePanningInterface?.let {
|
|
847
882
|
it(isInPanMode)
|
|
@@ -851,7 +886,7 @@ object Parser {
|
|
|
851
886
|
)
|
|
852
887
|
}
|
|
853
888
|
mapConfig.headerActions?.let { headerActions ->
|
|
854
|
-
setActionStrip(
|
|
889
|
+
setActionStrip(parseMapHeaderActions(context, headerActions))
|
|
855
890
|
}
|
|
856
891
|
}.build()
|
|
857
892
|
}
|
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
|
+
}
|
package/jest.js
ADDED